Sync next2 into next: the four fixes from the fsn1app1 deploy rehearsal #222

Merged
clawbot merged 4 commits from next2 into next 2026-09-24 12:15:04 +02:00
4 Commits
Author SHA1 Message Date
clawbot a57efeed12 Build apps with BuildKit so build stages stop piling up (closes #220)
Check / check (pull_request) Successful in 3m24s
Multi-stage app builds left an untagged image for every build stage after each deploy, and nothing could safely remove them. upaas now asks Docker for a BuildKit build, which keeps stages in Docker's build cache instead of as images; Docker limits and cleans that cache itself. The final image is still tagged `upaas-<app>:<N>`, so old-image cleanup is unchanged. BuildKit's progress messages are decoded and written to the deployment log as plain text.

Deviation: adds `github.com/moby/buildkit` v0.16.0 (matching the pinned Docker client), added with `go get` since no make target adds dependencies.
Judgement call: the cache limit is on by default only from Docker Engine 28.2; older engines need the `daemon.json` setting the README now names.

Model: opus-5-5
2026-09-23 12:45:42 +02:00
clawbot a60ea144fb Remove images from earlier deploys after a successful deploy (closes #216)
Every deploy built and tagged a new image and nothing removed the old ones, so disk use grew with each push. After a successful deploy, upaas now removes the app's old `upaas-<app>:<N>` tags by name, without force, keeping the current image and the previous one that rollback starts. Docker deletes an image only when no other tag or container still uses it, so an image shared with another app stays. A failed removal is a warning in the deployment log, not a failed deploy. The post-deploy step is one function, tested against a fake Docker API.

Judgement call: untagged images from other stages of a multi-stage build stay; they are the build cache.
On the first deploy after upgrading, all older images of that app are removed at once.

Model: opus-5-5
2026-09-23 12:24:36 +02:00
clawbot 56345bc6f6 Remove the git clone container's anonymous volume with it (closes #215)
The pinned `alpine/git` image declares a volume at `/git`, so every clone container got an anonymous volume, and the container was removed without its volumes, leaving one volume behind per deploy. The clone container is now removed together with its volumes, whether the clone succeeds, fails or is cancelled; the removal uses a context that outlives cancellation. Tests cover success, failure and cancellation against a fake Docker API, and a manual check against real Docker is recorded on the PR. The old app container's own anonymous volumes are still kept on redeploy, since deleting them could discard app data.

Model: opus-5-5
2026-09-23 12:04:32 +02:00
clawbot ddcd179841 Keep deployment logs findable after the container is recreated (closes #214)
Deployment logs were stored under a directory named after the container's hostname, and the path was worked out again from the current hostname on download. Docker gives a recreated container a new hostname, so every older log download returned 404. New logs now go to `logs/<appname>/` with no hostname in the path. Logs written by older versions under an old hostname directory are still found by looking one directory deeper, inside the same confined log root. Tests cover both the hostname-free path and downloading an old-layout log.

Model: opus-5-5
2026-09-23 11:44:30 +02:00