diff --git a/Jenkinsfile b/Jenkinsfile index 8340c84..f2a7526 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -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,28 +134,64 @@ 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" \ - sudo docker buildx build \ - --builder ${BUILDER_NAME} \ - --platform ${TARGET_PLATFORMS} \ - --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} \ - --build-arg http_proxy=${HTTP_PROXY_URL} \ - --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 \ - . + + # ── 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 \ + --platform "\$PLATFORM" \ + --network host \ + --progress=plain \ + --provenance=false \ + --cache-from type=registry,ref=${API_CACHE_IMAGE} \ + --build-arg HTTP_PROXY=${HTTP_PROXY_URL} \ + --build-arg HTTPS_PROXY=${HTTP_PROXY_URL} \ + --build-arg NO_PROXY=${NO_PROXY_HOSTS} \ + --build-arg http_proxy=${HTTP_PROXY_URL} \ + --build-arg https_proxy=${HTTP_PROXY_URL} \ + --build-arg no_proxy=${NO_PROXY_HOSTS} \ + -f src/LiveRecorder.WebApi/Dockerfile \ + -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,31 +236,59 @@ 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" \ - sudo docker buildx build \ - --builder ${BUILDER_NAME} \ - --platform ${TARGET_PLATFORMS} \ - --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} \ - --build-arg HTTPS_PROXY=${HTTP_PROXY_URL} \ - --build-arg NO_PROXY=${NO_PROXY_HOSTS} \ - --build-arg http_proxy=${HTTP_PROXY_URL} \ - --build-arg https_proxy=${HTTP_PROXY_URL} \ - --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 \ - frontend + + 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 \ + --platform "\$PLATFORM" \ + --network host \ + --progress=plain \ + --provenance=false \ + --cache-from type=registry,ref=${WEB_CACHE_IMAGE} \ + --build-arg NODE_IMAGE=${WEB_NODE_IMAGE} \ + --build-arg NGINX_IMAGE=${WEB_NGINX_IMAGE} \ + --build-arg HTTP_PROXY=${HTTP_PROXY_URL} \ + --build-arg HTTPS_PROXY=${HTTP_PROXY_URL} \ + --build-arg NO_PROXY=${NO_PROXY_HOSTS} \ + --build-arg http_proxy=${HTTP_PROXY_URL} \ + --build-arg https_proxy=${HTTP_PROXY_URL} \ + --build-arg no_proxy=${NO_PROXY_HOSTS} \ + -f frontend/Dockerfile \ + --build-arg VITE_API_BASE_URL=/api \ + -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}" """ } }