Skip to content

IPv6 Problems with Docker

  • hosting
  • servers
  • infrastructure
  • docker
  • updates

Where to start

Docker networking is, interesting.
IPv4 ✅
IPv4 and IPv6 🟡
IPV6 💥

Short and Sweet

I'm running n8n to automate things between various api's, it's pretty awesome. But now I want to migrate my n8n vm to be ipv6 only.
After turning off ipv4 and rebooting, suddenly none of the api calls worked. DNS resolution is failing. I've got DNS resolution working, JANKILY and it takes ~3 seconds to respond but it does respond. Still doesn't work as n8n tries to connect to the IPv4 responded with.

Some info

When IPv4 is available on the host system, the docker daemon will create a DNS server for the containers that's hardcoded to 127.0.0.11
It resolves container names first, then searches the external dns servers.

When IPv6 is enabled, the ip6 server reported on the host system via whatever dhcp client (using /run/hook-state/resolv.conf/eth0.dhcp6 || eth0.ra for example) is simply appended to the generated /etc/resolv.conf inside the docker containers.

When both IPv4 and IPv6 are enabled on the host system, this means there are two DNS entries generated in /etc/resolv.conf - which creates and fully explains the intermittent dns resolution problems I was seeing with the Nextcloud-AIO.

Musl and GLIBC

The containers that end up having issues are the ones based on Musl instead of GlibC - eg - anything Alpine based.

Musl does dns resolution in parrallel, it will query all the servers in /etc/resolv.conf and whichever responds the fastest wins and is reported back to whichever application requested the lookup. When ipv6 is enabled, the ipv6 dns server can and fairly often does respond faster than the internal docker one, but it's less likely than the docker one responding faster so it can easily appear on the surface as if things are working as intended. ** This explains the DNS resolution issues I was having with Nextcloud AIO!**

Some of the issue here has been alleviated in Alpine 3.18 ?

When ipv4 is removed

Things break. I SWEAR to god I've seen it not even put 127.0.0.11 into /etc/resolv.conf a few times , but I can't seem to reproduce that right now.

Testing

dockernet ip6 configuration.

networks:
  dockernet:
    name: app-dockernet
    enable_ipv6: true
    driver: bridge
    internal: false
    driver_opts:
      com.docker.network.enable_ipv6: "true"
      com.docker.network.bridge.enable_ip_masquerade: "true"
    ipam:
      driver: default
      config:
       - subnet: 172.19.238.0/24
         gateway: 172.19.238.1
       - subnet: fd49:1::/64
         gateway: fd49:1::1
  mongonet:
    name: mongonet
    driver: bridge
    internal: true

Test configurations:

/home/deadc0de # cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.17.4
PRETTY_NAME="Alpine Linux v3.17"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"
/home/deadc0de # docker version
Client:
 Version:           24.0.5
 API version:       1.43
 Go version:        go1.20.6
 Git commit:        ced0996
 Built:             Fri Jul 21 20:34:32 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          24.0.5
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.6
  Git commit:       a61e2b4
  Built:            Fri Jul 21 20:35:56 2023
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.6.18
  GitCommit:        2456e983eb9e37e47538f59ea18f2043c9a73640
 runc:
  Version:          1.1.5
  GitCommit:        f19387a6bec4944c770f7668ab51c4348d9c2f38
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

A

Only dockernet No mongonet

n8n with mongo, mongo express, and traefik as an ingress to n8n and mongo express.
This can really be any images, I just had these ready. It can be 3x nginx's with different names, or alpine's doing a while sleep loop. Anything to create a container and give it a hostname on the test network.

/home/deadc0de # docker exec -it app-n8n sh
~ $ nslookup mongo
Server:         127.0.0.11
Address:        127.0.0.11:53

Non-authoritative answer:
Name:   mongo
Address: 172.19.238.5

Non-authoritative answer:
Name:   mongo
Address: fd49:1::5

~ $ nslookup google.com
Server:         127.0.0.11
Address:        127.0.0.11:53

** server can't find google.com: SERVFAIL

** server can't find google.com: SERVFAIL

~ $ cat /etc/resolv.conf
nameserver 127.0.0.11
nameserver fd60::3
options ndots:0

Add DNS Entries

/etc/docker/daemon.json add dns: ["fd60::3"] the internal network dns ip6 address,

/home/deadc0de # nano /etc/docker/daemon.json
/home/deadc0de # service docker restart
 * Stopping Docker Daemon ...                                                                                                                                                                              [ ok ]
 * Starting Docker Daemon ...                                                                                                                                                                              [ ok ]
/home/deadc0de # docker exec -it app-n8n sh
~ $ nslookup mongo
Server:         127.0.0.11
Address:        127.0.0.11:53

Non-authoritative answer:
Name:   mongo
Address: 172.19.238.3

Non-authoritative answer:
Name:   mongo
Address: fd49:1::3

~ $ nslookup google.com
Server:         127.0.0.11
Address:        127.0.0.11:53

** server can't find google.com: SERVFAIL

** server can't find google.com: SERVFAIL

~ $

Add DNS Entries

/etc/docker/daemon.json add dns: ["fd60::3","192.168.255.1"] the internal network dns ip6 address,

/home/deadc0de # docker exec -it app-n8n sh
~ $ nslookup mongo
Server:         127.0.0.11
Address:        127.0.0.11:53

Non-authoritative answer:
Name:   mongo
Address: 172.19.238.5

Non-authoritative answer:
Name:   mongo
Address: fd49:1::5

~ $ nslookup google.com
Server:         127.0.0.11
Address:        127.0.0.11:53

Server:         fd60::3
Address:        [fd60::3]:53

Non-authoritative answer:
Name:   google.com
Address: 142.250.69.238

Non-authoritative answer:
Name:   google.com
Address: 2607:f8b0:4002:c05::65
Name:   google.com
Address: 2607:f8b0:4002:c05::66
Name:   google.com
Address: 2607:f8b0:4002:c05::8b
Name:   google.com
Address: 2607:f8b0:4002:c05::64

~ $
This is where things get interesting. Now the domains are resolving, but they're returning ipv4 addresses which can never work, and the nslookup for google takes much much longer than it should.

Current Results

n8n now resolves external addresses, but it tries to connect via IPv4 ERROR: connect ENETUNREACH 192.168.255.5:443

With mongonet added to every container too

/app # nano docker-compose.yml
/app # docker compose down && docker compose up -d
[+] Running 6/6
 ✔ Container traefik        Removed                                                                                                                                                                         0.5s
 ✔ Container app-n8n        Removed                                                                                                                                                                         4.2s
 ✔ Container mongo          Removed                                                                                                                                                                         0.4s
 ✔ Container mongo-express  Removed                                                                                                                                                                         0.5s
 ✔ Network app-dockernet    Removed                                                                                                                                                                         0.1s
 ✔ Network mongonet         Removed                                                                                                                                                                         0.2s
[+] Running 6/6
 ✔ Network app-dockernet    Created                                                                                                                                                                         0.1s
 ✔ Network mongonet         Created                                                                                                                                                                         0.0s
 ✔ Container mongo-express  Started                                                                                                                                                                         2.1s
 ✔ Container traefik        Started                                                                                                                                                                         2.1s
 ✔ Container app-n8n        Started                                                                                                                                                                         1.9s
 ✔ Container mongo          Started                                                                                                                                                                         1.2s
/app # docker exec -it app-n8n sh
~ $ nslookup mongo
Server:         127.0.0.11
Address:        127.0.0.11:53

Non-authoritative answer:
Name:   mongo
Address: 172.19.238.2

Non-authoritative answer:
Name:   mongo
Address: fd49:1::2

~ $ nslookup google.com
Server:         127.0.0.11
Address:        127.0.0.11:53

Server:         fd60::3
Address:        [fd60::3]:53

Non-authoritative answer:
Name:   google.com
Address: 142.250.72.46

Non-authoritative answer:
Name:   google.com
Address: 2607:f8b0:400f:804::200e

Current Results

No Change

Disclaimer

I'm no super genius, I just have a lot of time on my hands and I've dived as deep as I can go into this.

Further Reading