Set the ip of the Docker bridge with Systemd

Docker logoWhenever 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:

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:

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:

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.

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

Bring down the docker0 interface:

And delete the bridge.

Finally, start the Docker daemon

Now, check out the docker0 interface:

And your routing table should look like:

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

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

The following two tabs change content below.

Thijs Schnitger

Senior Engineer at Container Solutions
Thijs is a Systems Engineer specialized in all things Linux. At Container Solutions he mainly focuses on programmable infrastructure, when he’s not busy lending a hand. His years of experience with development, delivery and operations make him an allround application debugger and problem solver.

Latest posts by Thijs Schnitger (see all)

5 Comments

  1. Hi,

    As mentioned in the docker documentation, it is best not to copy the whole systemd unit file but to create an override with just the options you want to tweak. That way, if the unit file is changed in a newer version of the package, you will get the new options and you will keep your modifications. One thing that is not mentioned in the docs, though, is that

    is a special case, and need to be cleared before getting defined again:


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

  2. Thanks for the post! I just did this on Ubuntu 16 2 ways.

    The first I just was a Bad Person and I modified the /lib/systemd/system/docker.service to add the –bip info and it worked.

    So I rolled back to my pre-modified snapshot and created the docker.conf file for the over right and put in the info you mentioned. However when I started up docker if failed with an error I can’t scroll back to. I looked at the original docker.service file and it looks like it may have changed since last year since my string was /usr/bin/dockerd -H fd://

    So I modified the new docker.conf to be

    [Service]
    ExecStart=
    ExecStart=/usr/bin/dockerd -H fd:// –bip=172.17.16.1/24

    Started up docker and got the correct subnet for docker0.

    Thanks for the great writeup!

  3. Thank you very much for this tutorial. It is very useful.
    But since the command line options have changed after 1.8. You should now replace -d by the subcommand daemon.

Leave a Reply

Your email address will not be published. Required fields are marked *