ADR-0016: Containerd mirror wiring for the registry cache, and Colima on containerd
Status: accepted · Date: 2026-10-13 · Decision makers: James Hebden
Context and Problem Statement
For the cluster to pull through the cache, its container runtime has to be told which registries to mirror. The runtime both drivers share is containerd, but they reach it differently: k3d hands a file to k3s, which turns it into containerd configuration, while Colima’s VM already runs its own containerd. The first design configured dockerd’s registry-mirrors, which only ever mirrors Docker Hub, so images from other registries bypassed the cache.
Decision Drivers
- Mirror every upstream registry, not only Docker Hub
- Use the one mechanism both drivers share
- A driver shouldn’t depend on a host name that only some container setups provide
- Configuration that Xianyun fully owns should be written, not merged
Considered Options
- Write containerd’s per-registry
hosts.tomlfor both drivers, delivered the way each driver can accept it, and run Colima on containerd - dockerd
registry-mirrorsindaemon.json - k3s
registries.yamlin Colima - Run two containerd instances in the Colima VM
Decision Outcome
Chosen option: “containerd hosts.toml for both drivers, and Colima on containerd”.
- k3d passes
--registry-config <registries.yaml>, and k3s expands it into containerd configuration at node start. - Colima is always started with
--runtime containerd. Xianyun writes/etc/containerd/config.toml(withconfig_pathset to/etc/containerd/certs.d) and one/etc/containerd/certs.d/<upstream>/hosts.tomlper upstream over SSH, then restarts containerd and k3s so they re-read it. The files are overwritten in full on everyup, which is simpler than merging and avoids duplicate entries, because Xianyun owns that directory and the shippedconfig.tomlhas nothing else to preserve. - The two drivers reach the host cache by different names: Colima uses
host.docker.internaland k3d useshost.k3d.internal. The shared code carries only the port.host.docker.internalis a Docker Desktop and Colima contract that rootless Docker doesn’t provide, so a shared name would let k3d pulls silently skip the cache. - Nothing is removed on
destroy. The configuration lives inside the VM, and deleting the VM deletes it.
Option 2 shipped first and mirrored Docker Hub only. Option 3 doesn’t work on Colima because its k3s uses the VM’s external containerd, so registries.yaml is never rendered into it. Option 4 doubles the footprint for no gain.
Consequences
Good:
- Every upstream in
registry_mirror.upstreamsis mirrored - Re-running
upconverges to the same configuration
Bad:
- A Colima profile no longer exposes a Docker socket, so
docker context useagainst it stops working fordocker buildanddocker run. Usenerdctlor a separate Colima profile. - The k3d mirror configuration sets
insecureSkipVerify: truefor the endpoint (TM-REG-003) - The Colima path has unit tests against a mocked runner but no end-to-end test
Neutral:
- Documented as shipped behaviour: the config reference says Xianyun always starts Colima on containerd
Implementation Location
crates/xianyun-cluster/src/driver/colima.rscrates/xianyun-cluster/src/driver/k3d.rscrates/xianyun-cli/src/commands/up.rs