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 As mentioned in the comments below, the proper way to override the unit file is to create a directory /etc/systemd/system
and edit it./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!