ci: bypass buildx --push auth via per-platform --load + docker push + manifest

buildx build --push has failed 401 on every attempt. The buildkit auth
forwarding (whether via docker-container or docker driver) does not work
reliably on this builder.

New strategy: build each platform separately with --load (into local
docker, which can read /root/.docker/config.json), then push with
native docker push, then assemble a multi-arch manifest with
docker manifest create/push.

Per-platform tags are pushed as :<BUILD_ID>-amd64 / :<BUILD_ID>-arm64
and the manifest combines them under the canonical :<BUILD_ID> and :latest.

This replaces a single buildx --push call with:
  1. buildx build --platform linux/amd64 --load
  2. docker push (amd64)
  3. docker rmi  (free disk)
  4. buildx build --platform linux/arm64 --load
  5. docker push (arm64)
  6. docker rmi  (free disk)
  7. docker manifest create + push (multi-arch)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-02 20:24:27 +08:00
co-authored by Claude Opus 4.8
parent 75b07bf10e
commit 761041a70e
Vendored
+84 -29
View File
@@ -90,17 +90,6 @@ pipeline {
# Verify emulation works before proceeding
sudo docker run --rm --platform linux/arm64 docker.m.daocloud.io/library/alpine:latest uname -m
# Use the default docker driver so registry auth is shared with the
# host daemon (the docker-container driver requires manual session
# forwarding which has been unreliable on this builder).
if ! sudo docker buildx inspect --builder ${BUILDER_NAME} >/dev/null 2>&1; then
sudo docker buildx create \
--name ${BUILDER_NAME} \
--driver docker \
--use
fi
sudo docker buildx inspect --builder ${BUILDER_NAME} --bootstrap >/dev/null
"""
}
}
@@ -109,6 +98,7 @@ pipeline {
steps {
sh """
set -e
run_with_heartbeat() {
log_file="\$1"
build_label="\$2"
@@ -144,17 +134,26 @@ pipeline {
fi
return "\$cmd_status"
}
sudo docker buildx inspect --builder ${BUILDER_NAME} --bootstrap >/dev/null
echo 'Building and pushing multi-arch API image: ${API_IMAGE_TAGGED}'
run_with_heartbeat /tmp/live-recorder-api-buildx-${IMAGE_TAG}.log "API multi-arch build" \
# ── Build each platform separately, push with docker CLI,
# then assemble a multi-arch manifest.
# buildx --push does not forward auth reliably on this
# builder; per-platform --load + docker push + manifest
# bypasses that entirely.
for PLATFORM in linux/amd64 linux/arm64; do
ARCH_TAG="\${PLATFORM##*/}" # amd64 / arm64
PLAT_REF="${API_IMAGE_TAGGED}-\${ARCH_TAG}"
PLAT_LATEST="${API_IMAGE_LATEST}-\${ARCH_TAG}"
echo ''
echo "=== Building API for \$PLATFORM -> \$PLAT_REF ==="
run_with_heartbeat /tmp/live-recorder-api-\${ARCH_TAG}.log "API \${ARCH_TAG} build" \
sudo docker buildx build \
--builder ${BUILDER_NAME} \
--platform ${TARGET_PLATFORMS} \
--platform "\$PLATFORM" \
--network host \
--progress=plain \
--provenance=false \
--cache-from type=registry,ref=${API_CACHE_IMAGE} \
--cache-to type=registry,ref=${API_CACHE_IMAGE},mode=max \
--build-arg HTTP_PROXY=${HTTP_PROXY_URL} \
--build-arg HTTPS_PROXY=${HTTP_PROXY_URL} \
--build-arg NO_PROXY=${NO_PROXY_HOSTS} \
@@ -162,10 +161,37 @@ pipeline {
--build-arg https_proxy=${HTTP_PROXY_URL} \
--build-arg no_proxy=${NO_PROXY_HOSTS} \
-f src/LiveRecorder.WebApi/Dockerfile \
-t ${API_IMAGE_TAGGED} \
-t ${API_IMAGE_LATEST} \
--push \
-t "\$PLAT_REF" \
-t "\$PLAT_LATEST" \
--load \
.
echo "=== Pushing \$PLAT_REF ==="
sudo docker push "\$PLAT_REF" 2>&1 | tail -5
sudo docker push "\$PLAT_LATEST" 2>&1 | tail -5
# Free disk space before the next platform build
sudo docker rmi "\$PLAT_REF" "\$PLAT_LATEST" 2>/dev/null || true
done
echo ''
echo "=== Creating multi-arch manifest: ${API_IMAGE_TAGGED} ==="
sudo docker manifest create "${API_IMAGE_TAGGED}" \
"${API_IMAGE_TAGGED}-amd64" \
"${API_IMAGE_TAGGED}-arm64"
sudo docker manifest create "${API_IMAGE_LATEST}" \
"${API_IMAGE_LATEST}-amd64" \
"${API_IMAGE_LATEST}-arm64"
echo "=== Pushing manifests ==="
sudo docker manifest push "${API_IMAGE_TAGGED}" 2>&1 | tail -3
sudo docker manifest push "${API_IMAGE_LATEST}" 2>&1 | tail -3
# (Optionally clean up per-platform tags from registry, but harmless to leave them)
echo ''
echo "API multi-arch images pushed successfully:"
echo " ${API_IMAGE_TAGGED}"
echo " ${API_IMAGE_LATEST}"
"""
}
}
@@ -174,6 +200,7 @@ pipeline {
steps {
sh """
set -e
run_with_heartbeat() {
log_file="\$1"
build_label="\$2"
@@ -209,17 +236,21 @@ pipeline {
fi
return "\$cmd_status"
}
sudo docker buildx inspect --builder ${BUILDER_NAME} --bootstrap >/dev/null
echo 'Building and pushing multi-arch Web image: ${WEB_IMAGE_TAGGED}'
run_with_heartbeat /tmp/live-recorder-web-buildx-${IMAGE_TAG}.log "Web multi-arch build" \
for PLATFORM in linux/amd64 linux/arm64; do
ARCH_TAG="\${PLATFORM##*/}"
PLAT_REF="${WEB_IMAGE_TAGGED}-\${ARCH_TAG}"
PLAT_LATEST="${WEB_IMAGE_LATEST}-\${ARCH_TAG}"
echo ''
echo "=== Building Web for \$PLATFORM -> \$PLAT_REF ==="
run_with_heartbeat /tmp/live-recorder-web-\${ARCH_TAG}.log "Web \${ARCH_TAG} build" \
sudo docker buildx build \
--builder ${BUILDER_NAME} \
--platform ${TARGET_PLATFORMS} \
--platform "\$PLATFORM" \
--network host \
--progress=plain \
--provenance=false \
--cache-from type=registry,ref=${WEB_CACHE_IMAGE} \
--cache-to type=registry,ref=${WEB_CACHE_IMAGE},mode=max \
--build-arg NODE_IMAGE=${WEB_NODE_IMAGE} \
--build-arg NGINX_IMAGE=${WEB_NGINX_IMAGE} \
--build-arg HTTP_PROXY=${HTTP_PROXY_URL} \
@@ -230,10 +261,34 @@ pipeline {
--build-arg no_proxy=${NO_PROXY_HOSTS} \
-f frontend/Dockerfile \
--build-arg VITE_API_BASE_URL=/api \
-t ${WEB_IMAGE_TAGGED} \
-t ${WEB_IMAGE_LATEST} \
--push \
-t "\$PLAT_REF" \
-t "\$PLAT_LATEST" \
--load \
frontend
echo "=== Pushing \$PLAT_REF ==="
sudo docker push "\$PLAT_REF" 2>&1 | tail -3
sudo docker push "\$PLAT_LATEST" 2>&1 | tail -3
sudo docker rmi "\$PLAT_REF" "\$PLAT_LATEST" 2>/dev/null || true
done
echo ''
echo "=== Creating multi-arch manifest: ${WEB_IMAGE_TAGGED} ==="
sudo docker manifest create "${WEB_IMAGE_TAGGED}" \
"${WEB_IMAGE_TAGGED}-amd64" \
"${WEB_IMAGE_TAGGED}-arm64"
sudo docker manifest create "${WEB_IMAGE_LATEST}" \
"${WEB_IMAGE_LATEST}-amd64" \
"${WEB_IMAGE_LATEST}-arm64"
echo "=== Pushing manifests ==="
sudo docker manifest push "${WEB_IMAGE_TAGGED}" 2>&1 | tail -3
sudo docker manifest push "${WEB_IMAGE_LATEST}" 2>&1 | tail -3
echo ''
echo "Web multi-arch images pushed successfully:"
echo " ${WEB_IMAGE_TAGGED}"
echo " ${WEB_IMAGE_LATEST}"
"""
}
}