Docker

Docker Container Networking Tutorial

1. Introduction

In this post, we will learn the basics of Docker container networking in a single host setup. We will see the basic inrastructure provided by the Docker Engine for container networking, the “Docker network” family of commands, and the basics of creating user-defined networks. We wil not cover networking with containers in multiple hosts setup here.

2. Docker networking basics

Docker provides the basic infrastructure, for networking containers within a single host, out of the box. At installation, Docker creates a virtual Ehternet bridge, called docker0, on the host. An ethernet bridge connects two different networks and forwards packets from one connected network to the other. docker0 does the same task for all network interfaces connected to it. Docker also provides 3 default Docker networks and the infrastructure to create user-defined Docker networks. Lets explore this more.

2.1 Default networks provided by Docker

Docker creates 3 networks by default – bridge, host and none. The command docker network ls lists them out.

$docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
81419cac2baf        bridge              bridge              local               
18e8e68644ea        host                host                local               
1f87f168df62        none                null                local

The column NETWORK ID provides the unique ID given to the network. The column NAME provides the name of the network. The column DRIVERgives the Docker network driver plugin used. A Docker network driver plugin adapts the networking features of Docker to the host OS’s networking support. The SCOPE column gives the scope of visibility of the networks

2.2 The Bridge network

Docker provides the bridge network by default. A docker container created on the host is connected to this network by default. The bridge network maps to the docker0 bridge of the host. Lets quickly check this out by creating a container and checking it’s assigned network.

$ docker run --detach infinite-loop-alpine
ceb6846e5d7af370b6b382c258ddc76b03c8b6fc2d04ca4df5c2d17a27aae11f
$
$ docker ps --format="{{.ID}} {{.Names}}"
ceb6846e5d7a loving_roentgen
7f7ef05a21f1 hariharan-private-docker-registry
$
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "81419cac2bafee0c12cba4221b6a5697d9c4cf128259111cc19c6dd6ccfeb28d",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Containers": {
            "7f7ef05a21f1476beab8dea21056444ec428add3e0f98206ecc4930208f29572": {
                "Name": "hariharan-private-docker-registry",
                "EndpointID": "92266572755b163aaa3f32d8e7f81b95a31c9ae5abc161977a241e9c69721bfc",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "ceb6846e5d7af370b6b382c258ddc76b03c8b6fc2d04ca4df5c2d17a27aae11f": {
                "Name": "loving_roentgen",
                "EndpointID": "17c86e7adbfd5035532d0760d5c715a91ee2685c24e58f4777c07504c859583f",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
$
$ docker exec -it loving_roentgen ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
          inet addr:172.17.0.3  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:3%32751/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:268 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:46584 (45.4 KiB)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1%32751/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

The command docker network inspect <docker-network-name> inspects details of a Docker network. As you can see, a subnet and gateway is already created for bridge. The entry "com.docker.network.bridge.name": "docker0" shows that bridge is mapped to docker0. The new container named loving_roentgen was automatically added to the bridge network and is allocated the IP 172.17.0.3 from the subnet of IPs reserved for bridge.

Finally, when you run the command ifconfig within the container you see that there are 2 network interfaces configured – the loopback interface lo and the ethernet interface etho.

2.3 The none network

The none is used to attach a Docker container to a no-network network! This means that the Docker container will have its own network stack but it will not be configured. Containers attached to the none network will not have an IP address and will be stand-alone. Lets see an example.

$ docker run --detach --net=none infinite-loop-alpine
8ce6015f36de4a2b1d942a23a5799e50109a156c9d2170781f03b4802e4be034
$
$ docker ps --format="{{.ID}} {{.Names}}"
8ce6015f36de adoring_kowalevski
ceb6846e5d7a loving_roentgen
7f7ef05a21f1 hariharan-private-docker-registry
$
$ docker network inspect none
[
    {
        "Name": "none",
        "Id": "1f87f168df62320ee4d91b06e79f8bc32204995ae1cdaaaa6b272089299e72e4",
        "Scope": "local",
        "Driver": "null",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Containers": {
            "8ce6015f36de4a2b1d942a23a5799e50109a156c9d2170781f03b4802e4be034": {
                "Name": "adoring_kowalevski",
                "EndpointID": "e5955b9d6cb0980dd1f88d2fb8f94d0b75a6f5274f526dfe82768cad5175a746",
                "MacAddress": "",
                "IPv4Address": "",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
$
$ docker exec -it adoring_kowalevski ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1%32525/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

As you can see from the above, the command to attach a container to the none network is through the --net=none option. The command docker run --detach --net=none infinite-loop-alpine created a container called adoring_kowalevski and assigned it the none network. This can be verified by inspecting the network through the command docker network inspect none. It is seen that adoring_kowalevski does not have IP address or MAC address allotted to it. Finally, when you run the command ifconfig within the container you see that only the loopback interface is configured.

The none network is useful to create containers that need to do standalone batch jobs without any dependency on other networks.

2.4 The host network

When a container is connected to the host network, it gets the same network configuration as in the host OS.

$ docker run --detach --net=host infinite-loop-alpine
9b53dbb876d3d53a4d90ad14374cd73398342481e3cc976f42e9302e2806c846
$
$ docker ps --format="{{.ID}} {{.Names}}"
9b53dbb876d3 stupefied_meninsky
ceb6846e5d7a loving_roentgen
7f7ef05a21f1 hariharan-private-docker-registry
$
$ docker network inspect host
[
    {
        "Name": "host",
        "Id": "18e8e68644ea8984908af0084c72a788726c7cc685a1937e4d8213546834fa1e",
        "Scope": "local",
        "Driver": "host",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Containers": {
            "9b53dbb876d3d53a4d90ad14374cd73398342481e3cc976f42e9302e2806c846": {
                "Name": "stupefied_meninsky",
                "EndpointID": "584f923dc3f9c41d16754d99fc66b9b7403c31cbb707d3e3cd2655baacfd7e7f",
                "MacAddress": "",
                "IPv4Address": "",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
$
$ docker exec -it stupefied_meninsky ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:FE:8F:34:D6  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:feff:fe8f:34d6%32754/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:32 errors:0 dropped:0 overruns:0 frame:0
          TX packets:350 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:2144 (2.0 KiB)  TX bytes:62088 (60.6 KiB)

enp0s25   Link encap:Ethernet  HWaddr F0:DE:F1:34:04:7D  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
          Interrupt:20 Memory:f2600000-f2620000 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1%32754/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:248 errors:0 dropped:0 overruns:0 frame:0
          TX packets:248 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:19932 (19.4 KiB)  TX bytes:19932 (19.4 KiB)

veth1195497 Link encap:Ethernet  HWaddr 92:94:1E:B1:88:A3  
          inet6 addr: fe80::9094:1eff:feb1:88a3%32754/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:268 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:648 (648.0 B)  TX bytes:46584 (45.4 KiB)

veth8dbd591 Link encap:Ethernet  HWaddr F6:59:DB:33:90:D4  
          inet6 addr: fe80::f459:dbff:fe33:90d4%32754/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:428 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:648 (648.0 B)  TX bytes:68993 (67.3 KiB)

virbr0    Link encap:Ethernet  HWaddr 52:54:00:0D:56:AB  
          inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

wlp3s0    Link encap:Ethernet  HWaddr 00:24:D7:8A:BF:7C  
          inet addr:192.168.1.107  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::224:d7ff:fe8a:bf7c%32754/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3018393 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1256101 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:4091579215 (3.8 GiB)  TX bytes:148684970 (141.7 MiB)

As you can see from the above, the command docker run --detach --net=host infinite-loop-alpine created a container called stupefied_meninsky and assigned it the host network. This can be verified by inspecting the network through the command docker network inspect host. Finally, when you run the command ifconfig within the container you see that it has all the network interfaces configured in the host OS (well, from my laptop’s OS actually. The interfaces configured in your host OS may vary).

2.5 Docker engine commands to manage Docker networks

We already saw the command docker network ls and docker network inspect. Here is a summary of commands to manage Docker networks. Use option docker network <command> --help to see the list of all options for the command.

CommandSummary
docker network connect <network-name> <container-name>Connects the given container to the specified network.
docker network disconnect <network-name> <container-name>Disconnects the given container to the specified network.
docker network create [--driver <driver-name>] <network-name>Creates a new Docker network with the given name. If the option –driver is not given then the network will be created as a bridge network. Else, the specified driver will be used.
docker network inspect <network-name>Provides details for the given Docker network. To inspect details of multiple networks mention all other network names separated by a space.
docker network lsList all Docker networks.
docker network rm <network-name>Remove the given Docker network. To inspect details of multiple networks mention all other network names separated by a space.

3. User defined networks

As shown in the table above, the command docker network create [--driver <driver-name>] <network-name> is used to create a new user-defined network. The option --driver <driver-name> is optional. If not provided, a bridge network is created. This option can take one of the values bridge, overlay, or macvlan as provided by Docker or a user-defined driver value.

3.1 Create a user defined Docker network

Lets use the command above to create a custom bridge network.

$ docker network create --driver bridge example-network-1
4480467dd40757e2507426367b599de520b330287fb579f37082f4f726f6467f
$
$ docker network list
NETWORK ID          NAME                DRIVER              SCOPE
81419cac2baf        bridge              bridge              local               
4480467dd407        example-network-1   bridge              local               
18e8e68644ea        host                host                local               
1f87f168df62        none                null                local               
$
$ docker network inspect example-network-1 
[
    {
        "Name": "example-network-1",
        "Id": "4480467dd40757e2507426367b599de520b330287fb579f37082f4f726f6467f",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Internal": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
$
$ docker run --detach --name=infinite-loop-1 infinite-loop-alpine
44c4b02e18dc182d37efad85c04bd936f020dbe9e1e1036b435e30a97905e279
$
$ docker run --detach --name=infinite-loop-2 infinite-loop-alpine
c9268f5d5746e23790074fc0b06bcc0d33451da12c13aa77b12248830600d560
$
$ docker network connect example-network-1 infinite-loop-1 
$ docker network connect example-network-1 infinite-loop-2 
$
$ docker network inspect example-network-1 
[
    {
        "Name": "example-network-1",
        "Id": "4480467dd40757e2507426367b599de520b330287fb579f37082f4f726f6467f",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Internal": false,
        "Containers": {
            "44c4b02e18dc182d37efad85c04bd936f020dbe9e1e1036b435e30a97905e279": {
                "Name": "infinite-loop-1",
                "EndpointID": "8604f0d048680019c122f07ad35dbc00b474f689d8ff75719f307f57d29b5a03",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "c9268f5d5746e23790074fc0b06bcc0d33451da12c13aa77b12248830600d560": {
                "Name": "infinite-loop-2",
                "EndpointID": "d769935f984f9dfbc82ae3de107ad841117967aac20f0e826b429859c3d31ffd",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
$
$ docker exec -it infinite-loop-1 ping -c 4 infinite-loop-2
PING infinite-loop-2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.185 ms
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.172 ms
64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.192 ms
64 bytes from 172.18.0.3: seq=3 ttl=64 time=0.174 ms

--- infinite-loop-2 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.172/0.180/0.192 ms

We created a new bridge network called example-network-1 and connected 2 containers called infinite-loop-1 and infinite-loop-2 to it. Next, we verified that the network had the containers connected successfully. Lastly, we pinged the container infinite-loop-2 from within infinite-loop-1 using the container name.

Do note that containers can be accessed by name only within user-defined networks. In Docker’s bridge netowrk, for example, containers can be accessed over the network only by their IP addresses.

5. Summary

In this post We were introduced to the basics of Docker container networking. The Docker Engine enables 3 types of networks out of the box – bridge, overlay, and none. The bridge network is the default network for most practical purposes. User defined networks can be of 3 types – bridge, overly, and MACVLAN. The “Docker network” family of commands provides the necessary commands to create and manage Docker networks. Finally, we saw how to communicate among containers in a single-host setup.

Hariharan Narayanan

Hari graduated from the School of Computer and Information Sciences in the University of Hyderabad. Over his career he has been involved in many complex projects in mobile applications, enterprise applications, distributed applications, micro-services, and other platforms and frameworks. He works as a consultant and is mainly involved with projects based on Java, C++ and Big Data technologies.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button