Cloud Native Blog - Container Solutions

Set the ip of the Docker bridge with Systemd

Written by Thijs Schnitger | Jun 29, 2015 7:38:03 AM

Whenever you connect to a network you don't control, you will have to work with whatever network address you're offered. Sometimes you find yourself stuck on a network where the subnet addressing interferes with your Docker daemon's default subnet, thus messing up your routes and leaving you unable to connect either to the internet or to your containers (right, Frank?).

When this happens, your routing table will look like this:

  
route
(out) Kernel IP routing table
(out) Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
(out) default         172.17.0.1      0.0.0.0         UG    1024   0        0 wlan0
(out) link-local      *               255.255.0.0     U     1000   0        0 wlan0
(out) 172.17.0.0      *               255.255.255.0   U     0      0        0 wlan0
(out) 172.17.0.0      *               255.255.0.0     U     0      0        0 docker0

As you can see, the last two lines overlap. The subnet specified for docker0 (172.17.0.0/16) encompasses the subnet of wlan0 (172.17.0.0/24), leading to unpredictable outcomes. For instance, where do you think a packet destined for 172.17.25.126 will be routed? The solution of course is to change the ip of docker0 and the subnet used by the Docker daemon to hand out addresses to containers. The docs show you how to configure docker0 but they don't tell you the complete story of how to change it when you're on a system using systemd. So let me show you.

On my Ubuntu system, the systemd unit file for the Docker service is /lib/systemd/system/docker.service. Copy this file to /etc/systemd/system and edit it. As mentioned in the comments below, the proper way to override the unit file is to create a directory /etc/systemd/system/docker.service.d and override any settings in a docker.conf file. We only need to override the line in the [Service] block that says ExecStart=/usr/bin/docker daemon -H fd:// and add the --bip argument at the end, but we need to clear ExecStart first.
So in the end the /etc/systemd/system/docker.service.d/docker.conf should contain this:


[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon -H fd:// --bip=192.168.169.1/24

As you can see I just picked a random private subnet, you can choose any as long as you stick within the ranges defined in RFC 1918.
After you changed a unit file, you need to reload the systemd daemon with:

  
systemctl daemon-reload

Before we can create a new bridge we have to get rid of the old one. Because the bridge is in use by the Docker daemon we need to stop that one first. A new bridge will then be recreated with the address we specified when we start the Docker daemon again. So first, stop the Docker daemon.

  
systemctl stop docker

We need a program called brctl to, well, control the bridge, which is part of the bridge-utils package.

  
sudo apt-get install bridge-utils

Bring down the docker0 interface:

  
sudo ip link set docker0 down

And delete the bridge.

  
sudo brctl delbr docker0

Finally, start the Docker daemon

  
systemctl start docker

Now, check out the docker0 interface:

  
ifconfig
(out)docker0   Link encap:Ethernet  HWaddr 26:6c:be:6f:1d:70  
(out)          inet addr:192.168.169.1  Bcast:0.0.0.0  Mask:255.255.255.0
(out)          inet6 addr: fe80::246c:beff:fe6f:1d70/64 Scope:Link
(out)          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
(out)          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
(out)          TX packets:264 errors:0 dropped:0 overruns:0 carrier:0
(out)          collisions:0 txqueuelen:0 
(out)          RX bytes:0 (0.0 B)  TX bytes:44757 (44.7 KB)

And your routing table should look like:

  
route
(out)Kernel IP routing table
(out)Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
(out)default         172.17.0.1      0.0.0.0         UG    1024   0        0 wlan0
(out)link-local      *               255.255.0.0     U     1000   0        0 wlan0
(out)172.17.0.0      *               255.255.255.0   U     0      0        0 wlan0
(out)192.168.169.0   *               255.255.255.0   U     0      0        0 docker0

	

If it does, you should be all set! To check if it works as expected, fire up a container and check it's ip:

  
docker run daemon nginx
docker inspect --format "" `docker ps -lq`
(out)192.168.169.2

I hope you find this post useful, let me know in the comments if you do or if you have any questions!