From 4ed0e1b61559505ceb82604f2bd9e9abeefc8fed Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 24 Jul 2026 15:45:15 +0200 Subject: [PATCH] fix: block single-arch images from reaching production A hand-pushed evcc/optimizer:latest carrying only a linux/arm64 manifest took production down: Container Apps nodes are amd64, found no matching manifest, and every replica looped in ImagePullBackOff. Deploy now inspects the tag before touching Azure and fails with an explicit error when linux/amd64 is missing. The index template covers multi-platform tags; single-platform tags publish a bare manifest, for which that template fails and the fallback reads the config blob. docker-build builds linux/amd64,linux/arm64. Buildx cannot load a manifest list into the local image store, so it pushes directly and the separate docker-push target is gone. Local iteration moves to docker-build-local, which is host-arch and never pushes; the default target uses it, so a bare make no longer publishes anything. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/deploy.yml | 18 ++++++++++++++++++ Makefile | 19 ++++++++++++------- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3c98f99bf..0a5c681ae 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -20,6 +20,24 @@ jobs: steps: - uses: actions/checkout@v6 + - name: Verify image provides linux/amd64 + run: | + image="${{ env.IMAGE }}:${{ inputs.image_tag || 'latest' }}" + # multi-platform tags publish an index; single-platform tags publish a + # bare manifest, for which the index template fails and we fall back + platforms=$(docker buildx imagetools inspect "$image" \ + --format '{{range .Manifest.Manifests}}{{.Platform.OS}}/{{.Platform.Architecture}} {{end}}' 2>/dev/null) \ + || platforms=$(docker buildx imagetools inspect "$image" \ + --format '{{.Image.OS}}/{{.Image.Architecture}}') + echo "$image provides: $platforms" + case " $platforms " in + *" linux/amd64 "*) ;; + *) + echo "::error::$image has no linux/amd64 manifest. Container Apps nodes are amd64, so every replica would fail with ImagePullBackOff. Publish via the 'Publish Docker' workflow instead of pushing by hand." + exit 1 + ;; + esac + - uses: azure/login@v2 with: creds: ${{ secrets.AZURE_CREDENTIALS }} diff --git a/Makefile b/Makefile index d6163bda6..9e3ebe676 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,11 @@ DOCKER_IMAGE ?= evcc/optimizer DOCKER_TAG ?= latest +# Container Apps nodes are amd64; an arm64-only tag takes production down +DOCKER_PLATFORMS ?= linux/amd64,linux/arm64 RESOURCE_GROUP ?= rg-optimizer-prod -default: build docker-build +default: build docker-build-local build:: go generate ./... @@ -31,16 +33,19 @@ loadtest:: uv run locust --host http://localhost:7050 --headless -t 30s -u 2 --only-summary uv run locust --host http://localhost:7050 --headless -t 30s -u 4 --only-summary -docker: docker-build docker-push docker-run +docker: docker-build docker-run +# Buildx cannot load a manifest list into the local image store, so a +# multi-platform tag only exists once pushed to the registry. docker-build:: - docker buildx build . --tag $(DOCKER_IMAGE) + docker buildx build . --platform $(DOCKER_PLATFORMS) --tag $(DOCKER_IMAGE):$(DOCKER_TAG) --push -docker-run:: - docker run -p 7050:7050 -it $(DOCKER_IMAGE) +# Host architecture only, loaded locally for docker-run. Never push this. +docker-build-local:: + docker buildx build . --tag $(DOCKER_IMAGE):$(DOCKER_TAG) --load -docker-push:: - docker push $(DOCKER_IMAGE) +docker-run:: docker-build-local + docker run -p 7050:7050 -it $(DOCKER_IMAGE):$(DOCKER_TAG) fly:: fly deploy --local-only