mirror of
https://github.com/pgsty/minio.git
synced 2026-08-09 07:43:29 +03:00
ci: publish container images from a published release, on demand
The release workflow built and pushed the container images in the same run that created the draft, so pgsty/minio:latest moved to a build nobody had signed or published yet. Abandoning that draft left latest pointing at it with no way to notice, and the images were the one artifact of a release that escaped the draft gate entirely. Image publishing moves to its own dispatch-triggered workflow that takes a tag and refuses to touch anything that is not a published, non-prerelease release, and that is not the latest one - since it moves the latest image tag, running it for an older release would silently roll users back. It builds from the archives attached to that release, checked against the published checksums, rather than rebuilding from source: the image then contains the same binary the tarball does, by construction rather than by assumption. GoReleaser loses its dockers and docker_manifests sections along with the QEMU, buildx and registry-login steps that only existed to serve them, and the release job drops packages: write, which was granted for a GHCR push that never happened. Releasing now has one more manual step. That is the point: tagging no longer moves docker latest, so the tag can be cut, inspected, signed and published before anything reaches users who pull by tag. Co-authored-by: ChatGPT <noreply@openai.com> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -28,59 +28,6 @@ archives:
|
|||||||
- minio
|
- minio
|
||||||
name_template: "minio_{{ .Env.PKG_VERSION }}_{{ .Os }}_{{ .Arch }}"
|
name_template: "minio_{{ .Env.PKG_VERSION }}_{{ .Os }}_{{ .Arch }}"
|
||||||
|
|
||||||
dockers:
|
|
||||||
- id: minio-amd64
|
|
||||||
ids:
|
|
||||||
- minio
|
|
||||||
goos: linux
|
|
||||||
goarch: amd64
|
|
||||||
dockerfile: Dockerfile.goreleaser
|
|
||||||
use: buildx
|
|
||||||
image_templates:
|
|
||||||
- "pgsty/minio:{{ .Tag }}-amd64"
|
|
||||||
- "pgsty/minio:latest-amd64"
|
|
||||||
build_flag_templates:
|
|
||||||
- "--platform=linux/amd64"
|
|
||||||
- "--label=org.opencontainers.image.version={{ .Tag }}"
|
|
||||||
- "--label=org.opencontainers.image.created={{ .Date }}"
|
|
||||||
- "--label=org.opencontainers.image.revision={{ .FullCommit }}"
|
|
||||||
extra_files:
|
|
||||||
- dockerscripts/docker-entrypoint.sh
|
|
||||||
- dockerscripts/download-static-curl.sh
|
|
||||||
- LICENSE
|
|
||||||
- CREDITS
|
|
||||||
|
|
||||||
- id: minio-arm64
|
|
||||||
ids:
|
|
||||||
- minio
|
|
||||||
goos: linux
|
|
||||||
goarch: arm64
|
|
||||||
dockerfile: Dockerfile.goreleaser
|
|
||||||
use: buildx
|
|
||||||
image_templates:
|
|
||||||
- "pgsty/minio:{{ .Tag }}-arm64"
|
|
||||||
- "pgsty/minio:latest-arm64"
|
|
||||||
build_flag_templates:
|
|
||||||
- "--platform=linux/arm64"
|
|
||||||
- "--label=org.opencontainers.image.version={{ .Tag }}"
|
|
||||||
- "--label=org.opencontainers.image.created={{ .Date }}"
|
|
||||||
- "--label=org.opencontainers.image.revision={{ .FullCommit }}"
|
|
||||||
extra_files:
|
|
||||||
- dockerscripts/docker-entrypoint.sh
|
|
||||||
- dockerscripts/download-static-curl.sh
|
|
||||||
- LICENSE
|
|
||||||
- CREDITS
|
|
||||||
|
|
||||||
docker_manifests:
|
|
||||||
- name_template: "pgsty/minio:{{ .Tag }}"
|
|
||||||
image_templates:
|
|
||||||
- "pgsty/minio:{{ .Tag }}-amd64"
|
|
||||||
- "pgsty/minio:{{ .Tag }}-arm64"
|
|
||||||
- name_template: "pgsty/minio:latest"
|
|
||||||
image_templates:
|
|
||||||
- "pgsty/minio:latest-amd64"
|
|
||||||
- "pgsty/minio:latest-arm64"
|
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: "minio_{{ .Env.PKG_VERSION }}_checksums.txt"
|
name_template: "minio_{{ .Env.PKG_VERSION }}_checksums.txt"
|
||||||
algorithm: sha256
|
algorithm: sha256
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
name: Publish Docker Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "Published RELEASE.* tag to package as pgsty/minio"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: docker-release
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Images are built from a published release rather than from the build
|
||||||
|
# that produced it, so an abandoned draft can never leave :latest
|
||||||
|
# pointing at something nobody shipped.
|
||||||
|
- name: Validate published release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
INPUT_TAG: ${{ inputs.tag }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
TAG="${INPUT_TAG}"
|
||||||
|
VERSION_HYPHEN="${TAG#RELEASE.}"
|
||||||
|
PKG_VERSION="$(echo "${VERSION_HYPHEN}" | sed -E 's/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2})-([0-9]{2})-([0-9]{2})Z$/\1\2\3\4\5\6.0.0/')"
|
||||||
|
if [ "${PKG_VERSION}" = "${VERSION_HYPHEN}" ]; then
|
||||||
|
echo "Invalid release tag: ${TAG}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IS_DRAFT="$(gh release view "${TAG}" --repo "${GITHUB_REPOSITORY}" --json isDraft --jq .isDraft)"
|
||||||
|
IS_PRERELEASE="$(gh release view "${TAG}" --repo "${GITHUB_REPOSITORY}" --json isPrerelease --jq .isPrerelease)"
|
||||||
|
PUBLISHED_AT="$(gh release view "${TAG}" --repo "${GITHUB_REPOSITORY}" --json publishedAt --jq .publishedAt)"
|
||||||
|
LATEST_TAG="$(gh release view --repo "${GITHUB_REPOSITORY}" --json tagName --jq .tagName)"
|
||||||
|
|
||||||
|
if [ "${IS_DRAFT}" != false ] || [ "${IS_PRERELEASE}" != false ] || [ -z "${PUBLISHED_AT}" ]; then
|
||||||
|
echo "${TAG} must be a published, non-prerelease GitHub Release"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# This workflow moves :latest, so it must not run for an older tag.
|
||||||
|
if [ "${TAG}" != "${LATEST_TAG}" ]; then
|
||||||
|
echo "Refusing to replace Docker latest with non-latest release ${TAG} (latest is ${LATEST_TAG})"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "RELEASE_TAG=${TAG}"
|
||||||
|
echo "PKG_VERSION=${PKG_VERSION}"
|
||||||
|
echo "PUBLISHED_AT=${PUBLISHED_AT}"
|
||||||
|
} >> "${GITHUB_ENV}"
|
||||||
|
|
||||||
|
- name: Validate Docker Hub credentials
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if [ -z "${{ secrets.DOCKERHUB_USERNAME }}" ] || [ -z "${{ secrets.DOCKERHUB_TOKEN }}" ]; then
|
||||||
|
echo "Missing Docker Hub credentials. Set DOCKERHUB_USERNAME and DOCKERHUB_TOKEN repository secrets."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Checkout release tag
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.tag }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Prepare verified Docker contexts
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
assets_dir="docker-release/assets"
|
||||||
|
mkdir -p "${assets_dir}"
|
||||||
|
|
||||||
|
amd64_archive="minio_${PKG_VERSION}_linux_amd64.tar.gz"
|
||||||
|
arm64_archive="minio_${PKG_VERSION}_linux_arm64.tar.gz"
|
||||||
|
checksums="minio_${PKG_VERSION}_checksums.txt"
|
||||||
|
gh release download "${RELEASE_TAG}" --repo "${GITHUB_REPOSITORY}" \
|
||||||
|
--dir "${assets_dir}" \
|
||||||
|
--pattern "${amd64_archive}" \
|
||||||
|
--pattern "${arm64_archive}" \
|
||||||
|
--pattern "${checksums}"
|
||||||
|
|
||||||
|
# The binaries going into the images are the published ones, checked
|
||||||
|
# against the published checksums, not a rebuild that merely ought to
|
||||||
|
# match them.
|
||||||
|
cd "${assets_dir}"
|
||||||
|
grep -F " ${amd64_archive}" "${checksums}" | sha256sum --check
|
||||||
|
grep -F " ${arm64_archive}" "${checksums}" | sha256sum --check
|
||||||
|
cd "${GITHUB_WORKSPACE}"
|
||||||
|
|
||||||
|
# Dockerfile.goreleaser expects the binary at the context root and
|
||||||
|
# the entrypoint scripts under dockerscripts/, which is the layout
|
||||||
|
# GoReleaser used to assemble via extra_files.
|
||||||
|
for arch in amd64 arm64; do
|
||||||
|
context="docker-release/${arch}"
|
||||||
|
archive="${assets_dir}/minio_${PKG_VERSION}_linux_${arch}.tar.gz"
|
||||||
|
mkdir -p "${context}/dockerscripts"
|
||||||
|
tar -xzf "${archive}" -C "${context}" minio
|
||||||
|
cp Dockerfile.goreleaser LICENSE CREDITS "${context}/"
|
||||||
|
cp dockerscripts/docker-entrypoint.sh dockerscripts/download-static-curl.sh \
|
||||||
|
"${context}/dockerscripts/"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "RELEASE_REVISION=$(git rev-parse HEAD)" >> "${GITHUB_ENV}"
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
with:
|
||||||
|
platforms: arm64
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push amd64 image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: docker-release/amd64
|
||||||
|
file: docker-release/amd64/Dockerfile.goreleaser
|
||||||
|
platforms: linux/amd64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
pgsty/minio:${{ env.RELEASE_TAG }}-amd64
|
||||||
|
pgsty/minio:latest-amd64
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.version=${{ env.RELEASE_TAG }}
|
||||||
|
org.opencontainers.image.created=${{ env.PUBLISHED_AT }}
|
||||||
|
org.opencontainers.image.revision=${{ env.RELEASE_REVISION }}
|
||||||
|
|
||||||
|
- name: Build and push arm64 image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: docker-release/arm64
|
||||||
|
file: docker-release/arm64/Dockerfile.goreleaser
|
||||||
|
platforms: linux/arm64
|
||||||
|
push: true
|
||||||
|
tags: |
|
||||||
|
pgsty/minio:${{ env.RELEASE_TAG }}-arm64
|
||||||
|
pgsty/minio:latest-arm64
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.version=${{ env.RELEASE_TAG }}
|
||||||
|
org.opencontainers.image.created=${{ env.PUBLISHED_AT }}
|
||||||
|
org.opencontainers.image.revision=${{ env.RELEASE_REVISION }}
|
||||||
|
|
||||||
|
- name: Publish multi-architecture manifests
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag "pgsty/minio:${RELEASE_TAG}" \
|
||||||
|
"pgsty/minio:${RELEASE_TAG}-amd64" \
|
||||||
|
"pgsty/minio:${RELEASE_TAG}-arm64"
|
||||||
|
docker buildx imagetools create \
|
||||||
|
--tag "pgsty/minio:latest" \
|
||||||
|
"pgsty/minio:latest-amd64" \
|
||||||
|
"pgsty/minio:latest-arm64"
|
||||||
|
docker buildx imagetools inspect "pgsty/minio:${RELEASE_TAG}"
|
||||||
|
docker buildx imagetools inspect "pgsty/minio:latest"
|
||||||
@@ -12,7 +12,6 @@ on:
|
|||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
packages: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
@@ -61,28 +60,6 @@ jobs:
|
|||||||
echo "Package version: ${PKG_VERSION}"
|
echo "Package version: ${PKG_VERSION}"
|
||||||
echo "LDFLAGS: ${LDFLAGS}"
|
echo "LDFLAGS: ${LDFLAGS}"
|
||||||
|
|
||||||
- name: Validate Docker Hub credentials
|
|
||||||
run: |
|
|
||||||
set -euo pipefail
|
|
||||||
if [ -z "${{ secrets.DOCKERHUB_USERNAME }}" ] || [ -z "${{ secrets.DOCKERHUB_TOKEN }}" ]; then
|
|
||||||
echo "Missing Docker Hub credentials. Set DOCKERHUB_USERNAME and DOCKERHUB_TOKEN repository secrets."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Set up QEMU
|
|
||||||
uses: docker/setup-qemu-action@v3
|
|
||||||
with:
|
|
||||||
platforms: arm64
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Build Draft release with GoReleaser
|
- name: Build Draft release with GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v6
|
uses: goreleaser/goreleaser-action@v6
|
||||||
with:
|
with:
|
||||||
|
|||||||
Reference in New Issue
Block a user