Title: DNS resolution broken on IPv6-only clusters with Docker: enable_network_magic() is IPv4-only
What happened:
On an IPv6-only cluster (ipFamily: ipv6) running on Docker, CoreDNS pods cannot resolve external names. The node's /etc/resolv.conf contains nameserver 172.18.0.1 (the IPv4 default gateway), which is unreachable from IPv6-only pods. CoreDNS logs show:
[ERROR] plugin/errors: 2 ghcr.io. AAAA: read udp [fd00:10:244::43]:59624->[172.18.0.1]:53: connect: network is unreachable
The root cause is in enable_network_magic() in the node entrypoint script. It replaces Docker's embedded DNS (127.0.0.11) with the IPv4 default gateway:
docker_host_ip=$(ip -4 route show default | cut -d' ' -f3)
This is hardcoded to IPv4. On an IPv6-only cluster, the resulting nameserver (172.18.0.1) is unreachable from pods that only have IPv6 addresses.
Note: even if the entrypoint used ip -6 route show default to get the IPv6 gateway (fc00:f853:ccd:e793::1), DNS still wouldn't work because Docker's DNS proxy does not listen on the IPv6 bridge gateway address (see moby/moby#41651). So the entrypoint fix alone is not sufficient — but it is a prerequisite for any future Docker fix to work.
What you expected to happen:
CoreDNS pods on an IPv6-only cluster should be able to forward DNS queries to an upstream resolver. The entrypoint should configure at least one IPv6-reachable nameserver in /etc/resolv.conf when the cluster uses ipFamily: ipv6.
How to reproduce it (as minimally and precisely as possible):
cat <<EOF | kind create cluster --name test --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
ipFamily: ipv6
EOF
# Check resolv.conf — only has IPv4 nameserver
docker exec test-control-plane cat /etc/resolv.conf
# nameserver 172.18.0.1
# The original Docker resolv.conf had 127.0.0.11
docker exec test-control-plane cat /etc/resolv.conf.original
# nameserver 127.0.0.11
# CoreDNS pods can't reach the IPv4 nameserver — verify from a debug pod
kubectl run -it --rm debug --image=alpine --restart=Never -- nslookup google.com
# ;; connection timed out; no servers could be reached
kind delete cluster --name test
Anything else we need to know?:
The entrypoint's enable_network_magic() function is entirely IPv4-centric:
- Uses
ip -4 route show default to find the host IP
- Only patches
iptables (not ip6tables)
- Only resolves
host.docker.internal via getent ahostsv4
On Podman this works by accident: Podman's aardvark-dns puts its own IPv6 nameserver in /etc/resolv.conf (not 127.0.0.11), so the sed replacement is a no-op and the working IPv6 nameserver survives.
There is also a Docker-side issue: Docker's DNS proxy only listens on the IPv4 bridge gateway, not the IPv6 one (moby/moby#41651, open since 2020). Even if kind fixed the entrypoint to use the IPv6 gateway, there's currently nothing listening on port 53 there. A complete fix requires both kind and Docker changes.
As a workaround, running a socat DNS proxy on the node bridges the gap:
# Get the node's IPv6 address
NODE_IPV6=$(docker inspect test-control-plane -f '{{.NetworkSettings.Networks.kind.GlobalIPv6Address}}')
# Install socat and start DNS proxies (UDP + TCP)
docker exec test-control-plane bash -c "
apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq socat >/dev/null 2>&1
socat UDP6-LISTEN:53,bind=[${NODE_IPV6}],fork,reuseaddr UDP4:172.18.0.1:53 &
socat TCP6-LISTEN:53,bind=[${NODE_IPV6}],fork,reuseaddr TCP4:172.18.0.1:53 &
"
# Patch CoreDNS to forward to the node's IPv6 address instead of /etc/resolv.conf
kubectl get cm coredns -n kube-system -o json \
| sed "s|forward . /etc/resolv.conf|forward . ${NODE_IPV6}|" \
| kubectl apply -f -
kubectl rollout restart deployment/coredns -n kube-system
Environment:
- kind version: v0.31.0 (also reproduced with v0.29.0)
- Runtime info: Docker 29.3.0
- Kubernetes version: v1.34.0
Title: DNS resolution broken on IPv6-only clusters with Docker: enable_network_magic() is IPv4-only
What happened:
On an IPv6-only cluster (
ipFamily: ipv6) running on Docker, CoreDNS pods cannot resolve external names. The node's/etc/resolv.confcontainsnameserver 172.18.0.1(the IPv4 default gateway), which is unreachable from IPv6-only pods. CoreDNS logs show:The root cause is in
enable_network_magic()in the node entrypoint script. It replaces Docker's embedded DNS (127.0.0.11) with the IPv4 default gateway:docker_host_ip=$(ip -4 route show default | cut -d' ' -f3)This is hardcoded to IPv4. On an IPv6-only cluster, the resulting nameserver (
172.18.0.1) is unreachable from pods that only have IPv6 addresses.Note: even if the entrypoint used
ip -6 route show defaultto get the IPv6 gateway (fc00:f853:ccd:e793::1), DNS still wouldn't work because Docker's DNS proxy does not listen on the IPv6 bridge gateway address (see moby/moby#41651). So the entrypoint fix alone is not sufficient — but it is a prerequisite for any future Docker fix to work.What you expected to happen:
CoreDNS pods on an IPv6-only cluster should be able to forward DNS queries to an upstream resolver. The entrypoint should configure at least one IPv6-reachable nameserver in
/etc/resolv.confwhen the cluster usesipFamily: ipv6.How to reproduce it (as minimally and precisely as possible):
Anything else we need to know?:
The entrypoint's
enable_network_magic()function is entirely IPv4-centric:ip -4 route show defaultto find the host IPiptables(notip6tables)host.docker.internalviagetent ahostsv4On Podman this works by accident: Podman's aardvark-dns puts its own IPv6 nameserver in
/etc/resolv.conf(not127.0.0.11), so the sed replacement is a no-op and the working IPv6 nameserver survives.There is also a Docker-side issue: Docker's DNS proxy only listens on the IPv4 bridge gateway, not the IPv6 one (moby/moby#41651, open since 2020). Even if kind fixed the entrypoint to use the IPv6 gateway, there's currently nothing listening on port 53 there. A complete fix requires both kind and Docker changes.
As a workaround, running a socat DNS proxy on the node bridges the gap:
Environment: