Native IPv6 Functionality in Docker

The days of kludgy hacks for IPv6-connected docker containers are over. A recent PR merged native IPv6 functionality into the docker daemon. The new bits have not yet made it into the docker ppa package as of 1/17/2015. Therefore, some assembly is required.

You’ll need to compile docker from source. The only currently supported docker build process uses docker. Does this remind anyone of the movie Inception?

Here’s an installation process you can use on a fresh 64-bit Ubuntu 14.04 VM.

 

sudo apt-get update
sudo apt-get -y install git build-essential docker.io
git clone https://github.com/docker/docker.git
cd docker
sudo make build
sudo make binary
sudo service docker.io stop
sudo ip link set docker0 down
sudo ip link delete docker0
VERSION=1.4.1  # version as of this writing
sudo cp ./bundles/$VERSION-dev/binary/docker-$VERSION-dev $(which docker)
sudo echo "DOCKER_OPTS='--ipv6 --fixed-cidr-v6=\"2001:DB8::/64\"'" >> /etc/default/docker.io
service docker.io start

Docker does not put an address within the /64 on the docker0 bridge. It uses fe80::1/64. The default route in the container is set to this link local address.

Your containers will not be able to communicate with the IPv6 internet unless the /64 you’ve selected is routed to the docker host. Unlike how docker handles IPv4 in containers, there is no NAT. Use a provider that will route the /64 to your docker host. Linode did this for me after I emailed the request to its support team. Using providers such as DigitalOcean that support IPv6 but do not route a /64 to your VM are not positioned to offer IPv6 connectivity to containers. You’ll have to use the Neighbor Discovery hack that I described in another post.

I’m not sure why docker doesn’t have an option to connect containers directly to a bridge that includes the internet-facing port. Doing this with LXC is easy to accomplish. I suspect this can be done with docker. I don’t know how though. Perhaps someone with more more knowledge of docker can explain how to attach the daemon to a bridge with the LAN interface.

I’ll note that the docker build environment appears to have a bug with name resolution in the build container if IPv6 DNS servers are in /etc/resolv.conf. I didn’t want to invest the time to troubleshoot it. You can comment out the IPv6 DNS servers in the docker host’s /etc/resolv.conf file to avoid the defect.

If you run into problems, let me know in the comments.

16 thoughts on “Native IPv6 Functionality in Docker

  1. Thanks for the info, this is exactly what I was looking for. It should be noted that I got rather confused at first, as you wrote 1/17/2014 rather than 1/17/2015. The new year does that to us :)

      1. I would be very interested in an article of your experiences actually getting IPv6 working in a docker container on DO. I’ve spent a good amount of time digging around google and my terminal, and have yet to find anything that actually works with a current version of docker.

        Your articles are admittedly the closest I’ve gotten.
        TY, etc. :)

  2. Ian,

    You are right that there is very limited information out there on using docker with IPv6. I had to read the github issues log to figure out some aspects of this article. Can you elaborate on what’s giving you problems or inform me of things you’d like to know more about? I can share my thoughts in a long comment or perhaps another blog post.

    1. It turns out that half of my issues where from mistakenly passing the IPv6 options to the docker client rather than starting the daemon with them. Now it’s nicely setting up the v6 addresses and routing for me, but inbound packets still aren’t making to my container. When setting it all up by hand (addresses and routes), I managed to get it working once, but was unable to reproduce it. How I’ve set it up is roughly:

      Everything is on the …:4008/125 subnet.
      On the host docker0 gets …:4009/125, and a route is added to point the subnet to docker0.
      In the container I give eth0 the IP …:400a/125, and the default route is set to …:4009 via eth0 (the docker0 IP).

      The only problem with that, is that the docker daemon seems to step in and mess around in a seemingly unpredictable way, because I was regularly getting exactly 8 pings back before they stopped coming through. Now with the daemon properly setup with –ipv6 –fixed-cidr-v6=”…:4008/125″ in /etc/default/docker, it’s assigning the addresses and setting up the default route as expected, but when I add the route for …:4008/125 on the host, nothing ever gets through to the container. I’ve checked everything several times and can’t seem to find the disconnect (no pun intended).

      I’m using ping6 google.com to test for connectivity, and it works fine when I’m pinging any address on an interface on the host machine. Also, I do have ipv6 forwarding on in sysctl.

      If you have any suggestions, I’m all ears :)

  3. sudo apt-get -y install git build-essential docker.io

    This line gives me the following error:

    E: Package ‘docker.io’ has no installation candidate

    What should be done regarding this?

  4. Jeff, I’ve successfully configured my containers to get IPv6 addresses and I’m using ndppd to proxy the ND messages, however what would be your approach to assign a “static” IPv6 address to a container for production use, similar to binding an exposed port to a specific IPv4 address? Your tutorial was super helpful, thanks!

    1. Brad, I don’t think docker has a built-in way to do static assignment. I suspect its developers believe that injecting this state into the container is not a best practice. It’s not a very “cloudy” thing to do. I believe many of the fleet management packages use a model in the which the VM/container registers with a controller that assigns a DNS name, which is used to identify the VM/container.

      I can think of several ways to accomplish what you want.

      1) Use the lxc driver – If you switch from using libcontainer to lxc, you can pass options to the lxc options including a static IPv6 address.

      2) Modify pipework – Modifying Jérôme Petazzoni’s pipework script (https://github.com/jpetazzo/pipework) to support shouldn’t be too difficult if you knew a little bash scripting.

      3) DHCPv6 – You can “statically” assign IPv6 address based on virtual MAC addresses.

      1. Thanks for the thoughtful reply, this is great. What I ended up doing is actually running docker run with the –cap-add=NET_ADMIN flag, and then you can add addresses to the container’s eth0 interface. You also need to use NDPPD to forward the neighbour discovery messages from the docker0 bridge to your network. I’m going to make a blog post on this and I’ll link here, when I do.

Leave a reply to Jeff Loughridge Cancel reply