Podman - Networking 3/3
In the previous articles, we had a look at the basics of Podman networking. In this article, I want to focus on some special behavior and concepts. Let's check out networking in pods and rootless mode.
In the previous articles, we had a look at the basics of Podman networking. In this article, I want to focus on some special behavior and concepts. Let's check out networking in pods and rootless mode.
Port publishing
In case of usability, you have to be aware, that Podman differentiates between rootfull and rootless modes. Without any additional configuration, you cannot publish privileged ports.
Rootfull
Rootfull port publishing was already covered in the previous articles "Podman - Networking 1/3" and "Podman - Networking 2/3". Nevertheless, let's check an already known example: "Start a simple web container and publish the Web Port."
# Start httpd container and publish port 80
$ sudo podman container run -d -p 80:80 docker.io/library/httpd
# List running containers
$ sudo podman container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f11b7196bb57 docker.io/library/httpd httpd-foreground 5 seconds ago Up 5 seconds ago 0.0.0.0:80->80/tcp tender_jennings
# Check the published port
$ curl localhost:80
<html><body><h1>It works!</h1></body></html>
As expected, everything works.
Rootless
In rootless, you are limited to unprivileged ports. Per definition, these are ports above 1023. Publishing the port 80 will raise an error and the container cannot be started. Therefore, I will use Port 8080/tcp.
# Start httpd container and publish port 80
$ podman container run -d -p 8080:80 docker.io/library/httpd
# List running containers
$ podman container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b16476c14c76 docker.io/library/httpd:latest httpd-foreground 39 seconds ago Up 40 seconds ago 0.0.0.0:8080->80/tcp recursing_liskov
# Check the published port
$ curl localhost:8080
<html><body><h1>It works!</h1></body></html>
Now let's see what happens, if we want to use Port 80/tcp. Please ensure, that the containers from the previous examples are removed, since Port 80/tcp is already in use from the rootfull container.
# Start rootless httpd container and publish port 80
$ podman container run -d -p 80:80 docker.io/library/httpd
Error: rootlessport cannot expose privileged port 80, you can add 'net.ipv4.ip_unprivileged_port_start=80' to /etc/sysctl.conf (currently 1024), or choose a larger port number (>= 1024): listen tcp 0.0.0.0:80: bind: permission denied
Configuration
This behavior may be inconvenient, but quite easy to configure. In fact, the above error already explains what needs to be done.
# Configure sysctl (temporary)
$ sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
# Try again rootless with published port 80/tcp
$ podman container run -d -p 80:80 docker.io/library/httpd
# List running containers
$ podman container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f58628972336 docker.io/library/httpd httpd-foreground 43 seconds ago Up 43 seconds ago 0.0.0.0:80->80/tcp zealous_easley
# Check the published port
$ curl localhost:80
<html><body><h1>It works!</h1></body></html>
To make the above change persistent, you just need to edit /etc/sysctl.conf
and add the below line.
Afterwards, you can reboot, and the configuration will persist.
Macvlan
Sometimes, it can be very useful to publish containers differently. If you want to make it look like the host is directly publishing some ports and there is no virtual network between the container and the host, you can use Macvlan.
First, you will need to create a Macvlan network. You also need to ensure that the CNI DHCP plugin is loaded and running. Please also remove all containers from previous examples, beforehand.
# Create a macvlan network
$ sudo podman network create -d macvlan macvlan-net
/etc/cni/net.d/macvlan-net.conflist
# List networks
$ sudo podman network ls
NETWORK ID NAME VERSION PLUGINS
2f259bab93aa podman 0.4.0 bridge,portmap,firewall,tuning
ec9a4ae9ac28 macvlan-net 0.4.0 macvlan
# Ensure CNI DHCP is running
$ sudo /usr/libexec/cni/dhcp daemon
# Create a container
$ sudo podman container run -d docker.io/library/httpd
# Check the published port
$ curl localhost:80
<html><body><h1>It works!</h1></body></html>
Pod networking
Lastly, I want to demonstrate how containers are communicating inside pods. This can be especially useful for sidecar containers, but also for small setups. If you don't know anything about Pods, I recommend having a look here.
Having 2 containers in one pod, has the huge benefit, that containers can reach each other's exposed ports, but there is also some special behavior.
Communication in pods
Having 2 or more containers in a Pod has some nice benefits. For example, if you have one container in the pod, that exposes port (not publish), it can be reached via "localhost:PORT" from every other container in the same pod.
# Create a pod
$ podman pod create web-pod
# Run a web container in the pod
$ podman container run -d --pod web-pod docker.io/library/httpd
# List containers and attached pods
podman container ls -p
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES POD ID PODNAME
37ae8644d49f k8s.gcr.io/pause:3.5 About a minute ago Up 13 seconds ago 9a0913613d1d-infra 9a0913613d1d web-pod
1e29eb4410cd docker.io/library/httpd httpd-foreground 12 seconds ago Up 13 seconds ago stoic_jepsen 9a0913613d1d web-pod
# Run another container interactivly and connect to the other container
$ podman container run -it --rm --pod web-pod docker.io/library/fedora curl localhost
<html><body><h1>It works!</h1></body></html>
Publish ports
If you want to publish ports for the containers in a pod, you have to do this on pod creation and for the pod itself. Otherwise, the port may not be published and reachable from the outside.
# Create pod and publish port 80/tcp
$ sudo podman pod create -p 80:80 -n publish-pod
# List pods
$ sudo podman pod ls
POD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
26fe5de43ab3 publish-pod Created 5 seconds ago 7de09076d2b3 1
# Run a container in the pod
$ sudo podman container run -d --pod publish-pod docker.io/library/httpd
# List containers
$ sudo podman container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7de09076d2b3 k8s.gcr.io/pause:3.5 About a minute ago Up 23 seconds ago 0.0.0.0:80->80/tcp 26fe5de43ab3-infra
088befb90e59 docker.io/library/httpd httpd-foreground 23 seconds ago Up 23 seconds ago 0.0.0.0:80->80/tcp exciting_khayyam
# Test connection
$ curl localhost:80
<html><body><h1>It works!</h1></body></html>
Attach networks
Attaching a network to containers in a pod, must be done on pod creation, too. Assigning networks to the containers itself if they are located in a pod may lead to connection issues and should be avoided.
# Create a network
$ sudo podman network create pod-net
# Create a pod
$ sudo podman pod create --net pod-net -n net-pod
# List containers and pods
$ sudo podman container ls -p
8d98564bb6bf k8s.gcr.io/pause:3.5 32 seconds ago Up 5 seconds ago 7bc1a386dd9f-infra 7bc1a386dd9f net-pod
a7d7304591e2 docker.io/library/httpd httpd-foreground 5 seconds ago Up 5 seconds ago optimistic_beaver 7bc1a386dd9f net-pod
Links
The guide above provides a nice overview of additional Podman networking behavior. You can find additional helpful guides and tutorials in the official documentation and in some blogs, I recommend reading.
Conclusion
Podman provides very powerful networking tools. You can create separate networks for internal or external use. You can publish ports and communicate in pods in different ways. Even rootless works in most scenarios and allows configuring very sophisticated setups, that work without root access.
This is the last article, focusing on Podman networking. In the future, I will show some setups, where you can see how the networking functionality can be used for real deployments.