Short Answer:
Add (3) directives in your docker-compose.yml
file, (1) to daemon.json then re-build your containers and drop the Docker host's SLAAC addressed interface onto the docker-compose bridge and the container will itself receive an IPV6 SLAAC address.
This solution is demonstrated to be compatible with:
- docker-compose v. 2.1.1 and
- docker-compose file format v. 3.9.
If you don't know how to achieve the above read the longer answer below. It's actually not very difficult or time consuming.
Intro:
(Feel free to skip this intro- just context on the problems I'm trying to solve).
Like others visiting this question, I too have bumped-up against the issues of IPv6 networking in docker-compose. From what I could see certain IPV6 directives only worked with much older docker-compose file versions. And this could have knock-ons in respect to newer directives not being supported in the older docker-compose file versions I guess. And some of the solutions wouldn't work with swarm.
The only way many folks seemed to be able to get IPV6 connectivity working in their docker-compose configs was to use "IPV6 NAT" that some frustrated Docker user coded. That's not a criticism BTW: we need folks that will not be defeated who doggedly find ways around problems/limitations. But IPv6 was supposed to solve the problem of NAT'ing ;-)
I thought: There has to be an easier way!
And there was...
MY SETUP:
I'll describe my setup to enable comparative analysis if you run into difficulties:
MikroTik router configured for IPv6 SLAAC addressing which is connected to a dual-stack IPV4/V6 switch.
A Raspberry Pi 4 running 64bit Ubuntu 20.04 LTS connected to the switch via eth0 from which it gains its' IPv6 Global Unicast Address ("GUA") from the router.
Docker version used = Docker Engine Community v. 20.10.11
docker-compose = v. 2.1.1
docker-compose file format = v. 3.9
docker-compose IPv6 Config:
docker-compose.yml
My networks
section:
networks:
my-custom-network:
name: my-custom-network
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 192.168.XX.0/24
gateway: 192.168.xx.1
Note that the only IPv6-specific directive is just enable_ipv6: true
Next, the relevant part of my docker-compose.yml
file containing the other (2) IPv6-specific directives in the services
section for the container I want to IPV6 address is:
sysctls:
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.eth0.proxy_ndp=1
Obviously being YAML, take care to drop that part in with the correct leading spaces or it will puke misleading errors when the only problems is the indenting of the directives.
/etc/docker/daemon.json
I added just (1) IPv6 specific directive here:
"ipv6": true, "fixed-cidr-v6": "2001:470:1d3f:8::/64",
This step is necessary to assign IPv6 globally routable IPv6 addresses to our containers.
Finally, cut a fresh set of containers (but don't start them yet) after you're done tweaking:
docker-compose build --no-cache
Docker Host Network Config:
Validate the IPv6 config of the router is righteous before doing the IPv6 Docker config by pinging something with ping6
from your Docker host:
ping6 ipv6.google.com
If response is returned successfully, it establishes that both the Docker host & router can resolve and route IPv6 packets. The problem is now reduced to just getting the container IPV6 addressed.
- Since the Pi's eth0 interface is itself IPv6 addressed and talking IPv6 happily to our router, we'll join this to the docker-compose bridge:
NOTE: The above command is NON-Persistent- it won't survive reboot. The process of adding eth0 could be completely automated..
Start your containers:
docker-compose start
Verify the container now as an IPv6 GUA:
docker exec -it containerName bash
and then:
hostname -I
You should see a SLAAC configured IPv6 GUA address now.
- Poke a hole in your IPv6 firewall to tailor the access as required
SECURITY:
What you- thankfully- WON'T see: Any other containers receiving IPv6 GUA addresses.
Only the containers with those above sysctls
directives included in their configuration will receive an SLAAC IPv6 address- no others. In my case, I only wanted to expose the proxy container in front of a WordPress site, not the other containers, a webserver & backing database. So ONLY the proxy is reachable via IPv6.
Validation of Config:
The below site is a 100% docker-compose contraption configured using the above process, so the procedures outlined here can be demonstrated to work correctly:
http://[2001:470:1d3f:8:42:c0ff:fea8:1504]/
PLEASE NOTE: I'm changing ISP's next week, so might be some down-time while the new link is configured.
You can also validate the IPV6 config for a container's IPv6 addressing using an IPv6 Testing site:
https://ipv6-test.com/validate.php
Conclusion:
That's it: just (3) IPv6-specific directives in docker-compose
, (1) in daemon.json
, some bridging and a properly IPv6 configured router. Done. And no NATing required.
Again, not a perfect, nor ideal solution, but it's another way of getting round the IPv6 connectivity issues. if I've missed a step out somewhere please ping me a comment.