/ Docker

Networking with Docker

This hands-on guide will help you understand how networking works with Docker.

When you install Docker, it creates three networks automatically. You can list *these networks using the docker network ls command:

root@ubuntu:~# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f0a2eabc9004        bridge              bridge              local
84b903e031be        host                host                local
c82ab14d5177        none                null                local
root@ubuntu:~#

These three networks are built into Docker. When you run a container, you can use the --network flag to specify which networks your container should connect to.

  • The bridge network represents the docker0 network present in all Docker installations. Unless you specify otherwise with the docker container run --network=<NETWORK> option, the Docker daemon connects containers to this network by default. You can see this bridge as part of a host’s network stack by using the ifconfig command on the host.
root@ubuntu:~# ifconfig 
docker0   Link encap:Ethernet  HWaddr 02:42:9f:33:c6:42  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:9fff:fe33:c642/64 Scope:Link
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:23605 errors:0 dropped:0 overruns:0 frame:0
          TX packets:54913 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:6884705 (6.8 MB)  TX bytes:25698564 (25.6 MB)

  • The none network adds a container to a container-specific network stack. That container lacks a network interface.

  • The host network adds a container on the host’s network stack. As far as the network is concerned, there is no isolation between the host machine and the container. For instance, if you run a container that runs a web server on port 80 using host networking, the web server is available on port 80 of the host machine.

The none and host networks are not directly configurable in Docker. However, you can configure the default bridge network, as well as your own user-defined bridge networks.

List the current docker networks

root@ubuntu:~# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f0a2eabc9004        bridge              bridge              local
84b903e031be        host                host                local
c82ab14d5177        none                null                local

Create a alpine container named container1 and inspect the /etc/resolv.conf and /etc/hosts file. Also note the IP Address of the container.

root@ubuntu:~# docker run -itd --name=container1 alpine sh
37985ded1e9c462561d81a953552cb58a3a832f819746e18e01c65554b56fc07

root@ubuntu:~# docker exec container1 cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 10.0.2.3

root@ubuntu:~# docker exec container1 cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.2    37985ded1e9c

root@ubuntu:~# docker inspect container1 |grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",
                    

Create another isolated bridge network named bridge2

root@ubuntu:~# docker network create --driver bridge --subnet 192.168.111.1/24 bridge2
5340acb01851b00a2143383056d67e625ee77b67dca02242a50bea168090587d

root@ubuntu:~# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
f0a2eabc9004        bridge              bridge              local
5340acb01851        bridge2             bridge              local
84b903e031be        host                host                local
c82ab14d5177        none                null                local

root@ubuntu:~# ifconfig 
br-5340acb01851 Link encap:Ethernet  HWaddr 02:42:fb:50:db:04  
          inet addr:192.168.111.1  Bcast:0.0.0.0  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)

docker0   Link encap:Ethernet  HWaddr 02:42:9f:33:c6:42  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:9fff:fe33:c642/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:23608 errors:0 dropped:0 overruns:0 frame:0
          TX packets:54919 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:6884901 (6.8 MB)  TX bytes:25698928 (25.6 MB)
          

Create another alpine container named container2 attached to bridge2 network and inspect the /etc/resolv.conf and /etc/hosts file. Also note the IP Address of the container.

root@ubuntu:~# docker run -itd --name=container2 --net=bridge2 alpine sh
f084cd26d2c0967a2d839c7467312063752e8715b27b91416b8c21e5ecf02340

root@ubuntu:~# docker exec container2 cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
192.168.111.2    f084cd26d2c0

root@ubuntu:~# docker exec container2 cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0

root@ubuntu:~# docker inspect container2 |grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "",
                    "IPAddress": "192.168.111.2",
root@ubuntu:~#

Try accessing container1 from container2

root@ubuntu:~# docker exec -it container2 sh
/ # ping 172.17.0.2

PING 172.17.0.2 (172.17.0.2): 56 data bytes
^C
--- 172.17.0.2 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss

Create third alpine container connected to both bridge networks. Also inspect the /etc/resolv.conf and /etc/hosts file. Also note the IP Address of the container.

root@ubuntu:~# docker run -itd --name=container3 alpine sh
1726892f1b42d308321cc07c0e90c12183b00f99225dc539a5bed0ad801ca649

root@ubuntu:~# docker network connect bridge2 container3

root@ubuntu:~# docker exec -it container3 sh

/ # cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.3    1726892f1b42
192.168.111.3    1726892f1b42

/ # cat /etc/resolv.conf 
nameserver 127.0.0.11
options ndots:0

/ # 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
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 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:648 (648.0 B)  TX bytes:0 (0.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:C0:A8:6F:03  
          inet addr:192.168.111.3  Bcast:0.0.0.0  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 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:648 (648.0 B)  TX bytes:0 (0.0 B)
          

Try accessing container1 and container2 from container3 using IP Address and name. Also check connectivity to external network.

/ # ping -c3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.138 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.120 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.116 ms

--- 172.17.0.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.116/0.124/0.138 ms

/ # ping -c3 192.168.111.2
PING 192.168.111.2 (192.168.111.2): 56 data bytes
64 bytes from 192.168.111.2: seq=0 ttl=64 time=0.126 ms
64 bytes from 192.168.111.2: seq=1 ttl=64 time=0.130 ms
64 bytes from 192.168.111.2: seq=2 ttl=64 time=0.134 ms

--- 192.168.111.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.126/0.130/0.134 ms

/ # ping -c3 container1
ping: bad address 'container1'

/ # ping -c3 container2
PING container2 (192.168.111.2): 56 data bytes
64 bytes from 192.168.111.2: seq=0 ttl=64 time=0.151 ms
64 bytes from 192.168.111.2: seq=1 ttl=64 time=0.118 ms
64 bytes from 192.168.111.2: seq=2 ttl=64 time=0.130 ms

--- container2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.118/0.133/0.151 ms

/ # ping -c3 google.com
PING google.com (216.58.199.174): 56 data bytes
64 bytes from 216.58.199.174: seq=0 ttl=61 time=22.968 ms
64 bytes from 216.58.199.174: seq=1 ttl=61 time=61.807 ms
64 bytes from 216.58.199.174: seq=2 ttl=61 time=35.257 ms

--- google.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 22.968/40.010/61.807 ms

Note that container1 belongs to the default bridge network and so is not accessible using name where as container2 belongs to the user-defined-network running a embedded DNS server which resolves the container names on the same network.

Create another network named bridge3 and restrict external access to the network by using --internal option

root@ubuntu:~# docker network create --internal bridge3
84322cf4cfb6f70d553e23b2753b48d24c28d7eaba2016a6134da1b4691792aa

root@ubuntu:~# docker run -itd --name=container4 --net=bridge3 alpine sh
caa817054e0cb86dddf312d33b1e2357f7af728f7b60527b9a4b4bfaf4e1b511

root@ubuntu:~# docker exec -it container4 sh
/ # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
^C
--- 8.8.8.8 ping statistics ---
5 packets transmitted, 0 packets received, 100% packet loss
/ # exit

Also check the iptables rules. Masquerading is disabled on the internal network

root@ubuntu:~# iptables -t nat -L -n |grep MASQUERADE
MASQUERADE  all  --  192.168.111.0/24     0.0.0.0/0           
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0           
root@ubuntu:~#

Enjoy :)