Mirror the flight-deck bootstrap image set to ghcr.io #794
Labels
No labels
burndown-2026-06
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/infrastructure#794
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Stand up a ghcr.io copy of the images a rebuilt cluster needs, so losing
kai-server does not also lose every image required to bring one back.
This issue is written to be picked up cold. Everything below marked verified
was measured on 2026-08-12 and does not need re-deriving. Everything under
settle first is an open decision.
Why
Every workload image lives in exactly one place, the Forgejo package registry on
kai-server. The standalone registry in the
registrynamespace on NodePort30500 is a different failure domain from the Forgejo application, so it
survives a bad Forgejo upgrade, but it does not survive losing the machine,
because it is on the machine.
Restic snapshots to ser8 cover data. They do not make images pullable into a
cluster that does not exist yet.
Scope, decided
Mirror these, and only these.
Six runtime images at the exact SHAs the fleet runs, nine tags in total because
two images run at more than one SHA:
Plus
agentic-osat its:releasealias only. That is the CI and dev-baseimage, so without it a recovered cluster can run workloads but cannot build new
ones.
That list drifts as pins move. Regenerate it rather than trusting the snapshot
above:
Explicitly out of scope
agentic-os, which alone is about 116 GiB per issue 733. Mirroring historycosts nearly all the bytes and buys nearly nothing for recovery.
serving path. Deploy keeps pulling from Forgejo. Changing image references is
a separate decision with its own blast radius.
imagePullPolicy: Alwaysproblem. Tracked incoilyco-bridge/deployissue 372. A second registry is not its fix, andfixing it here would confuse two unrelated failures.
coilyco-gamingandcoilyco-bridgeimages are not in thispass.
Verified, do not re-derive
coilyco-opsGitHub App holdspackages: writeon all four installations, including thecoilyco-flight-deckorganisation withrepository_selection: all. Soghcr.io/coilyco-flight-deck/<image>is reachable with the credential thatalready exists. No new account, no new secret, no token-refresh timer.
/github/coilyco-ops-app-idand/github/coilyco-ops-private-key-base64. The mirror controller inscripts/forgejo_github_mirror_sync.pyalready mints short-lived installationtokens from these and is the working reference for how to do it.
ghcr.io/coilysiren/lunch-money-k8s:latest, and thedefault/docker-registrySecret's auth entry is
ghcr.io.limitis silentlycapped, so enumerate with
&page=Nuntil a short page returns./forgejo/coilyco-ops/registry-read-tokenexistsfor pulling from the Forgejo side.
Settle first
Forgejo-to-GitHub mirror as a user systemd timer, it has passwordless sudo,
and it is not the machine this protects against losing. kai-server is the
wrong host for the same reason the current registry is.
deploy pin changes. A timer is simpler and tolerates missed runs. A hook is
timelier but couples release to a second registry being up.
skopeo copymoves manifests and layers betweenregistries without a local daemon and preserves digests.
crane copyisequivalent. Pulling and re-pushing through Docker is the option to avoid,
because it rewrites manifests and breaks digest equality.
package store did, which reached 120.3 GiB and forced two emergency purges,
recorded in issues 733 and 599.
Constraints
:latestor any moving alias except
agentic-os:release, which is already a movingalias upstream and is mirrored as-is. The deploy contract says deployment uses
the full upstream source SHA and does not substitute
latest, and a recoverymirror gains nothing from breaking that. During a rebuild, "which build is
:latest" is the worst time to be unsure.on the free tier carry storage and bandwidth limits. These images are already
published to a public Forgejo registry, so publish them public deliberately
rather than discovering the limit later.
update, never prune, never force. A stale extra tag is harmless. A deleted one
during recovery is not.
logging and continuing, so a silently empty mirror is not discovered during a
recovery.
Done when
agentic-os:releaseexist underghcr.io/coilyco-flight-deck/, with digests matching the Forgejo source.change and in what order to pull from the mirror instead.
docs/carries the runbook, and the trifecta is updated if a feature entry iswarranted.
Related
coilyco-bridge/deployissue 372, the pull-policy problem this is not.scripts/forgejo_github_mirror_sync.pyas the working reference for App-tokenminting, per-target scoping, and never-force mirroring.
One loose end found while scoping
deploy/lunch-money/values.yamlin this repository pinsdocker.io/coilysiren/lunch-money-k8s. That Docker Hub repository returns 404,while the running pod uses a
ghcr.iocopy. The tracked reference points at aregistry path that does not exist, so a reconcile from that file would fail to
pull. Worth fixing independently of this work.
Evaluate an ECR disaster-recovery mirror for fleet imagesto Mirror fleet images to ghcr.io for cold-rebuild recoveryMirror fleet images to ghcr.io for cold-rebuild recoveryto Mirror the flight-deck bootstrap image set to ghcr.io