The nodes' containerd 234,762 has its own image store, so an image from docker build is invisible to them. The quick fix, kind 14,561 load docker-image l3-booknest-api:1.3 --name l3-booknest, imports a tar export on every node. It suits CI, but copies the whole image each time, and breaks with a :latest tag: Kubernetes 5,150 then defaults to imagePullPolicy: Always, tries Docker Hub 514 and fails with ErrImagePull.
This chapter works like production instead: push to Image Registries's registry and let the nodes pull. kind's documented wiring puts the registry on the kind network and gives each node a hosts.toml that maps localhost:33500, the name you push to, onto l3-registry:5000, a name the nodes can reach:
docker run -d --name l3-registry --restart unless-stopped -p 127.0.0.1:33500:5000 \
-v l3-registry-data:/var/lib/registry registry:3 >/dev/null
docker network connect kind l3-registry
for i in api web; do docker tag l3-booknest-$i:1.3 localhost:33500/booknest-$i:1.3
docker push -q localhost:33500/booknest-$i:1.3; done
D=/etc/containerd/certs.d/localhost:33500
for node in $(kind get nodes --name l3-booknest); do
docker exec $node mkdir -p $D
echo '[host."http://l3-registry:5000"]' | docker exec -i $node cp /dev/stdin $D/hosts.toml
done
kubectl run pull-test --restart=Never --image=localhost:33500/booknest-api:1.3 >/dev/null \
--command -- node -e 'console.log("pulled and ran on Node", process.version)'
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/pull-test >/dev/null
kubectl logs pull-test && kubectl delete pod pull-testlocalhost:33500/booknest-api:1.3 localhost:33500/booknest-web:1.3 pulled and ran on Node v24.21.0 pod "pull-test" deleted from default namespace
containerd reads hosts.toml on each pull, so nothing restarts. BookNest keeps this wiring, plus kind's local-registry-hosting ConfigMap for tools such as Tilt 435,773 , as k8s/connect-registry.sh.