WARNING
In production IPv6 should always be used without NAT. Only use IPv6 and NAT for testing purposes. There is no valid reason to use IPv6 with NAT in any production environment.
IPv6 and NAT
IPv6 is designed to remove the need for NAT and that is a very, very good thing. NAT breaks Peer-to-Peer connections and that is exactly what is one of the great things of IPv6. Every device on the internet gets it’s own public IP-Address again.
Docker and IPv6
Support for IPv6 in Docker has been there for a while now. It is disabled by default however. The documentation describes on how to enable it.
I wanted to enable IPv6 on my Docker setup on my laptop running Ubuntu, but as my laptop is a mobile device the IPv6 prefix I have changes when I move to a different location. IPv6 Prefix Delegation isn’t available at every IPv6-enabled location either, so I wanted to figure out if I could enable IPv6 in my Docker setup locally and use NAT to have my containers reach the internet over IPv6.
At home I have IPv6 via ZeelandNet and at the office we have a VDSL connection from XS4All. When I’m on a remote location I enable our OpenVPN tunnel which has IPv6 enabled. This way I always have IPv6 available.
The Docker documentation shows that enabling IPv6 is very easy. I modified the systemd service file of docker and added a fixed IPv6 CIDR:
ExecStart=/usr/bin/dockerd --ipv6 --fixed-cidr-v6="fd00::/64" -H fd://
fd00::/64 is a Site-Local IPv6 subnet (deprecated) which can be safely used.
I then added a NAT rule into ip6tables so that it would NAT for me:
sudo ip6tables -t nat -A POSTROUTING -s fd00::/64 -j MASQUERADE
Result
My Docker containers now get a IPv6 Address as can be seen below:
root@da80cf3d8532:~# ip -6 a 1: lo:mtu 65536 state UNKNOWN qlen 1 inet6 ::1/128 scope host valid_lft forever preferred_lft forever 15: eth0@if16: mtu 1500 state UP inet6 fd00::242:ac11:2/64 scope global nodad valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever root@da80cf3d8532:~#
In this case the address is fd00::242:ac11:2 which as assigned by Docker.
Since my laptop has IPv6 I can now ping pcextreme.nl from my Docker container.
root@da80cf3d8532:~# ping6 -c 3 pcextreme.nl -n PING pcextreme.nl (2a00:f10:101:0:46e:c2ff:fe00:93): 56 data bytes 64 bytes from 2a00:f10:101:0:46e:c2ff:fe00:93: icmp_seq=0 ttl=61 time=14.368 ms 64 bytes from 2a00:f10:101:0:46e:c2ff:fe00:93: icmp_seq=1 ttl=61 time=16.132 ms 64 bytes from 2a00:f10:101:0:46e:c2ff:fe00:93: icmp_seq=2 ttl=61 time=15.790 ms --- pcextreme.nl ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max/stddev = 14.368/15.430/16.132/0.764 ms root@da80cf3d8532:~#
Again, this should ONLY be used for testing purposes. For production IPv6 Prefix Delegation is the route to go down.