How to Build a Multi-Arch Docker Image in a Jenkins Pipeline
Drive docker buildx from a Jenkins stage to cross-build amd64 + arm64 into one pushed manifest.
On an agent with Docker and Buildx, register QEMU emulators, create a builder, log in with bound credentials, then docker buildx build --platform ... --push.
Buildx in a stage
Install emulators, create a builder, then build both platforms and push under the build number tag.
pipeline {
agent any
stages {
stage('Build multi-arch') {
steps {
withCredentials([usernamePassword(credentialsId: 'registry-creds',
usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
sh '''
echo "$REG_PASS" | docker login -u "$REG_USER" --password-stdin registry.example.com
docker run --privileged --rm tonistiigi/binfmt --install all
docker buildx create --use
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t registry.example.com/myorg/app:${BUILD_NUMBER} \
--push .
'''
}
}
}
}
}Gotchas
- The agent needs Docker with Buildx and the ability to run a privileged container for QEMU registration.
- Buildx pushes the multi-platform manifest directly; you cannot load it into the agent's local daemon.
- Use triple single-quotes for the shell block so Groovy does not interpolate
$REG_USERbefore the shell sees it.
Verify it actually works
Validate the pipeline definition against the running controller before committing. Jenkins parses declarative pipelines strictly, and a syntax error surfaces as a failed build rather than a clear parse message.
# validate a Jenkinsfile against the live controller
curl -X POST -F "jenkinsfile=<Jenkinsfile" \
https://your-jenkins/pipeline-model-converter/validate
# replay a build with modified script to test a change without committing
# Build page -> Replay -> edit -> RunAgent and workspace assumptions that break in CI
- An agent label that matches no online agent leaves the build queued indefinitely rather than failing.
- Workspaces are reused between builds by default, so stale files from a previous run can mask or cause failures. Use
cleanWs()or a fresh workspace when correctness matters. - Tools resolved from the controller PATH are not necessarily on the agent PATH. Declare them in a
toolsblock or install them in the pipeline. - Credentials bound with
withCredentialsare masked in logs but still visible to any process you launch; avoid passing them as command-line arguments.