Docker Networking : Basics

Docker Networking : Basics

Scott Lowe has done a great job introducing Docker on his blog so I won't repeat it here. In this article, I am trying to put together my understanding of Docker networking. I am creating Docker containers in an Ubuntu 14.04 based virtual machine. Let's begin.

Installing Docker

Although Scott's post has commands to install Docker, they are specific to Ubuntu 12.04 while I am running Ubuntu 14.04. So, here are the commands I used to install Docker.

# Ensure kernel version is higher than 3.8

uname -a

# Update and add dependencies

sudo apt-get update

sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring

# Add Docker repository key to apt-key

sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -"

# Add Docker repository to apt source list

sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"

# Update and install Docker

sudo apt-get update

sudo apt-get install lxc-docker

After installation, a quick sudo docker version command shows the version of docker installed for Client and Server.

amit@ubuntu:~$ sudo docker version

Client version: 1.5.0

Client API version: 1.17

Go version (client): go1.4.1

Git commit (client): a8a31ef

OS/Arch (client): linux/amd64

Server version: 1.5.0

Server API version: 1.17

Go version (server): go1.4.1

Git commit (server): a8a31ef

amit@ubuntu:~$

Note that in this article, both Client and Server are co-located but they can be made to communicate over network.

docker0 Bridge

Once Docker daemon starts (can be checked using service docker status), Docker creates a virtual interface called docker0 and assigns an IP address from the private address range that is currently unused on the Docker host. This subnet is usually /16 and is shared between all containers on the Docker host. docker0 is a bit more than a virtual interface - it is a virtual Ethernet bridge which is created in software inside the kernel of Docker host.

Note:

Docker requires a bridge to function but it does not have to be docker0. It can be a linux bridge or even an open vswitch.

Now, every time a container is created, Docker creates two interfaces - one interface is given to the container and called eth0, and the other interface (with a unique name starting with veth) is given to the host and is bound to docker0 bridge. Inside the host kernel, the two interfaces are linked so that packets can travel between them. The container's eth0 interfaces are assigned an IP address from the private subnet and given a random MAC address (or assigned using --mac-address parameter).

With no containers created yet, the status of docker0 is as follows. The docker0 interface is assigned the IP address from the subnet 172.17/16 subnet. Notice the interfaces column has no veth interfaces bound yet.

amit@ubuntu:~$ ifconfig docker0

docker0 Link encap:Ethernet HWaddr 56:84:7a:fe:97:99

inet addr:172.17.42.1 Bcast:0.0.0.0 Mask:255.255.0.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)

amit@ubuntu:~$ sudo brctl show

bridge name bridge id STP enabled interfaces

docker0 8000.56847afe9799 no

Container Networking

I created and started few containers on the local Docker host with the Docker daemon listening on Unix socket (default - unix://var/run/docker.sock). Here is the link to my Github page that has the Ansible playbook and the custom module I wrote to gather networking information. Here's the output after running the playbook.

name = C4

ip_address = 172.17.0.3

prefix_len = 16

gateway = 172.17.42.1

mac_address = 02:42:ac:11:00:03

bridge = docker0

name = C3

ip_address = 172.17.0.5

prefix_len = 16

gateway = 172.17.42.1

mac_address = 02:42:ac:11:00:05

bridge = docker0

name = C2

ip_address = 172.17.0.4

prefix_len = 16

gateway = 172.17.42.1

mac_address = 02:42:ac:11:00:04

bridge = docker0

Notice that all containers' eth0 interface IP address is within the bridge's range of network addresses and the gateway is docker0 bridge's IP address. Also note the veth interfaces bound to docker0 bridge.

amit@ubuntu:~$ sudo brctl show

bridge name bridge id STP enabled interfaces

docker0 8000.56847afe9799 no veth5e3f58c

vethd10bbd4

vethfc203cb

By default, all containers can communicate with each other and the outside world. Docker adds a default rule in iptables with an ACCEPT policy.

amit@ubuntu:~$ sudo iptables -L -n

Chain INPUT (policy ACCEPT)

target prot opt source destination

Chain FORWARD (policy ACCEPT)

target prot opt source destination

DOCKER all -- 0.0.0.0/0 0.0.0.0/0

ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED

ACCEPT all -- 0.0.0.0/0 0.0.0.0/0

ACCEPT all -- 0.0.0.0/0 0.0.0.0/0

Chain OUTPUT (policy ACCEPT)

target prot opt source destination

Chain DOCKER (1 references)

target prot opt source destination

To prevent any type of communication, it is recommended that iptables rules are applied appropriately.

Further, NAT is implemented in iptables on host when Docker starts. This way containers can talk to outside world but not in other direction. This can be changed using -p or -P flag to expose any ports on the container to the outside world.

amit@ubuntu:~$ sudo iptables -t nat -L -n

Chain PREROUTING (policy ACCEPT)

target prot opt source destination

DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)

target prot opt source destination

Chain OUTPUT (policy ACCEPT)

target prot opt source destination

DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)

target prot opt source destination

MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0

Chain DOCKER (2 references)

target prot opt source destination

Conclusion

Docker is a very easy to use and understand open platform that has the potential to be the next VMware. There are some providers that are already providing Docker containers including Google Container Engine. Docker is constantly in development so a lot of changes are expected but personally, I would like to see Clustering/HA, automation, and other features. So to get started, I will be exploring Swarm, Kubernetes and others next.