Podman - Networking 2/3

In the previous article I explained how container networking works in general and how it is reflected in Podman. Now, let's see how we can use this in some examples and how the different networking layers work hand in hand.

Podman - Networking 2/3

In the previous article I explained how container networking works in general and how it is reflected in Podman. Now, let's see how we can use this in some examples and how the different networking layers work hand in hand.

For this guide, I will focus on the podman network command and how it can be used for internal or external networks.

💡
The guide is tested on Fedora 34 with Podman 3.1.2The guide is tested on Fedora 34 with Podman 3.1.2

Creating and Reviewing Networks

Podman provides a sub-command to manage container networks. These networks can be used for containers. For now, I will stick to rootfull networking, but will address rootless in a future article in more details.

Let's see what is built-in right after a fresh Podman installation.

# List networks
$ sudo podman network ls
NAME    VERSION  PLUGINS
podman  0.4.0    bridge,portmap,firewall,tuning

# Inspect the default network (named podman)
$ sudo podman network inspect podman
[
    {
        "cniVersion": "0.4.0",
        "name": "podman",
        "plugins": [
            {
                "bridge": "cni-podman0",
                "hairpinMode": true,
                "ipMasq": true,
                "ipam": {
                    "ranges": [
                        [
                            {
                                "gateway": "10.88.0.1",
                                "subnet": "10.88.0.0/16"
                            }
                        ]
                    ],
                    "routes": [
                        {
                            "dst": "0.0.0.0/0"
                        }
                    ],
                    "type": "host-local"
                },
                "isGateway": true,
                "type": "bridge"
            },
            {
                "capabilities": {
                    "portMappings": true
                },
                "type": "portmap"
            },
            {
                "type": "firewall"
            },
            {
                "type": "tuning"
            }
        ]
    }
]

As you can see, there is already a network existing. The details like the IP range, enabled plugins and the type of the network can be reviewed, too.

Let's create a new network.

# Create new network with the name test01
$ sudo podman network create test-net
/etc/cni/net.d/test-net.conflist

# List all networks
$ sudo podman network ls
NETWORK ID    NAME      VERSION  PLUGINS
2f259bab93aa  podman    0.4.0    bridge,portmap,firewall,tuning
254ddbe0ec1e  test-net  0.4.0    bridge,portmap,firewall,tuning,dnsname

A new network can be inspected, and you can review the details like IP ranges or gateway addresses.

# Inspect a network
$ sudo podman network inspect test-net
[
    {
        "cniVersion": "0.4.0",
        "name": "test-net",
        "plugins": [
            {
                "bridge": "cni-podman1",
                "hairpinMode": true,
                "ipMasq": true,
                "ipam": {
                    "ranges": [
                        [
                            {
                                "gateway": "10.89.0.1",
                                "subnet": "10.89.0.0/24"
                            }
                        ]
                    ],
                    "routes": [
                        {
                            "dst": "0.0.0.0/0"
                        }
                    ],
                    "type": "host-local"
                },
                "isGateway": true,
                "type": "bridge"
            },
            {
                "capabilities": {
                    "portMappings": true
                },
                "type": "portmap"
            },
            {
                "backend": "",
                "type": "firewall"
            },
            {
                "type": "tuning"
            },
            {
                "capabilities": {
                    "aliases": true
                },
                "domainName": "dns.podman",
                "type": "dnsname"
            }
        ]
    }
]

You might see the additional dnsname plugin, which is only present for external networks. I will explain this in the next section.

You can also remove networks, if you don't need them any longer.

# Remove test01 network
$ sudo podman network rm test-net

In the next sections, I will create some networks with different settings and explain why and how they are useful.

External/Internal networks

Podman does differentiate between external and internal networks. If you don't specify anything, Podman will create an external network.

External networks

External networks are needed

So, let's see how external networks can be used.

# Create external network
$ sudo podman network create external-net

# List networks
$ sudo podman network ls
NETWORK ID    NAME          VERSION  PLUGINS
2f259bab93aa  podman        0.4.0    bridge,portmap,firewall,tuning
e6876f616464  external-net  0.4.0    bridge,portmap,firewall,tuning,dnsname

As you can see, there is also a plugin named "dnsname" enabled, which allows addressing containers in this network by their container name. This behavior can be overridden with the option --disable-dns.

Let's see this feature in an example, where I am creating a container rcv01 and ping it from another container.

# Create a container receiver attached to the new network
$ sudo podman container run -d --net external-net --name rcv01 fedora:34 sleep 3000

# Run a container and try to reach rcv01 via dns
$ sudo podman container run -it --rm --net external-net --name snd01 alpine ping -c3 rcv01
PING rcv01 (10.89.0.2): 56 data bytes
64 bytes from 10.89.0.2: seq=0 ttl=42 time=0.020 ms
64 bytes from 10.89.0.2: seq=1 ttl=42 time=0.081 ms
64 bytes from 10.89.0.2: seq=2 ttl=42 time=0.041 ms

--- rcv01 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.020/0.047/0.081 ms

As you can see, the container snd01 is able to ping the other container (rcv01) properly via container name.

Internal networks

On the other hand, you can also have internal networks. Containers in an internal network are not able to be contacted from outside this network and are also not able to connect to the outside.

# Create internal network
$ sudo podman network create internal-net --internal
WARN[0000] dnsname and --internal networks are incompatible.  dnsname plugin not configured for network internal-net 
/etc/cni/net.d/internal-net.conflist

# List networks
$ sudo podman network ls
NETWORK ID    NAME          VERSION  PLUGINS
2f259bab93aa  podman        0.4.0    bridge,portmap,firewall,tuning
7a1c7dff6e97  internal-net  0.4.0    bridge,portmap,firewall,tuning
e6876f616464  external-net  0.4.0    bridge,portmap,firewall,tuning,dnsname

As you can see, internal networks also disable the dnsname plugin per design. So, no DNS in internal networks.

The first thing, you may want to test is publishing a port and check if it is reachable.

# Create a container in external net
$ sudo podman container run -d -p 8080:80 --net external-net --name ext-app httpd

# Create a container in internal net
$ sudo podman container run -d -p 8081:80 --net internal-net --name int-app httpd

# Try to curl both
$ curl localhost:8080
<html><body><h1>It works!</h1></body></html>

$ curl localhost:8081
curl: (28) Failed to connect to localhost port 8081: Connection timed out

Network settings

You can configure your networks in many ways, to really tailor them to your needs and linking. For example, it may be a good idea to provide your own IP address ranges or netmasks to limit the amount of containers in a range.

Let's configure a network where only 1 container is allowed.

# Create the network
$ sudo podman network create --subnet 10.99.0.0/30 small-net
/etc/cni/net.d/small-net.conflist

The subnet option describes, that a network will be created as described below:

  • network address: 10.99.0.0
  • broadcast address: 10.99.0.3
  • available addresses: 10.99.0.1 - 10.99.0.2
  • gateway: 10.99.0.1

This leaves only one option for the container: 10.99.0.2.

# Create the container
$ sudo podman container run -d --net small-net httpd
4a3ba8d67b31726d38c012614b351c4d9decc2a811542ca05da387e444e3621f

# Try to create another container
$ sudo podman container run -d --net small-net httpd
ERRO[0000] Error adding network: failed to allocate for range 0: no IP addresses available in range set: 10.99.0.1-10.99.0.2 
ERRO[0000] Error while adding pod to CNI network "small-net": failed to allocate for range 0: no IP addresses available in range set: 10.99.0.1-10.99.0.2 
Error: error configuring network namespace for container 2578ba063160273b3c265f8309007723e1f32f6efa24baeed87e5eef8f12c15c: failed to allocate for range 0: no IP addresses available in range set: 10.99.0.1-10.99.0.2

As you can see, no more containers can be running in this network.

You can do way more stuff, like defining the DHCP range or move the gateway to a different IP address. Please have a look here for more information.

Manual IP address

Sometimes, it can be useful to define the IP address on a container basis and don't assign addresses via DHCP. This can be done with Podman, too.

Let's create a container, that is running in a new network, but has a manual IP address.

# Create a network
$ sudo podman network create manual-net

# Check the subnet range of the new network
$ sudo podman network inspect manual-net | grep subnet
"subnet": "10.89.2.0/24"

# Create a container with a manual address
$ sudo podman container run -d --ip=10.89.2.2 --net manual-net httpd

# Inspect the container IP
sudo podman container inspect -l | grep IPAddress
            "IPAddress": "",
                    "IPAddress": "10.89.2.2",

As desired, the container is running with a manual IP address. This allows you to set up systems, that require a valid IP address or even to build your own DNS resolver.

Documentation

In addition to the article, I strongly recommend reading the docs about the podman network command and taking a look at the Getting Started Guide. Furthermore, you can find some helpful articles in blogs and at GitHub.

Configuring container networking with Podman
Confused about how to network rootless and rootfull pods with Podman? Read on.
containers/podman
Podman: A tool for managing OCI containers and pods - containers/podman

Conclusion

With the provided network capabilities, you can create internal and external networks and configure them to your taste. If this is not enough, you can also configure the network completely manually. On top, you are having the option to use container names for DNS resolution, so you don't need to remember IP addresses at all.