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.
Command | Summary |
---|---|
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 ls | List 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.