hack: add opt-in NAT64 support to IPv6-only kind clusters - #1275
Draft
Yuan Gao (ygao-g) wants to merge 3 commits into
Draft
hack: add opt-in NAT64 support to IPv6-only kind clusters#1275Yuan Gao (ygao-g) wants to merge 3 commits into
Yuan Gao (ygao-g) wants to merge 3 commits into
Conversation
This was referenced Aug 27, 2026
Collaborator
|
why do we need egress off of the host machine from the test cluster at all? |
Collaborator
|
we push images into the registry / cluster |
Collaborator
Author
Benjamin Elder (@BenTheElder) It's the actor-egress e2e tests, which fetch real external origins:
|
Yuan Gao (ygao-g)
force-pushed
the
kind-ipv6-nat64
branch
from
August 28, 2026 00:21
a22c540 to
de34199
Compare
On an IPv6-only cluster the script rewrote kind's `https://[::1]:PORT` kubeconfig entry to `https://localhost:PORT` unconditionally. That breaks any host whose `/etc/hosts` leaves `localhost` off the `::1` line, including the Ubuntu cloud image Lima runs: `localhost` resolves v4-only and every later kubectl fails at connect. The rewrite existed for one case, a macOS client reaching kind inside a Lima VM, where limactl re-forwards the published port to the host's v4 loopback only. Running the loop inside the guest reaches `[::1]` directly and avoids that path entirely.
On a fresh IPv6-only kind cluster nothing resolves from inside a pod, so the install never completes. CoreDNS inherits the node's IPv4 resolver, which a v6-only pod cannot reach, and the in-cluster registry has no name a pod can look up. This gives the cluster its own Corefile, gated on ipv6: a forward to an IPv6 upstream, overridable with IPV6_DNS_UPSTREAM, and a kind-registry:53 server block so atelet can pull from its own network namespace. The Corefile patch runs kubectl straight after `kind create`, which returns before the apiserver answers, so the script now waits for the control plane from inside the node first.
Yuan Gao (ygao-g)
force-pushed
the
kind-ipv6-nat64
branch
from
August 28, 2026 16:23
de34199 to
39d6148
Compare
Yuan Gao (ygao-g)
marked this pull request as draft
August 28, 2026 22:50
Yuan Gao (ygao-g)
force-pushed
the
kind-ipv6-nat64
branch
5 times, most recently
from
August 29, 2026 16:31
5a52665 to
cd207e3
Compare
An IPv6-only kind cluster on a host with no IPv6 egress comes up but cannot reach anything: external names resolve to addresses nothing can route, so every outbound call from a pod times out. Nothing in the tree set up the translation such a host needs, so that cluster could not be brought up by hand at all. IPV6_DNS64_PREFIX now deploys the kubernetes-sigs/nat64 agent and points cluster DNS through it, and a probe pod proves the two halves meet before the install can fail minutes later as a rollout timeout. Off by default, because translate_all sends traffic through a translator that a host with working IPv6 egress does not need. The agent maps each Pod address into an IPv4 pool and refuses a Pod CIDR wider than /120, so the prefix also narrows what kubeadm hands out.
Yuan Gao (ygao-g)
force-pushed
the
kind-ipv6-nat64
branch
from
August 30, 2026 16:11
cd207e3 to
544e519
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Do not merge until #958 lands. Its two commits are in the diff below
because a fork branch cannot be based on another pull request; only the last
commit is under review here.
Part of #246.
An IPv6-only kind cluster is usable on a host that has IPv6 egress of its own,
and not on one that does not: external names resolve to addresses nothing can
reach, so anything that pulls an image or calls out times out. Every GitHub
Actions runner is the second kind of host, which is what stops an IPv6-only CI
lane from getting as far as the install.
IPV6_DNS64_PREFIXonhack/create-kind-cluster.shturns on both halvestogether: it deploys the kubernetes-sigs/nat64 agent from
hack/third_party/nat64/and points cluster DNS through the prefix that agenttranslates. Neither half is any use alone — the translator sits unused without
the DNS half, and the synthesized addresses go nowhere without the translator.
It stays opt-in and off by default, because it routes every external name
through the prefix, including names with AAAA records that already work.
The agent runs in the cluster rather than on the host, so nothing here enables
forwarding on the developer's machine or installs a userspace translator. It
translates Pod source addresses only; a hostNetwork pod and containerd use the
node's own dual-stack interfaces and reach IPv4 without it. Its
--nat-v4-cidrdefault is why the script narrows each node's pod CIDR to a
/120.The manifest is vendored rather than fetched at run time, because upstream ships
no release asset and its
install.yamlat tag v0.4.1 still names the v0.2.1image — the only copy matching the release is on a moving branch. So
hack/third_party/nat64/VERSIONpins the upstream commit and the image digest,and
hack/update/nat64.shregenerates the manifest from that pin. The copy istherefore reproducible rather than hand-made: re-running the script and
diffing is a drift check. Upstream's LICENSE is vendored alongside it.
It is amd64 only in practice — every published tag ships an x86-64 binary in the
arm64 slot of its image index — so
NAT64_IMAGEoverrides it for arm64developers. That covers CI, which is amd64.
#939 is the IPv6-only CI job this exists for. It asks for this setup from
hack/and reads back what it got, rather than configuring the translatorinline: a job that supplied the very thing it exists to gate would prove
nothing by going green.
9084d8eb1cb5a78f544e519b🤖 Generated with Claude Code