-
fix: make local docker uploads replica-independent (#104)
ci/woodpecker/tag/docker Pipeline was successfulreleased this
2026-07-05 17:39:49 +10:00 | 18 commits to master since this releaseWhy
Chunked blob uploads kept the in-progress session in process memory keyed by upload UUID, so the
POST/PATCH/PUTof a singledocker pushhad to land on the same replica. The API runs atminReplicas: 2with no session affinity (see argocd-appsapi-hpa.yaml), so a real push — which streams the layer viaPATCHthen finalises withPUT— intermittently 404s withBLOB_UPLOAD_UNKNOWNwhen a chunk hits a replica that never saw thePOST. This was flagged when the local docker registry landed (#103).Changes
- Stage chunked uploads in object storage under
uploads/<uuid>instead of an in-memory temp file. The UUID travels in theLocationURL handed to the client, so any replica reconstructs the staging key with no shared in-process state. Finalise streams the staged bytes plus any trailingPUTbody through the CAS in one pass; monolithic uploads are unchanged. - Support
DELETEof an in-progress upload (cancel) by dropping its staging object. - Reap abandoned staging objects in the GC (
uploads/older than 24h) via a newS3.ListStaleObjects, so cancelled/interrupted pushes don't leak.
Verification
- Split a single push across two instances sharing one Postgres+MinIO:
POST→A,PATCH→B,PUT→A finalises with the correct digest, and the blob pulls back byte-identical from both replicas. Config-blob and manifest pushes split the same way succeed;tags/listis correct. (Pre-fix, the cross-replicaPATCH404s.) scripts/docker-e2e.shstill passes (incl.TestLocalDockerPushPull); unit tests +go vetclean.
Reviewed-on: #104
Co-authored-by: Ben Vincent ben@unkin.net
Co-committed-by: Ben Vincent ben@unkin.netDownloads
- Stage chunked uploads in object storage under