Problem
Every published image is linux/amd64 only. A Raspberry Pi, an Orange Pi or an
ARM VPS cannot run Cluckwork at all — docker run fails to find a matching
manifest. For a small-farm product, a Pi under the desk is a likely deployment
target, so this closes off a real class of user.
Verified against the registry rather than inferred:
ghcr.io/mforce/cluckwork:v0.1.4
mediaType: application/vnd.docker.distribution.manifest.v2+json <- single manifest, not an index
architecture: amd64
os: linux
Cause: ci.yml's publish job does docker tag cluckwork-api:ci then
docker push of the image the image job already built on an ubuntu-latest
(amd64) runner. There is no --platform, no platforms: list and no QEMU setup
anywhere in .github/workflows/. Release promotion (#351) is a server-side
retag of that same digest, so it cannot add an architecture either.
This is smaller than it looks
The Dockerfile is already arm64-ready. #518 pinned the runtime base to the
multi-arch index digest on purpose, and said why:
Pinning an arch-specific digest here would quietly break the other
architecture.
#267 describes all three pins the same way. So #267's digest-pinning invariant
does not need revisiting: the pins resolve per-architecture by design, and the
policy is written down at the top of the Dockerfile. Both bases
(mcr.microsoft.com/dotnet/aspnet:10.0, node:26-alpine) publish arm64, and
.NET 10 targets arm64.
What is missing is only the CI build and push.
Work
The one open design question
Trivy scans the locally --loaded bytes (deliberately, so it examines the
freshly built image rather than a re-pull). --load cannot hold a multi-arch
index. Options, needing a decision rather than a default:
- Scan each architecture separately (doubles scan time, full coverage).
- Scan amd64 only and accept that an arm64-specific CVE is unscanned.
- Scan from the registry after push, which changes what the gate can block.
Costs
Build time roughly doubles, and worse if arm64 compiles under QEMU emulation
rather than a native arm64 runner. Worth measuring both before choosing.
Acceptance
Not covered
Whether to advertise arm64 support publicly is downstream of this. Raised while
preparing the repo for promotion, where "does it run on a Pi?" is a predictable
first question.
Problem
Every published image is
linux/amd64only. A Raspberry Pi, an Orange Pi or anARM VPS cannot run Cluckwork at all —
docker runfails to find a matchingmanifest. For a small-farm product, a Pi under the desk is a likely deployment
target, so this closes off a real class of user.
Verified against the registry rather than inferred:
Cause:
ci.yml'spublishjob doesdocker tag cluckwork-api:cithendocker pushof the image theimagejob already built on anubuntu-latest(amd64) runner. There is no
--platform, noplatforms:list and no QEMU setupanywhere in
.github/workflows/. Release promotion (#351) is a server-sideretag of that same digest, so it cannot add an architecture either.
This is smaller than it looks
The Dockerfile is already arm64-ready. #518 pinned the runtime base to the
multi-arch index digest on purpose, and said why:
#267 describes all three pins the same way. So #267's digest-pinning invariant
does not need revisiting: the pins resolve per-architecture by design, and the
policy is written down at the top of the Dockerfile. Both bases
(
mcr.microsoft.com/dotnet/aspnet:10.0,node:26-alpine) publish arm64, and.NET 10 targets arm64.
What is missing is only the CI build and push.
Work
docker/setup-qemu-action(SHA-pinned per the Actions policy in AGENTS.md).--platform linux/amd64,linux/arm64.docker tag+docker push, so:sha-<commit>resolves per architecture. The digest thepublishjobrecords for CI builds the runtime image but never publishes it — deploy-by-digest has no artifact to point at #351's promotion must then be the index digest, and
--prefer-index=falsein the promotion step needs re-reading against that —its current reasoning assumes a single manifest.
The one open design question
Trivy scans the locally
--loaded bytes (deliberately, so it examines thefreshly built image rather than a re-pull).
--loadcannot hold a multi-archindex. Options, needing a decision rather than a default:
Costs
Build time roughly doubles, and worse if arm64 compiles under QEMU emulation
rather than a native arm64 runner. Worth measuring both before choosing.
Acceptance
docker manifest inspect ghcr.io/mforce/cluckwork:<tag>returns an indexlisting
linux/amd64andlinux/arm64./health/readygreen.Deploy: farm timezone provisioning — seeded UTC + undocumented tzdata/ICU image dependency #264's tzdata/ICU requirement holds on arm64 too — do not let a base swap
smuggle in an Alpine or chiselled runtime.
gh attestation verifystill passes on the promoted reference.Not covered
Whether to advertise arm64 support publicly is downstream of this. Raised while
preparing the repo for promotion, where "does it run on a Pi?" is a predictable
first question.