Skip to content

Registry Management

KSail wires two kinds of OCI registries into a cluster, each solving a different problem. This guide shows how to configure both.

Local registryMirror registries
HoldsYour images and GitOps artifactsCached upstream images (pull-through)
DirectionYou push, the cluster pullsThe cluster pulls, the mirror caches
WhyFast inner-loop builds, workload push targetsAvoid rate limits; images survive cluster recreation

The local registry is where your own artifacts live: application images you build during development, and the OCI artifact ksail workload push publishes for GitOps reconciliation.

  1. Wire a registry at init, then create the cluster:

    Terminal window
    ksail cluster init --local-registry localhost:5050
    ksail cluster create
  2. Build and push an image to it like any other registry:

    Terminal window
    docker build -t localhost:5050/my-app .
    docker push localhost:5050/my-app
  3. Reference it from a manifest in your source directory — the cluster pulls localhost:5050/my-app on the next reconcile.

The result: a registry that backs both your dev image builds and the GitOps artifact workload push produces — no external registry required to iterate locally.

localRegistry.registry is declarative in ksail.yaml, and the host can be an external registry such as GHCR — point workload push at a registry your CI and clusters already share:

spec:
cluster:
localRegistry:
# Format: [user:pass@]host[:port][/path]
registry: "${REGISTRY_USER}:${REGISTRY_PASS}@ghcr.io/myorg/myrepo"

Mirror registries are pull-through caches that sit between your cluster and upstream registries. The first pull fetches from upstream and caches the image in a Docker volume; every later pull — from any KSail cluster on the machine — is served locally. Recreating a cluster does not empty the cache.

Docker-based clusters (Vanilla, K3s, Talos-on-Docker, VCluster, KWOK) enable mirrors for docker.io, ghcr.io, quay.io, and registry.k8s.io by default. Talos on Hetzner requires explicit mirror configuration.

Terminal window
# Format: [user:pass@]host[=upstream]
# host — the registry the cluster's image pulls are redirected from
# upstream — the endpoint the mirror fetches from on a cache miss
# Mirror Docker Hub through its real upstream endpoint
ksail cluster init --mirror-registry docker.io=https://registry-1.docker.io
# Authenticated mirror — higher rate limits, private images
ksail cluster init --mirror-registry '${GITHUB_USER}:${GITHUB_TOKEN}@ghcr.io=https://ghcr.io'

What this buys you:

  • No more rate limits. Anonymous Docker Hub pulls are throttled aggressively in CI and shared networks; a mirror pulls once and serves everyone.
  • Store images once. Multiple clusters on the same machine share one cache instead of each pulling its own copy.
  • Fast recreate loops. ksail cluster delete && ksail cluster create reuses every cached image — the second create is dramatically faster.

For both registry kinds, you rarely pass credentials inline. KSail auto-discovers them from, in order, your Docker config (~/.docker/config.json, e.g. after docker login ghcr.io), environment variables (the ${VAR} placeholders above), and GitOps secrets already in the cluster. A docker login you have already run is usually enough.

ksail cluster init (--local-registry, --mirror-registry)