Docker networks

Kamil Kurzyna

Docker has kept its popularity for quite a few years now (without surprise). Its success is based on many things like scalling, microservices and also its network solutions (and many more). In this article I’ll focus solely on docker networks and how they work.

Types of networks – bridge

Bridge is a default network which connects all containers and which has no defined network (–network option in CLI or networks in docker-compose).

Let’s take a look at this simple docker-compose:

version: '3.9'
  services:
    mongo:
      image: mongo
      networks:
       basicBridge:
        aliases:
         - mongoBridge
      ports:
       - "27017:27017"


  networks:
    basicBridge:
      driver: bridge

With this file I will create a container with mongoDB inside, that will expose port 27017 and will use bridge network (or, to be more specific – a virtual network) created with this file. If we inspect our docker networks, we will see:

Ok, the network is created, but how did this affect our iptables?

user@user-VirtualBox:~/docker$ sudo iptables -S 
-P INPUT ACCEPT
-P FORWARD DROP
-P OUTPUT ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
-N DOCKER-USER
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o br-f2d613c3f4ae -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-f2d613c3f4ae -j DOCKER
-A FORWARD -i br-f2d613c3f4ae ! -o br-f2d613c3f4ae -j ACCEPT
-A FORWARD -i br-f2d613c3f4ae -o br-f2d613c3f4ae -j ACCEPT
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.20.0.2/32 ! -i br-f2d613c3f4ae -o br-f2d613c3f4ae -p tcp -m tcp --dport 27017 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-f2d613c3f4ae ! -o br-f2d613c3f4ae -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o br-f2d613c3f4ae -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN

And if we grep these full iptable rules (I will return to this full iptables rules later)

-A FORWARD -o br-f2d613c3f4ae -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-f2d613c3f4ae -j DOCKER
-A FORWARD -i br-f2d613c3f4ae ! -o br-f2d613c3f4ae -j ACCEPT
-A FORWARD -i br-f2d613c3f4ae -o br-f2d613c3f4ae -j ACCEPT
-A DOCKER -d 172.20.0.2/32 ! -i br-f2d613c3f4ae -o br-f2d613c3f4ae -p tcp -m tcp --dport 27017 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-f2d613c3f4ae ! -o br-f2d613c3f4ae -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o br-f2d613c3f4ae -j DROP

We can see there our port 27017

-A DOCKER -d 172.20.0.2/32 ! -i br-f2d613c3f4ae -o br-f2d613c3f4ae -p tcp -m tcp --dport 27017 -j ACCEPT

exposed as well as easy movement of bytes between every possible container within this network. It we further inspect this network

user@user-VirtualBox:~/docker$ docker network inspect docker_basicBridge
[
    {
        "Name": "docker_basicBridge",
        "Id": "f2d613c3f4aec2fc21bfe873afb99e5be8169a160f6e4d0287a90935db78066d",
        "Created": "2021-02-11T14:20:43.946508597+01:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.20.0.0/16",
                    "Gateway": "172.20.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": true,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "5fe027febae2925af2aa1420ed0a8ada62ca3fdb4fe626fe0efc63692be7129f": {
                "Name": "docker_mongo_1",
                "EndpointID": "06105ac37fe92c35b7ff8fba1159b1adb899c35808fb0566455aca8a42ce8134",
                "MacAddress": "02:42:ac:14:00:02",
                "IPv4Address": "172.20.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {
            "com.docker.compose.network": "basicBridge",
            "com.docker.compose.project": "docker",
            "com.docker.compose.version": "1.25.5"
        }
    }
]

We notice things

{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}

and

"Containers": {
"5fe027febae2925af2aa1420ed0a8ada62ca3fdb4fe626fe0efc63692be7129f": {
"Name": "docker_mongo_1",
"EndpointID": "06105ac37fe92c35b7ff8fba1159b1adb899c35808fb0566455aca8a42ce8134",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
}
}

We see ip and subnet that is generated by the bridge driver. The 172.20.0.1 is a default value, although it can be changed.

It is important to remember that bridge is a network that pretty much by default limits itself only to localhost.

Types of network – none

In a full iptables -S list you could only see rules for a standard docker0 (default bridge) and our custom bridge interfaces. None of the lists (as can you suspect) literally cuts the container off the network by not binding it with any docker network. That also means none of ports has been exposed and that ther is no connection from outside the world. For example, if we run simple container

user@user-VirtualBox:~/docker$ docker run -d --network none -p 21017:21017 mongo

and list it

user@user-VirtualBox:~/docker$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
640095c2388e        mongo               "docker-entrypoint.s…"   3 seconds ago       Up 2 seconds                            intelligent_montalcini

Types of network – host and macvlan

The host network basically uses your host network rules for containers. As you can also suspect, port exposition will no work since apps inside our containers already use our network, not the default virtual one.

Macvlan is just a host network which will let you define the subnet and the gateway for your containers as well as physical network interface (as I wrote in the bridge section, our default docker networks are virtual networks).

Summary

There is also an overlay network, but I will skip it in this article. The reason is that I would have to go through swarm which is big and complex enough for a separate paper. But is that all? As you may notice, I have used the word 'driver’ few times. That’s because docker network uses 3-rd company solutions and this means that there are many more possibilities. So if you ever need something different, maybe there is already a solution for your needs. Or maybe write your own one. Anyway, I hope I have answered for at least a few questions that you had in mind about docker networks.

Peace!

Poznaj mageek of j‑labs i daj się zadziwić, jak może wyglądać praca z j‑People!

Skontaktuj się z nami