👷(docker) add arm64 platform support for image builds#296
Conversation
WalkthroughAdds QEMU setup and multi-architecture (linux/amd64, linux/arm64) build targets to the GitHub Actions Docker build/push workflow for backend and frontend; updates CHANGELOG to note arm64 support. Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer (push)
participant GH as GitHub Actions
participant QEMU as docker/setup-qemu-action
participant Buildx as docker buildx
participant Registry as Docker Registry
Dev->>GH: push event triggers workflow
GH->>QEMU: run QEMU setup step
GH->>Buildx: run build-push with platforms linux/amd64,linux/arm64
Buildx->>Registry: build and push multi-arch images
Registry-->>Dev: images available
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub. |
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/docker-hub.yml (1)
46-62:⚠️ Potential issue | 🟠 MajorThe arm64 image is published without being security-scanned.
The
Run trivy scanstep builds and scans only the default amd64 variant (no--platformflag, running on anubuntu-latest/ amd64 runner). The subsequentBuild and pushstep then publishes bothlinux/amd64andlinux/arm64to DockerHub, so the arm64 image bypasses the vulnerability scan entirely.Because the host is AMD64, arm64 images built locally or via QEMU emulation cannot automatically be found or loaded for scanning by tooling like Trivy without additional steps.
To close this gap, consider one of:
- Scan per-platform via matrix — build each platform separately, save as a tarball artifact, load and scan each, then merge manifests on push.
- Scan the pushed multi-arch manifest from the registry — push to a staging/short-lived tag first, then run trivy against that remote image with an explicit
--platform linux/arm64flag, before promoting the final tags.Also applies to: 90-108
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/docker-hub.yml around lines 46 - 62, The Trivy scan step ("Run trivy scan" using numerique-gouv/action-trivy-cache) only scans the default amd64 build while the "Build and push" step (docker/build-push-action@v6) publishes both linux/amd64 and linux/arm64, leaving arm64 unscanned; fix by either (A) converting the workflow to a build matrix over platforms (linux/amd64, linux/arm64) where each matrix job builds the platform-target (use docker/build-push-action to build and save a tar artifact), then in each job load that tar and run Trivy with the explicit --platform flag to scan the platform-specific image before pushing, or (B) change the push flow to first push to a staging tag (in "Build and push"), then add a separate scan job that runs Trivy against the remote manifest for each platform using --platform linux/arm64 and --platform linux/amd64 (promote tags only after both scans pass); update the "Run trivy scan" and "Build and push" steps to implement one of these flows so every published platform is scanned.
🧹 Nitpick comments (2)
.github/workflows/docker-hub.yml (2)
26-28: Consider scoping QEMU to only the required platform.The
platformsinput fordocker/setup-qemu-action@v3defaults toall, which installs QEMU binaries for every supported architecture. Since the runner already handleslinux/amd64natively, onlylinux/arm64emulation is actually needed here.♻️ Proposed change (apply identically to both jobs)
- - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64Also applies to: 70-72
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/docker-hub.yml around lines 26 - 28, The QEMU setup step using docker/setup-qemu-action@v3 currently installs all architectures; restrict the action by adding the platforms input to only emulate linux/arm64 (since linux/amd64 is native) so update the step that references docker/setup-qemu-action@v3 to include platforms: linux/arm64 (apply the same change for the other identical job where the step appears).
58-58: Consider using native arm64 runners to reduce QEMU emulation overhead.The platforms are specified correctly. However, building multiple platforms on the same runner with QEMU can significantly extend build times, particularly for complex Dockerfiles. By distributing platform-specific builds across multiple runners using a matrix strategy, you can drastically reduce build durations and streamline your CI pipeline.
Docker's own CI guidance recommends pairing
linux/amd64withubuntu-latestandlinux/arm64withubuntu-24.04-armin a build matrix, which avoids QEMU emulation entirely for arm64.This is a good-to-have improvement given that the QEMU approach is functionally correct, but worth considering as build times grow with the project.
Also applies to: 103-103
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/docker-hub.yml at line 58, The current platforms: linux/amd64,linux/arm64 entry causes QEMU emulation overhead; change the workflow to use a build matrix that creates separate jobs for each platform (e.g., matrix.os/arch pairs) so arm64 builds run on a native runner and amd64 on ubuntu-latest; specifically, replace the single platforms field usage with a matrix strategy that pairs linux/amd64 -> ubuntu-latest and linux/arm64 -> ubuntu-24.04-arm, then use the matrix values in the job runner and docker buildx invocation to avoid emulation and significantly reduce build time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In @.github/workflows/docker-hub.yml:
- Around line 46-62: The Trivy scan step ("Run trivy scan" using
numerique-gouv/action-trivy-cache) only scans the default amd64 build while the
"Build and push" step (docker/build-push-action@v6) publishes both linux/amd64
and linux/arm64, leaving arm64 unscanned; fix by either (A) converting the
workflow to a build matrix over platforms (linux/amd64, linux/arm64) where each
matrix job builds the platform-target (use docker/build-push-action to build and
save a tar artifact), then in each job load that tar and run Trivy with the
explicit --platform flag to scan the platform-specific image before pushing, or
(B) change the push flow to first push to a staging tag (in "Build and push"),
then add a separate scan job that runs Trivy against the remote manifest for
each platform using --platform linux/arm64 and --platform linux/amd64 (promote
tags only after both scans pass); update the "Run trivy scan" and "Build and
push" steps to implement one of these flows so every published platform is
scanned.
---
Nitpick comments:
In @.github/workflows/docker-hub.yml:
- Around line 26-28: The QEMU setup step using docker/setup-qemu-action@v3
currently installs all architectures; restrict the action by adding the
platforms input to only emulate linux/arm64 (since linux/amd64 is native) so
update the step that references docker/setup-qemu-action@v3 to include
platforms: linux/arm64 (apply the same change for the other identical job where
the step appears).
- Line 58: The current platforms: linux/amd64,linux/arm64 entry causes QEMU
emulation overhead; change the workflow to use a build matrix that creates
separate jobs for each platform (e.g., matrix.os/arch pairs) so arm64 builds run
on a native runner and amd64 on ubuntu-latest; specifically, replace the single
platforms field usage with a matrix strategy that pairs linux/amd64 ->
ubuntu-latest and linux/arm64 -> ubuntu-24.04-arm, then use the matrix values in
the job runner and docker buildx invocation to avoid emulation and significantly
reduce build time.
|
Some executions of CI steps could show an error.
The allowed actions list is configured in the organization's GitHub Settings. As I am an external contributor, I do not have access to modify these. I request the reviewer of this pull request to contact one of the people in this list: https://github.com/orgs/suitenumerique/people This pull request introduces QEMU (for emulation) and buildx (for cross-platform docker builds). These are needed because GitHub Actions runners are
Without these, the You can read more about it on github.com/docker/build-push-action. |
Signed-off-by: Stephan Meijer <me@stephanmeijer.com>
ff0f3dc to
a3d7c02
Compare
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/workflows/docker-hub.yml (1)
54-62: QEMU emulation will significantly inflate build times; consider adding layer cacheThe arm64 portion of the build is emulated using QEMU, and benchmarks have recorded up to 30× speedups when building on native Arm machines versus emulating via QEMU in CI. Neither
build-and-push-backendnorbuild-and-push-frontendconfigurescache-from/cache-to, so every run pays the full emulated build cost from scratch.Two recommended mitigations (either or both):
Option A — Add GHA layer cache to the existing build-push steps:
⚡ Add build cache
name: Build and push if: always() uses: docker/build-push-action@v6 with: context: . target: backend-production platforms: linux/amd64,linux/arm64 build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000 push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=maxApply the same diff to the frontend
Build and pushstep.Option B — Use a native
ubuntu-24.04-armrunner via a matrix strategy to eliminate emulation overhead entirely, building each platform on its native runner and pushing by digest before merging the manifest.Also applies to: 96-108
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/docker-hub.yml around lines 54 - 62, CI currently emulates arm64 which inflates build time; update the docker/build-push-action@v6 steps (the build-and-push-backend and build-and-push-frontend steps) to enable layer caching by adding cache-from and cache-to parameters (e.g., use type=gha and/or registry cache entries) so builds reuse prior layers, or replace the single-run approach with a matrix that targets native runners (include an ubuntu-24.04-arm runner in the matrix) to build the arm64 image natively and then push by digest; modify the action inputs for the steps that use context/target/platforms to include cache-from/cache-to or switch to a matrix strategy accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/docker-hub.yml:
- Line 58: The Trivy scan steps use numerique-gouv/action-trivy-cache with
docker-build-args but do not pass a --platform flag, so only linux/amd64 is
scanned while the workflow publishes a multi-arch manifest (platforms:
linux/amd64,linux/arm64); update the Trivy scan steps (the action usages of
numerique-gouv/action-trivy-cache and the docker-build-args inputs) to add a
second scan invocation that passes "--platform=linux/arm64" (or otherwise
include "--platform linux/arm64" in docker-build-args) so the arm64 image layers
are built and scanned, and if that action does not support platform builds, add
a short documented note in the workflow and open a follow-up issue to track
scanning arm64 separately.
---
Nitpick comments:
In @.github/workflows/docker-hub.yml:
- Around line 54-62: CI currently emulates arm64 which inflates build time;
update the docker/build-push-action@v6 steps (the build-and-push-backend and
build-and-push-frontend steps) to enable layer caching by adding cache-from and
cache-to parameters (e.g., use type=gha and/or registry cache entries) so builds
reuse prior layers, or replace the single-run approach with a matrix that
targets native runners (include an ubuntu-24.04-arm runner in the matrix) to
build the arm64 image natively and then push by digest; modify the action inputs
for the steps that use context/target/platforms to include cache-from/cache-to
or switch to a matrix strategy accordingly.
ℹ️ Review info
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.github/workflows/docker-hub.ymlCHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
- CHANGELOG.md
| with: | ||
| context: . | ||
| target: backend-production | ||
| platforms: linux/amd64,linux/arm64 |
There was a problem hiding this comment.
arm64 images are never scanned for vulnerabilities
The Trivy scan steps (lines 46–50 and 90–94) pass docker-build-args without a --platform flag, so numerique-gouv/action-trivy-cache only builds and scans the native linux/amd64 image. After this PR, the published multi-arch manifest also includes an linux/arm64 image whose base layers and packages are entirely unscanned — a different binary set that may carry different CVEs.
Options to address:
- Add a second scan invocation explicitly targeting
linux/arm64(if the custom action supports--platform linux/arm64indocker-build-args). - If option 1 is not feasible, document the known gap and open a follow-up issue to track it.
Also applies to: 103-103
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/docker-hub.yml at line 58, The Trivy scan steps use
numerique-gouv/action-trivy-cache with docker-build-args but do not pass a
--platform flag, so only linux/amd64 is scanned while the workflow publishes a
multi-arch manifest (platforms: linux/amd64,linux/arm64); update the Trivy scan
steps (the action usages of numerique-gouv/action-trivy-cache and the
docker-build-args inputs) to add a second scan invocation that passes
"--platform=linux/arm64" (or otherwise include "--platform linux/arm64" in
docker-build-args) so the arm64 image layers are built and scanned, and if that
action does not support platform builds, add a short documented note in the
workflow and open a follow-up issue to track scanning arm64 separately.
|
Rebased this branch on the latest target branch and force-pushed. |


Purpose / Proposal
Adding support for
linux/arm64when building Docker images.This is important because:
External contributions
git commit --signoff(DCO compliance)git commit -S)<gitmoji>(type) title description## [Unreleased]section (if noticeable change)Testing happens when GitHub Workflows are being executed.
Summary by CodeRabbit
New Features
Chores