docker-publish: use BuildKit (buildx) instead of legacy builder
The runners share one host Docker daemon across replicas; the legacy builder corrupts layers under that concurrency. buildx builds in an isolated buildkitd container. buildx is installed as a static binary, keeping the no-marketplace-actions property. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8b0ef6d709
commit
f2a58b2fb3
1 changed files with 45 additions and 12 deletions
|
|
@ -1,9 +1,15 @@
|
||||||
name: Build & publish Docker image
|
name: Build & publish Docker image
|
||||||
description: >-
|
description: >-
|
||||||
Build a Docker image and push it to this Forgejo instance's container
|
Build a Docker image with BuildKit (buildx) and push it to this Forgejo
|
||||||
registry. Reimplements docker/login-action + docker/metadata-action +
|
instance's container registry. Reimplements docker/login-action +
|
||||||
docker/build-push-action in plain shell using the docker CLI — no
|
docker/metadata-action + docker/setup-buildx-action + docker/build-push-action
|
||||||
marketplace actions are fetched or run.
|
in plain shell using the docker CLI and a statically-installed buildx plugin —
|
||||||
|
no marketplace actions are fetched or run.
|
||||||
|
|
||||||
|
BuildKit (not the legacy builder) is required: the runners share one host
|
||||||
|
Docker daemon across replicas, and the legacy builder corrupts layers under
|
||||||
|
that concurrency ("failed to get layer ... layer does not exist"). buildx
|
||||||
|
builds in an isolated buildkitd container, which is robust against it.
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
context:
|
context:
|
||||||
|
|
@ -61,6 +67,30 @@ runs:
|
||||||
fi
|
fi
|
||||||
docker --version
|
docker --version
|
||||||
|
|
||||||
|
# --- Ensure the buildx plugin exists (static binary, not a marketplace action) ---
|
||||||
|
if ! docker buildx version >/dev/null 2>&1; then
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64) BX_ARCH=amd64 ;;
|
||||||
|
aarch64|arm64) BX_ARCH=arm64 ;;
|
||||||
|
*) BX_ARCH="$(uname -m)" ;;
|
||||||
|
esac
|
||||||
|
mkdir -p /usr/local/lib/docker/cli-plugins
|
||||||
|
curl -fsSL --retry 3 --retry-connrefused \
|
||||||
|
"https://github.com/docker/buildx/releases/download/v0.19.3/buildx-v0.19.3.linux-${BX_ARCH}" \
|
||||||
|
-o /usr/local/lib/docker/cli-plugins/docker-buildx
|
||||||
|
chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx
|
||||||
|
fi
|
||||||
|
docker buildx version
|
||||||
|
|
||||||
|
# A host-networked buildkit builder so it can reach the registry on 127.0.0.1
|
||||||
|
# (buildkit treats loopback registries as insecure/HTTP automatically). A fixed
|
||||||
|
# name lets concurrent jobs share one builder and its cache; the inspect||create
|
||||||
|
# guard tolerates the create race between simultaneous jobs.
|
||||||
|
docker buildx inspect ci >/dev/null 2>&1 \
|
||||||
|
|| docker buildx create --name ci --driver docker-container --driver-opt network=host >/dev/null 2>&1 \
|
||||||
|
|| true
|
||||||
|
docker buildx use ci
|
||||||
|
|
||||||
# --- Resolve the registry host (canonical form of the block copy-pasted across repos) ---
|
# --- Resolve the registry host (canonical form of the block copy-pasted across repos) ---
|
||||||
host="${INPUT_REGISTRY_HOST:-${CONTAINER_REGISTRY_HOST:-$SERVER_URL}}"
|
host="${INPUT_REGISTRY_HOST:-${CONTAINER_REGISTRY_HOST:-$SERVER_URL}}"
|
||||||
host="${host#https://}"; host="${host#http://}"; host="${host%/}"
|
host="${host#https://}"; host="${host#http://}"; host="${host%/}"
|
||||||
|
|
@ -91,16 +121,19 @@ runs:
|
||||||
[ -n "$a" ] && extra+=( --build-arg "$a" )
|
[ -n "$a" ] && extra+=( --build-arg "$a" )
|
||||||
done <<< "${INPUT_BUILD_ARGS}"
|
done <<< "${INPUT_BUILD_ARGS}"
|
||||||
|
|
||||||
# --- Build ---
|
# --- Log in before building so buildx can push directly (skipped on PRs) ---
|
||||||
docker build "${extra[@]}" \
|
if [ "${INPUT_PUSH}" = "true" ]; then
|
||||||
|
printf '%s' "${INPUT_TOKEN}" | docker login "$host" -u "$OWNER" --password-stdin
|
||||||
|
output=( --push )
|
||||||
|
else
|
||||||
|
# Pull-request builds validate the Dockerfile without producing/pushing an image.
|
||||||
|
output=()
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Build (and push when requested) with BuildKit ---
|
||||||
|
docker buildx build "${extra[@]}" "${output[@]}" \
|
||||||
--label "org.opencontainers.image.source=${SERVER_URL}/${REPO}" \
|
--label "org.opencontainers.image.source=${SERVER_URL}/${REPO}" \
|
||||||
--label "org.opencontainers.image.revision=${SHA}" \
|
--label "org.opencontainers.image.revision=${SHA}" \
|
||||||
--label "org.opencontainers.image.created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
|
--label "org.opencontainers.image.created=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
|
||||||
"${tags[@]}" \
|
"${tags[@]}" \
|
||||||
"${INPUT_CONTEXT}"
|
"${INPUT_CONTEXT}"
|
||||||
|
|
||||||
# --- Push (skipped on pull requests by passing push: false) ---
|
|
||||||
if [ "${INPUT_PUSH}" = "true" ]; then
|
|
||||||
printf '%s' "${INPUT_TOKEN}" | docker login "$host" -u "$OWNER" --password-stdin
|
|
||||||
docker push --all-tags "$image"
|
|
||||||
fi
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue