Registry CLI¶
Every cairn-registry command. For what the tool actually does and why you'd want it, see
Registry — this page is just the command surface.
setup¶
sudo cairn-registry setup --dry-run
sudo cairn-registry setup
Provisions this machine as a registry host: certificate, config file, compose project, running container. Idempotent — safe to re-run.
Flags:
--dry-run— print every action, change nothing.--force— replace files cairn itself generates (the certificate, the compose file) when they no longer match what the current config would produce. The old file is kept alongside as a backup. Never applies toregistry.tomlitself — see Registry: changing the port.--only <stage>— run one stage only:preflight,admin-group, orregistry.--private-ip <ip>— also cover this address in the certificate, for when the registry and its clients later split onto separate machines.--skip-disk-free— proceed even if free disk space is under the minimum.--admin-group <name>— which group/etc/cairnis shared with (defaultcairn-admins).--no-admin-group— skip sharing/etc/cairnwith a group; leave it exactly as found.
A real (non---dry-run) run that actually brings the registry container up — the full run,
or --only registry on its own — finishes by running the same checks as doctor and exits
with its code. --dry-run and --only preflight/--only admin-group skip this, since
neither leaves anything running to check yet.
Storage¶
Images served by the registry are stored in /var/lib/cairn-registry by default.
Configuration¶
setup scaffolds /etc/cairn/registry.toml the first time none exists, fully commented:
[registry]
port = 5000
bind_address = "127.0.0.1"
data_dir = "/var/lib/cairn-registry"
[registry.retention]
enabled = false
keep_last = 10
max_age_days = 90
[registry.gc]
schedule = "weekly"
port/bind_address— where the registry listens.data_dir— where image blobs are stored on disk. An operator-chosen path, not an anonymous Docker volume, so you can point it at a specific disk.[registry.retention]— see prune below.[registry.gc] schedule— the cadencesetup-timerinstalls (a systemdOnCalendar=value;"weekly"/"daily"are valid as-is).
The file is absent-safe: with no file at all, cairn-registry setup still runs against these
same defaults. Once the file exists, it's entirely yours — edit any value, then re-apply with
sudo cairn-registry setup --force.
setup-timer¶
sudo cairn-registry setup-timer --dry-run
sudo cairn-registry setup-timer
Installs a systemd timer that runs prune then gc on the schedule set by [registry.gc]
schedule. Installed enabled but not started — run the first pass by hand and watch it,
then:
sudo systemctl start cairn-registry-maintenance.timer
status / start / stop / restart¶
Thin wrappers over docker compose, addressing the exact project setup created:
cairn-registry status # docker compose ps
cairn-registry start # docker compose up -d
cairn-registry stop # docker compose stop — data is untouched
cairn-registry restart # docker compose restart
images¶
cairn-registry images
cairn-registry images --host ghcr.io --namespace acmecorp --image erpnext-v16
cairn-registry images --namespace acmecorp --image 'erpnext-*'
cairn-registry images --json
Reports what cairn built, read from a registry's own API — never pulls an image to find out.
This is the registry-side counterpart to cairn-build images, which only ever answers for
the build machine itself; a registry (this machine's own, or a client's remote one) is always
this command's job, not that one's.
Flags:
--host <host[:port]>— which registry to query. Default: this machine's own (fromregistry.toml). Any other value queries that registry instead, local or remote.--namespace <name>— only repositories directly under this namespace (typically one client).--image <name>— only this image name; accepts a glob, e.g.'erpnext-*'.--json— machine-readable output.
An exact --namespace and --image together (no glob) read that one repository directly,
the same authenticated way cairn-build push/assign-tag do — this is what reaches a
registry that requires a login, GHCR included, after docker login/podman login. Any other
combination — no --image, or --image is a glob — enumerates the registry's whole catalog
first, then filters. Catalog enumeration only works unauthenticated, which cairn's own
self-hosted registry is by design; most third-party registries refuse it, so a whole-registry
or glob query against one of those will fail plainly rather than pretend to a partial answer.
Output is grouped by input hash and digest, not one row per tag — a deterministic content-hash
tag, latest, and any moving tag you assigned (an environment pointer, or anything else) can
all name the same build, so every name for it shows up together rather than scattered across
rows you'd otherwise have to cross-reference by eye. The repository line prints the full
reference — registry host included — not just the bare name: image = "..." in a target
descriptor needs the host too, since cairn refuses to assume one, and this is meant to be
copy-pasted straight in:
Registry ghcr.io
Repository ghcr.io/acmecorp/erpnext-v16
v16-a1b2c3d4e5f6 (input hash a1b2c3d4e5f6)
frappe v16.25.0 9a8daf34
erpnext v16.26.1 fd00cebb
a1b2c3d4e5f6 1.79 GB 2d latest, production, v16-a1b2c3d4e5f6
1 image(s) built by cairn in ghcr.io/acmecorp/erpnext-v16 across 1 input hash(es).
Sizes are the download size from the registry, not unpacked size on disk.
This is usually the fastest way to find the exact tag to put into a target's descriptor — whatever's listed alongside the build you want is the tag to watch.
doctor¶
cairn-registry doctor
OK reachable 127.0.0.1:5000 — 0 repositor(y/ies)
OK certificate /etc/cairn/registry.crt valid
OK disk headroom 82 GB free at /var/lib/cairn-registry
All 3 checks passed.
Three checks, each read-only:
- reachable — the registry answers over HTTPS.
- certificate — present and not expired.
- disk headroom — free space under
data_dir.
setup runs this automatically at the end of a real run — see setup above.
prune¶
cairn-registry prune --dry-run # report only
cairn-registry prune --yes # delete without prompting
For every repository, reports every digest's disposition — kept or deleted, and why — before
deleting anything. Deletes nothing unless [registry.retention] enabled = true; with it
false (the default), prune still runs and still reports, just never deletes.
Rules, in order:
- Only digests whose every tag matches cairn's own content-hash shape are even eligible. A
digest still carrying a moving series tag (
v16) or a declared environment tag (production) is categorically protected — never a candidate for deletion. - The newest
keep_lasteligible digests are kept regardless of age — the rollback floor. - Of what's left, only digests older than
max_age_daysare deleted.
gc¶
cairn-registry gc --dry-run # report the read-only window, then stop
cairn-registry gc --yes # actually reclaim storage
Reclaims disk space for digests prune already deleted — prune marks things eligible, gc
is the step that actually frees the bytes.
- Briefly puts the registry into read-only maintenance mode. Pulls (including a Target machine's own polling) continue throughout; pushes are refused until it finishes.
- Requires
--yesor--dry-run— it never runs with neither.