The deploy clears the images it hoarded, and keeps the ones a rollback needs (#119) - #187
Merged
Conversation
This was referenced Sep 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #119. On 09.09.2026 the dev
instance's 24 GB disk stood at 100% with 129 images — one per commit, nothing ever removing
one. Previews stopped starting, and dev read
unhealthybecause Docker could not write thefile its own health check needs. It was cleared by hand; nothing stopped it happening again.
Now a deployment clears what nothing needs:
everything it could go back to.
full cannot fetch the deployment that would fix it.
docker image prunewould have freed nothing here: every image is tagged with its commit sha,so none is ever dangling. It is removal by name.
What stays
Every image a container uses, running or stopped — so a preview on an older pull request keeps
its image — and the last three images that came up healthy on dev, listed in
/opt/platform-lite/deployed-imageson the instance.That rule is the third one. Review took the first two apart, and each time the casualty was
the same thing: the image
docs/deployment.mdtells an operator to roll back to, which it says"needs no registry access" — true only while the image is on the instance, because the
instance holds no registry credential of its own (G9).
1. "The three newest images." Previews pull into the same repository as dev. After a pull
request with two pushes is merged, the three newest are the new dev image and the two preview
images, and the version dev was running a minute earlier comes fourth and goes. The 7-second
rollback drilled on 05.09.2026 would have quietly stopped working.
2. "The last three deployments", seeded from
.env, recorded beside the.envwrite. Threeways to lose it, each reproduced before it was fixed:
.envnaming theversion rolled back from. The next deployment trusted the file, so the image dev was
actually running was the one it removed: deploy A, B, C; roll back to A; deploy D → on disk
B C D. Now the running version is read from the container.places on the list: A, B, C; D unhealthy, roll back to C; E unhealthy, roll back to C; F → on
disk
D E F, the last good version gone and both fallbacks known to be broken. Now a version isrecorded once it is healthy, and the running one only if its container says
healthyorit is on the list already — a version put back by hand stays even while a health check catches up.
docker loginboth write a file, and came before thefree-space check: at 100% the first write ended the run before any room was made. The check and
its clearing now run first. And the list is written to a temporary file and moved only when
the write succeeded — otherwise an empty file would have replaced every rollback target.
Also from review
dfended the deployment. Underset -euo pipefailthe assignment carrieddf's status and the fallback was never reached. Unreadable now reads as tight, and clearingis safe. The old line exits 1 where the path does not exist; the new one carries on.
the images are under
/var/lib/containerd, not/var/lib/docker. On one root filesystem thetwo read the same; on separate disks the rescue would have watched the wrong one. Both paths are
read, whichever exist, and the tighter counts.
(
3dbdg→devski);docker image rm <id>refuses an id tagged twice without--force.Removal is by
repo:tag, so the dead name is untagged and the image stays with the kept one.fn || echo WARNING, so bash runs itwith errexit off, and every read inside returns on failure rather than carrying on with an
empty list — which would otherwise have been reported as "nothing to remove".
Deliberately not here
preview-down.sh) — left out by Dawid's decision:preview images share dev's repository, so every deployment of dev sweeps them. A preview closed
without a merge keeps its image until the next one.
with #163.
preview-up.shremoves its old container,pulls its image, then copies the database before its first
docker run; in that gap nocontainer refers to the image. A dev deployment turning healthy inside it removes the image,
and if that deployment's
docker logout(older than this change, and shared by both scripts)has run by then, the preview's
docker runcannot pull it back: the job goes red with the oldpreview already gone, and a re-run fixes it. Closing it would take a lock around both spans in
preview-up.sh, which is the half of Dev instance keeps every image it ever pulled: the deploy must drop the old ones #119 left out.Test plan
The Docker daemon was not available locally, so the logic was tested against stand-in
dockercommands on PATH, with the functions cut verbatim from the script and run under
set -euo pipefail. A stateful simulator replays deployments in the script's order(record the running version →
up→ if healthy, record and clear):(the same sequence on the previous version: A removed)
(previous version: C removed, only broken D and E left)
dprev, two preview images pulled,mdeployed →dprevkept, previews cleareddeploy (a health check catching up after the disk was freed) → that version kept
(before the last fix: removed); a broken deploy nobody rolled back is still not recorded
smaller of two disks counts, in either order; nothing readable clears first
docker composeitself failingpsandinspect→ WARNING, nothing removedbash -n deploy/remote-deploy.sh,pnpm checkimages: N removed, andcat /opt/platform-lite/deployed-imageslists the running tag🤖 Generated with Claude Code