Understand networking in Podman

I received a message on Twitter on 17 October from a fellow who attended the openSUSE Asia Summit 2019. Strangely, I didn't get any notification about it and it's only today that I read the message. He also attended my workshop on openSUSE MicroOS and had some questions regarding inter-Pod communication.

As a quick response, I explained him very breifly about "container networking" and pointed him to the Kubernetes documentation on IP allocation. I do realize though, that most of the times, documenation can be lengthy and {boring}, and that you would just want a simple article or blog post that clears your doubts.

Tell me about Podman networks

Rootless containers (i.e containers started using Podman as a regular user) do not obtain an IP address. Podman uses slirp4netns to allow Internet connectivity inside the container.

Communication with a rootless container is achieved by mapping the container ports to the host, e.g using -p 8080:80 to map a webserver port 80 to the host on port port 8080.

$ podman run -dt --name webserver -p 8080:80 nginx
$ curl http://localhost:8080

Therefore, two rootless containers can communicate over their published ports on the host. Let's experiment this by starting an openSUSE Leap container and installing the telnet package.

$ podman run -dt --name leap leap
$ podman exec -it leap bash

4a0f95e011b9:/ # zypper in telnet

We run ip a s on the host to find its IP address. Say the IP address is 192.168.100.8. Now, from within Leap container let's telnet port 8080 over the host IP.

4a0f95e011b9:/ # telnet 192.168.100.10 8080
Trying 192.168.100.10...
Connected to 192.168.100.10.
Escape character is '^]'.

The connection went through successfully, meaning from the Leap container we've been able to access the Nginx container through it's mapped port on the host.

This same experiment can be repeated using two different pods, say you have a pod that contains your web services and another pod that contains your databases.

$ podman pod create --name webservice -p 8080:80
$ podman run -dt --name webserver --pod webservice nginx

$ podman pod create --name db -p 3306:3306
$ podman run -dt --name mariadb --pod db -e "MYSQL_ALLOW_EMPTY_PASSWORD=yes" mariadb

The Nginx container will be able to reach the MariaDB database over 192.168.100.10:3306 as the same port is mapped on the host.

Ideally, these two containers could have been created in the same pod and therefore share the same network space. Then, the Nginx container would reach the database over localhost:3306 easily.

I used the above Nginx/MariaDB example to explain rootless inter-Pod communication, which was the question that was asked to me initially.

What about rootfull containers?

Rootfull containers are those that are created using Podman with root privileges, either by the root user itself or using sudo privilege.

Containers created using Podman with root privileges obtain an IP address. Podman then uses the Container Network Interfec (CNI) instead of slirp4netns for networking provisioning.

Details about the network subnet is found in the CNI config file.

$ cat /etc/cni/net.d/87-podman-bridge.conflist

{
    "cniVersion": "0.3.0",
    "name": "podman",
    "plugins": [
      {
        "type": "bridge",
        "bridge": "cni0",
        "isGateway": true,
        "ipMasq": true,
        "ipam": {
            "type": "host-local",
            "subnet": "10.88.0.0/16",
            "routes": [
                { "dst": "0.0.0.0/0" }
            ]
        }
      },
      {
        "type": "portmap",
        "capabilities": {
          "portMappings": true
        }
      }
    ]
}

So, let's start a container with root privileges and see.

$ sudo podman run -dt --name db postgres

$ sudo podman inspect -f "{{.NetworkSettings.IPAddress}}" db
10.88.0.30

The podman inspect ... command returns the container's IP address and the same is ranged within the subnet specified in the CNI config. The PostgreSQL database can be accessed over 10.88.0.30:5432 from the host or from within any other container started using root privileges.

$ telnet 10.88.0.30 5432
Trying 10.88.0.30...
Connected to 10.88.0.30.
Escape character is '^]'.