Repository navigation
ci(images): publish managed-database images to GHCR and gate releases on them - #1462
Merged
Merged
Conversation
… on them The postgres/pgvector/timescaledb/postgres-ha/redis/mongodb WAL-G images were pushed to Docker Hub by hand, with no workflow and no record of what was published. Several tags the runtime references were never published (postgres-walg:15-bookworm and :16-bookworm), and nothing caught it. Add database-images.yml, driven by a tested planner script: - floating major tags are rebuilt every run (weekly schedule, pushes that touch an image, manual dispatch) so upstream base-image security rebuilds are picked up; - the newest 4 PostgreSQL minors per major are discovered from upstream and published as pinned tags (18.6/18.4/18.3/18.2-bookworm); frozen older minors are only built when missing or their context changed; - every image is verified before push (wal-g runs, and postgres reports exactly the tagged version), then signed with cosign. release.yml now calls it in ensure mode: it publishes only missing tags, so a release never moves a tag under a running database, then fails the release unless every required tag is anonymously pullable from GHCR. postgres-ha now takes the auto-failover package name from the upstream PG_MAJOR so it can build from a minor tag, and publishes the -bookworm-walg alias that DEFAULT_CLUSTER_IMAGE names. Signed-off-by: David Viejo <dviejokfs@temps.sh> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
📓 Changelog previewThis is what your commits will add to the generated ## [Unreleased]
### CI
- **images:** Publish managed-database images to GHCR and gate releases on them
### Fixed
- **images:** Never rebuild a published database tag on a failed lookup or missing alias
- **images:** Serialize every database-image publisher in one concurrency group |
|
…p or missing alias A GHCR lookup that failed (rate limit, outage, network) read as "missing", so a release would rebuild and push over a tag that was already published. Lookups are now retried and then abort the plan; only an explicit absent/denied answer counts as missing. An image published under some of its tags but not all (a new alias) was rebuilt in full, replacing the tags already there. The missing tags are now pointed at the existing digest by a retag job instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: David Viejo <dviejokfs@temps.sh>
…ncy group Releases and scheduled runs were keyed on github.ref, so they got different concurrency groups and could overlap. A release's alias copy, planned from the old image, could then replace tags a scheduled build had just published. All runs that can publish now share one group; pull requests and dry runs still only supersede themselves. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: David Viejo <dviejokfs@temps.sh>
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
The managed-database images (
postgres-walg,pgvector-walg,timescaledb-walg,postgres-ha,redis-walg,mongodb-walg) were pushed to Docker Hub by hand. No workflow builds them and nothing records what was published. As a result, tags the runtime references are missing:ALLOWED_POSTGRES_DOCKER_IMAGESallowsgotempsh/postgres-walg:15-bookwormand:16-bookworm, but neither exists on Docker Hub.This PR publishes all of them to GHCR on a schedule and makes releases fail if any required tag can't be pulled.
database-images.yml(new)What gets built is decided by
.github/scripts/database_image_matrix.py, which has unit tests.postgres-walg:18-bookworm,pgvector-walg:pg18,mongodb-walg:8.0postgres-walg:18.3-bookworm,postgres-ha:18.3-bookwormdocker.io/library/postgres. The newest is rebuilt every run; older ones only when missing or when their build context changesmainthat touch an image, andworkflow_dispatch(rebuild_allalso rebuilds frozen minors). Pull requests build and verify only the images they touch and publish nothing.wal-g --versionmust run, and PostgreSQL images must report exactly the version on their tag. This catches a dependency install quietly upgrading the server to a different minor.mariadb-walg-image.yml.git diffagainst the base commit rather than the GitHub API, so the release can call this workflow without grantingpull-requests: read.Release gate
release.ymlgets adatabase-imagesjob (it needsvalidate-release-refandrequire-tests, andcreate-releaseneeds it) that calls the workflow withensure: true:retagjob points the missing tags at the existing digest withdocker buildx imagetools create, so the existing signature and attestations still apply.test-nightly-release-workflows.shnow asserts the gate is in place and adds the new job to its permissions allowlist.postgres-hapostgresql-${PG_VERSION}-auto-failoverpackage name broke for minor builds (PG_VERSION=18.3). It now usesPG_MAJORfrom the upstream image's environment.{major}-bookworm-walg, the tagDEFAULT_CLUSTER_IMAGErefers to. Every build includes WAL-G now, so the alias points at the same image.Scope and load
This is CI only. No runtime code or image references change, and the runtime defaults still point at Docker Hub
gotempsh/*. The first run onmainpublishes 47 tags (about 47 matrix jobs, at most 12 at a time). After that, a scheduled run is about 15 jobs (floating tags plus the newest minor of each major).Test plan
python3 -m unittest test_database_image_matrix: 36 tests covering minor discovery (numeric sort, the missing upstream 18.5, unsupported majors), forced and missing-only plans, aliases and retags, GHCR lookups (absent, denied, rate-limited, unreachable, retried), the anonymous check, CLI validation, and that every tag the runtime references is in the catalog.github/scripts/test-nightly-release-workflows.shpasses. Withdatabase-imagesremoved fromcreate-release.needs, it fails as expecteddatabase-images.ymlandrelease.yml18.5-bookwormupstream);--checkpasses for a public GHCR tag and fails for an unpublished onedocker build --build-arg PG_VERSION=18.3 images/postgres-ha:postgres (PostgreSQL) 18.3, wal-g v3.0.8, pg_autoctl 2.2scripts/source_attribution.py checkpassesAfter merge
mainruns the workflow and publishes every tag.postgres-walg,postgres-ha,pgvector-walg,timescaledb-walg,redis-walg,mongodb-walg. Until then, the end-of-run check fails on both scheduled runs and releases. That's intended, because private packages also break fresh installs.Follow-ups (not in this PR)
gotempsh/*toghcr.io/gotempsh/*. This needs its own review, because changing an image reference can recreate existing containers.ghcr.io/gotempsh/mariadb-walg:11.4. That tag doesn't exist (the image only has commit-suffixed tags), andvalidate_immutable_mariadb_imagerejects plain tags anyway. The recommendation should be a digest-pinned reference.rustfs/rustfs:1.0.0,mariadb:lts,mongo:7.0,busybox,alpine,python:3.13-slim,aquasec/trivy, the OpenTelemetry collector) still come straight from Docker Hub. MinIO has already withdrawnquay.io/minio/minio:RELEASE.2025-09-07T16-13-09Z(LEGACY_MINIO_IMAGE), which now returns 401 on both quay.io and Docker Hub, so older MinIO services can't re-pull their image. Proposal: copy these images byte-for-byte intoghcr.io/gotempsh/mirror/…and cover them with the same release gate.🤖 Generated with Claude Code