Skip to content

[WIP] hack: add opt-in NAT64 support to IPv6-only kind clusters - #1275

Draft
Yuan Gao (ygao-g) wants to merge 4 commits into
agent-substrate:mainfrom
ygao-g:kind-ipv6-nat64
Draft

[WIP] hack: add opt-in NAT64 support to IPv6-only kind clusters#1275
Yuan Gao (ygao-g) wants to merge 4 commits into
agent-substrate:mainfrom
ygao-g:kind-ipv6-nat64

Conversation

@ygao-g

@ygao-g Yuan Gao (ygao-g) commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

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_PREFIX on hack/create-kind-cluster.sh turns on both halves
together: it deploys the kubernetes-sigs/nat64 agent from
hack/third_party/nat64/ and points cluster DNS through the prefix that agent
translates. 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-cidr
default 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.yaml at tag v0.4.1 still names the v0.2.1
image — the only copy matching the release is on a moving branch. So
hack/third_party/nat64/VERSION pins the upstream commit and the image digest,
and hack/update/nat64.sh regenerates the manifest from that pin. The copy is
therefore 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_IMAGE overrides it for arm64
developers. 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 translator
inline: a job that supplied the very thing it exists to gate would prove
nothing by going green. It is also how this is verified — a dispatch of
958 753 1080 979 1116 1057 1275 onto main comes up green
(example run).

commit subject
b4e5c9db hack: drop the IPv6 kubeconfig repoint #958
3d8fa87f hack: fix DNS on IPv6-only kind clusters #958
4e5b6859 hack: add opt-in NAT64 support to IPv6-only kind clusters this PR

🤖 This PR was developed with AI assistance. I have reviewed and tested all changes.

@BenTheElder

Copy link
Copy Markdown
Collaborator

why do we need egress off of the host machine from the test cluster at all?

@BenTheElder

Copy link
Copy Markdown
Collaborator

we push images into the registry / cluster

@ygao-g

Yuan Gao (ygao-g) commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

why do we need egress off of the host machine from the test cluster at all?

Benjamin Elder (@BenTheElder) It's the actor-egress e2e tests, which fetch real external origins:

Before, 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. Remove the repoint logic, but note that limactl re-forwards the
published port to the host's v4 loopback only, so a macOS client cannot
directly access kind clusters run inside a Lima VM via `[::1]`. Instead,
operations should run inside the guest.

Tested: manual tests creating IPv6-only kind clusters on a local env
with IPv6 egress, namely macOS + Lima VM.
CoreDNS inherits the node's IPv4 resolver, which a v6-only pod cannot
reach. Change CoreDNS's Corefile to forward to an overridable IPv6
upstream. Also add a kind-registry:53 server block to CoreDNS. In
addition, `kind create` returns before the apiserver answers, so add
logic to wait for the control plane from inside the node first.

Tested: manual tests of creation and installation on a local env with
IPv6 egress, namely macOS + Lima VM. CI cannot verify this — the GitHub
runner is IPv4-only, so an IPv6-only cluster there additionally needs
DNS64 and NAT64.
IP_FAMILY=ipv6 has no documentation, so the two things that reliably go
wrong get rediscovered every time: a Docker daemon with IPv6 off, and a
host that cannot route IPv6 at all. The second is usually measured with
`curl -6 <host>`, which cannot tell a resolver returning no AAAA apart
from a host with no route, and reports neither.

Also covers the kubeconfig rewrite kubectl needs when the cluster runs
in a Lima VM on macOS, where kind publishes the apiserver on [::1] and
Lima forwards that port to the host's 127.0.0.1.
@ygao-g

Copy link
Copy Markdown
Collaborator Author

why do we need egress off of the host machine from the test cluster at all?

Benjamin Elder (Benjamin Elder (@BenTheElder)) It's the actor-egress e2e tests, which fetch real external origins:

Updates on this:

  • Discuss with others and have a pending item to use an in-cluster origin instead of example.com in the egress tests;
  • However, there is still traffic to external domain, as atelet that will fetch the runtime from gs://gviros/...

Benjamin Elder (@BenTheElder) Does this answer your questions?

@ygao-g Yuan Gao (ygao-g) changed the title hack: add opt-in NAT64 support to IPv6-only kind clusters [WIP] hack: add opt-in NAT64 support to IPv6-only kind clusters Sep 4, 2026
An IPv6-only kind cluster on a host without IPv6 egress comes up but
reaches nothing: external names resolve to unroutable addresses, and
the tree had no way to set up the translation such a host needs.
IPV6_DNS64_PREFIX now deploys the kubernetes-sigs/nat64 agent, points
cluster DNS through it, and probes from a pod that both halves meet.

Off by default, since translate_all routes every external name through
a translator a host with working IPv6 egress does not need. The agent's
IPv4 pool caps a node at a /120 Pod CIDR, so the prefix narrows
podSubnet too.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants