Repository navigation
Mirror the MinIO CI image to GHCR #3766
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| name: Build MinIO Mirror | ||
|
|
||
| # Publishes ghcr.io/thepalaceproject/palace-ci-minio, the MinIO image used by the test suites of | ||
| # circulation, library-registry and virtual-library-card. MinIO withdrew anonymous public access | ||
| # to its own image (Docker Hub, then quay.io), so we host a copy built from its official GitHub | ||
| # release binaries. See docker/Dockerfile.minio.mirror for the full rationale. | ||
| # | ||
| # The image is pinned to a single upstream release and its content is fully determined by the | ||
| # checksums in that Dockerfile, so there is no scheduled rebuild: running this again produces the | ||
| # same image. It runs only when the Dockerfile or this workflow changes, or on demand. | ||
| # | ||
| # One-time manual step: GHCR packages are created private. After the first successful run, set the | ||
| # package visibility to public (Org -> Packages -> palace-ci-minio -> Package settings), matching | ||
| # the other Palace images. Without that, every developer and CI job would need a docker login. | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| paths: | ||
| - .github/workflows/build-minio-mirror.yml | ||
| - docker/Dockerfile.minio.mirror | ||
| # Build (but do not push) on PRs that touch the mirror, so a broken Dockerfile or workflow is | ||
| # caught in review rather than on main, where the failure would leave the image unpublished. | ||
| pull_request: | ||
| paths: | ||
| - .github/workflows/build-minio-mirror.yml | ||
| - docker/Dockerfile.minio.mirror | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: build-minio-mirror-${{ github.ref_name }}-${{ github.event_name }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| build: | ||
| name: Build MinIO Mirror | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 30 | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v7 | ||
| with: | ||
| persist-credentials: false | ||
|
|
||
| # See comment here: https://github.com/actions/runner-images/issues/1187#issuecomment-686735760 | ||
| - name: Disable network offload | ||
| run: sudo ethtool -K eth0 tx off rx off | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v4 | ||
|
|
||
| - name: Login to GitHub Container Registry | ||
| if: github.event_name != 'pull_request' | ||
| uses: docker/login-action@v4.6.0 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.repository_owner }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| # The Dockerfile is the single source of truth for which upstream release we mirror, so the | ||
| # tag is read back out of it rather than duplicated here where the two could drift apart. | ||
| - name: Determine image and tag | ||
| id: image | ||
| run: | | ||
| set -euo pipefail | ||
| image="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/palace-ci-minio" | ||
| tag=$(sed -n 's/^ARG MINIO_RELEASE=\(.*\)$/\1/p' docker/Dockerfile.minio.mirror | head -1) | ||
| if [[ -z "$tag" ]]; then | ||
| echo "::error::Could not read MINIO_RELEASE from docker/Dockerfile.minio.mirror" | ||
| exit 1 | ||
| fi | ||
| echo "Publishing $image:$tag" | ||
| echo "image=$image" >> "$GITHUB_OUTPUT" | ||
| echo "tag=$tag" >> "$GITHUB_OUTPUT" | ||
|
|
||
| # The mirror contains no RUN instructions, so both architectures cross-build on this single | ||
| # amd64 runner with no QEMU emulation and no per-arch runner matrix. | ||
| - name: Build mirror image | ||
| uses: docker/build-push-action@v7 | ||
| with: | ||
| context: . | ||
| file: ./docker/Dockerfile.minio.mirror | ||
| target: minio | ||
| platforms: linux/amd64,linux/arm64 | ||
| # On a pull request this builds both architectures and verifies the pinned checksums, | ||
| # then throws the result away. Only main and manual runs publish. | ||
| push: ${{ github.event_name != 'pull_request' }} | ||
| # Deliberately no `latest` tag: consumers pin this exact release. Following a moving | ||
| # upstream tag is part of how we ended up needing this mirror. | ||
| tags: ${{ steps.image.outputs.image }}:${{ steps.image.outputs.tag }} | ||
|
|
||
| - name: Verify published image | ||
| if: github.event_name != 'pull_request' | ||
| run: | | ||
| set -euo pipefail | ||
| ref="${{ steps.image.outputs.image }}:${{ steps.image.outputs.tag }}" | ||
| docker buildx imagetools inspect "$ref" | ||
| # Confirm both architectures actually made it into the published manifest list. | ||
| platforms=$(docker buildx imagetools inspect "$ref" --raw \ | ||
| | jq -r '.manifests[] | select(.platform.os != "unknown") | "\(.platform.os)/\(.platform.architecture)"') | ||
| echo "Published platforms: $platforms" | ||
| for platform in linux/amd64 linux/arm64; do | ||
| grep -qx "$platform" <<< "$platforms" \ | ||
| || { echo "::error::$platform missing from $ref"; exit 1; } | ||
| done | ||
| # Smoke-test the runner's native architecture. | ||
| docker run --rm --entrypoint /usr/bin/minio "$ref" --version | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| # syntax=docker/dockerfile:1.7 | ||
| # | ||
| # Mirror of the upstream MinIO server image, published as | ||
| # ghcr.io/thepalaceproject/palace-ci-minio. | ||
| # | ||
| # Why this exists | ||
| # --------------- | ||
| # MinIO withdrew anonymous public access to its server image: first from Docker Hub | ||
| # (~13 Sept 2026), then from quay.io (~24 Sept 2026). Both registries now answer 401 to | ||
| # anonymous manifest requests for every tag, and the binary download host (dl.min.io) answers | ||
| # 410. Every Palace repo that ran `FROM <registry>/minio/minio` in its test setup therefore | ||
| # fails before its test suite starts. Pinning an older tag or relying on a local Docker cache | ||
| # does not help: the whole repository is gated, and tox-docker passes `pull=True` on every | ||
| # build, forcing a fresh pull each time. | ||
| # | ||
| # The one channel MinIO still serves anonymously is GitHub release assets, so this image is | ||
| # assembled from the official release binaries rather than pulled and re-tagged. The binaries | ||
| # below are byte-for-byte identical to the ones inside the last upstream image CI used | ||
| # (quay.io/minio/minio:latest, labelled RELEASE.2025-09-07T16-13-09Z) — verified by comparing | ||
| # their sha256 against /usr/bin/minio and /usr/bin/mc extracted from that image. | ||
| # | ||
| # Scope | ||
| # ----- | ||
| # This is a bare passthrough. It contains no Palace configuration: no credentials, no buckets, | ||
| # no entrypoint script. The repos that consume it (circulation, library-registry, | ||
| # virtual-library-card) each configure MinIO differently and keep doing so in their own | ||
| # Dockerfiles — they change only their `FROM` line. Baking configuration in here would fork | ||
| # the image between repos immediately. | ||
| # | ||
| # This mirror is a bridge, not a destination; see the retirement ticket for replacing MinIO | ||
| # outright. Do not add features to it. | ||
| # | ||
| # Updating | ||
| # -------- | ||
| # The release strings and their checksums are a matched set. If you bump a version you MUST | ||
| # also replace the matching `--checksum=` value, or the build will fail (by design). | ||
| # Checksums come from the `.sha256sum` asset published alongside each binary. | ||
|
|
||
| ARG BASE_IMAGE=registry.access.redhat.com/ubi9/ubi-minimal:9.6 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The workflow says rebuilding produces the same image, but |
||
|
|
||
| # MinIO publishes one binary per platform rather than a multi-arch artifact, and each has its | ||
| # own checksum, so the download is split into a per-architecture stage that `fetch` selects | ||
| # from using TARGETARCH. This keeps checksum verification native to BuildKit's ADD. | ||
| FROM ${BASE_IMAGE} AS fetch-amd64 | ||
| ARG MINIO_RELEASE=RELEASE.2025-09-07T16-13-09Z | ||
| ARG MC_RELEASE=RELEASE.2025-08-13T08-35-41Z | ||
| ADD --chmod=755 --checksum=sha256:7c5bd8512c6e966455b1d198209358b2d191c77a83ab377c4073281065fb855f \ | ||
| https://github.com/minio/minio/releases/download/${MINIO_RELEASE}/minio.linux-amd64.${MINIO_RELEASE} \ | ||
| /staging/minio | ||
| ADD --chmod=755 --checksum=sha256:01f866e9c5f9b87c2b09116fa5d7c06695b106242d829a8bb32990c00312e891 \ | ||
| https://github.com/minio/mc/releases/download/${MC_RELEASE}/mc.linux-amd64.${MC_RELEASE} \ | ||
| /staging/mc | ||
|
|
||
| FROM ${BASE_IMAGE} AS fetch-arm64 | ||
| ARG MINIO_RELEASE=RELEASE.2025-09-07T16-13-09Z | ||
| ARG MC_RELEASE=RELEASE.2025-08-13T08-35-41Z | ||
| ADD --chmod=755 --checksum=sha256:5c83cd2cf151717ba0243f73e1c7802ff36e272b67144bdd7f1f7d684fd6f03d \ | ||
| https://github.com/minio/minio/releases/download/${MINIO_RELEASE}/minio.linux-arm64.${MINIO_RELEASE} \ | ||
| /staging/minio | ||
| ADD --chmod=755 --checksum=sha256:14c8c9616cfce4636add161304353244e8de383b2e2752c0e9dad01d4c27c12c \ | ||
| https://github.com/minio/mc/releases/download/${MC_RELEASE}/mc.linux-arm64.${MC_RELEASE} \ | ||
| /staging/mc | ||
|
|
||
| FROM fetch-${TARGETARCH} AS fetch | ||
|
|
||
| FROM ${BASE_IMAGE} AS minio | ||
| ARG MINIO_RELEASE=RELEASE.2025-09-07T16-13-09Z | ||
| ARG MC_RELEASE=RELEASE.2025-08-13T08-35-41Z | ||
|
|
||
| LABEL org.opencontainers.image.title="palace-ci-minio" \ | ||
| org.opencontainers.image.description="Unmodified MinIO server build, mirrored for Palace CI because upstream withdrew anonymous registry access." \ | ||
| org.opencontainers.image.version="${MINIO_RELEASE}" \ | ||
| org.opencontainers.image.source="https://github.com/ThePalaceProject/circulation" \ | ||
| org.opencontainers.image.vendor="The Palace Project" \ | ||
| io.palace.minio.release="${MINIO_RELEASE}" \ | ||
| io.palace.mc.release="${MC_RELEASE}" | ||
|
|
||
| COPY --from=fetch /staging/minio /usr/bin/minio | ||
| COPY --from=fetch /staging/mc /usr/bin/mc | ||
|
|
||
| # Matches the upstream image: MinIO reads credentials from these files when the corresponding | ||
| # environment variables are not set, and `mc` needs a writable config dir. | ||
| ENV MINIO_ROOT_USER_FILE=access_key \ | ||
| MINIO_ROOT_PASSWORD_FILE=secret_key \ | ||
| MINIO_KMS_SECRET_KEY_FILE=kms_master_key \ | ||
| MINIO_CONFIG_ENV_FILE=config.env \ | ||
| MC_CONFIG_DIR=/tmp/.mc | ||
|
|
||
| # Declaring the volume creates the mount point, so no RUN is needed here. Keeping this stage | ||
| # free of RUN instructions means the image cross-builds for every architecture without QEMU. | ||
| VOLUME ["/data"] | ||
| EXPOSE 9000 9001 | ||
|
|
||
| # A plain, unconfigured server. Consumers override this with their own CMD/ENTRYPOINT. | ||
| CMD ["minio", "server", "/data", "--address", ":9000", "--console-address", ":9001"] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A manual dispatch from a non-main branch still logs in and pushes. If that branch changes the Dockerfile without changing
MINIO_RELEASE, it overwrites the release tag pinned by the consumer in PR #3767. CI can then pull image contents that have not been merged. Restrict publishing to the intended branch, or give branch builds distinct tags.