What's Actually Happening
You're trying to build a Docker image for multiple platforms (like linux/amd64 and linux/arm64) using Docker buildx, but the build fails with architecture-specific errors. The image builds fine for your local platform but fails when targeting different architectures.
The Error You'll See
Buildx fails with platform mismatch:
```bash $ docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .
[+] Building 0.5s (3/12) ERROR: failed to solve: process "/bin/sh -c go build -o app" did not complete successfully
buildkitd: error: failed to solve: no match for platform in manifest linux/arm64: not found
# Platform not supported: executor failed running [/bin/sh -c pip install -r requirements.txt]: Cannot install package on arm64 ```
QEMU emulation error:
```bash $ docker buildx build --platform linux/arm64 -t myapp:arm64 .
WARN[0000] No support for arm64 in native builder ERROR: failed to solve: process "go build" did not complete successfully: qemu: uncaught target signal 11 (Segmentation fault) - core dumped
qemu: qemu-thread: error in select: Bad file descriptor ```
Base image not available:
```bash ERROR: failed to solve: pull access denied, repository does not exist or may require authorization: some-base-image: arm64 manifest does not exist
failed to fetch platform linux/arm64: manifest unknown: manifest unknown ```
Why This Happens
- 1.Buildx not properly configured - Missing or misconfigured builder instance
- 2.QEMU not installed - Cross-platform emulation not available
- 3.Base image missing for platform - Image doesn't support target architecture
- 4.Native compilation fails - Code compiled for wrong architecture
- 5.Package not available for platform - Dependency missing for target arch
- 6.Build cache corrupted - Cross-platform cache issues
- 7.Dockerfile not platform-aware - Commands assume specific architecture
- 8.Resource limits on emulation - QEMU needs adequate resources
Step 1: Check Buildx Configuration
```bash # List available builders: docker buildx ls
# Expected output showing multi-platform support: NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS default * docker default default running linux/amd64, linux/386 mybuilder docker-container mybuilder0 unix:///var/run/buildkit.sock running linux/amd64, linux/arm64, linux/arm/v7
# Check current builder: docker buildx use default docker buildx inspect --bootstrap
# If no multi-platform builder, create one: docker buildx create --name multiarch --driver docker-container --use
docker buildx inspect --bootstrap
# Expected platforms: Platforms: linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6
# Create builder with specific platforms: docker buildx create --name mybuilder \ --driver docker-container \ --driver-opt network=host \ --platform linux/amd64,linux/arm64,linux/arm/v7 \ --use
# Bootstrap the builder: docker buildx use mybuilder docker buildx inspect --bootstrap
# Check buildx version: docker buildx version # Should be v0.10+ for good multi-platform support ```
Step 2: Install and Configure QEMU
```bash # Check if QEMU is installed: docker run --rm --platform linux/arm64 alpine uname -m # Expected: aarch64 (arm64)
# If fails, install QEMU: docker run --privileged --rm tonistiigi/binfmt --install all
# Verify QEMU platforms: docker run --privileged --rm tonistiigi/binfmt --display
# Output should show: qemu-aarch64 (arm64): enabled qemu-arm (arm/v7): enabled qemu-ppc64le (ppc64le): enabled
# Check binfmt_misc: ls /proc/sys/fs/binfmt_misc/ # Should show qemu-aarch64, qemu-arm, etc.
# For Linux systems, also: cat /proc/sys/fs/binfmt_misc/qemu-aarch64 # Should show enabled
# Install QEMU packages on host (optional for better performance): # Ubuntu/Debian: sudo apt-get install qemu-user-static qemu-user-binfmt
# Fedora/RHEL: sudo dnf install qemu-user-static
# macOS (Docker Desktop includes QEMU): # Check Docker Desktop settings > Features > Use containerd
# Verify emulation works: docker run --rm --platform linux/arm64 alpine:latest uname -m # Output: aarch64
docker run --rm --platform linux/amd64 alpine:latest uname -m # Output: x86_64 ```
Step 3: Use Platform-Aware Base Images
```dockerfile # Dockerfile with platform awareness:
# Option 1: Use multi-platform base images FROM python:3.11-slim # python official image supports amd64, arm64, arm/v7
# Option 2: Specify platform explicitly FROM --platform=$TARGETPLATFORM python:3.11-slim
# Option 3: Use scratch for minimal images FROM --platform=$BUILDPLATFORM golang:1.21 AS builder FROM --platform=$TARGETPLATFORM scratch AS runtime
# Check base image platforms: docker buildx imagetools inspect python:3.11-slim
# Output: # Manifests: # Name: python:3.11-slim@sha256:abc... # Platform: linux/amd64 # Name: python:3.11-slim@sha256:def... # Platform: linux/arm64 # Name: python:3.11-slim@sha256:ghi... # Platform: linux/arm/v7
# If base image missing platform, use alternative: # Instead of: FROM some-custom-image:latest # Only amd64
# Use: FROM alpine:3.19 # Multi-platform RUN apk add --no-cache python3 py3-pip
# Or build from scratch: FROM --platform=$TARGETPLATFORM alpine:3.19 ```
Step 4: Fix Cross-Compilation in Dockerfile
```dockerfile # For Go applications (native cross-compilation): FROM --platform=$BUILDPLATFORM golang:1.21 AS builder
ARG TARGETPLATFORM ARG TARGETARCH ARG BUILDPLATFORM
WORKDIR /app COPY . .
# Go supports cross-compilation via GOARCH: RUN GOARCH=$TARGETARCH GOOS=linux go build -o app main.go
FROM --platform=$TARGETPLATFORM alpine:3.19 COPY --from=builder /app/app /app ENTRYPOINT ["/app"]
# For C/C++ applications (need cross-compiler): FROM --platform=$BUILDPLATFORM debian:bullseye AS builder
ARG TARGETARCH
RUN apt-get update && apt-get install -y \ build-essential \ gcc-aarch64-linux-gnu \ # ARM64 cross-compiler gcc-arm-linux-gnueabi \ # ARM cross-compiler libc6-dev-arm64-cross \ libc6-dev-arm-cross
WORKDIR /app COPY . .
RUN if [ "$TARGETARCH" = "arm64" ]; then \ aarch64-linux-gnu-gcc -o app main.c; \ elif [ "$TARGETARCH" = "arm" ]; then \ arm-linux-gnueabi-gcc -o app main.c; \ else \ gcc -o app main.c; \ fi
FROM --platform=$TARGETPLATFORM debian:bullseye-slim COPY --from=builder /app/app /app ENTRYPOINT ["/app"]
# For Rust applications: FROM --platform=$BUILDPLATFORM rust:1.75 AS builder
ARG TARGETARCH
RUN rustup target add aarch64-unknown-linux-gnu RUN rustup target add arm-unknown-linux-gnueabi
WORKDIR /app COPY . .
RUN if [ "$TARGETARCH" = "arm64" ]; then \ cargo build --release --target aarch64-unknown-linux-gnu; \ else \ cargo build --release; \ fi
FROM --platform=$TARGETPLATFORM debian:bullseye-slim COPY --from=builder /app/target/*/release/app /app ```
Step 5: Handle Platform-Specific Dependencies
```dockerfile # Use conditional logic for dependencies:
FROM --platform=$TARGETPLATFORM python:3.11-slim
ARG TARGETARCH
# Install platform-specific packages: RUN if [ "$TARGETARCH" = "arm64" ] || [ "$TARGETARCH" = "arm" ]; then \ # ARM-specific packages pip install --no-cache-dir \ numpy==1.26.0 \ scipy==1.11.0; \ else \ # AMD64 packages (may have more options) pip install --no-cache-dir \ numpy==1.26.0 \ scipy==1.11.0 \ some-amd64-only-package; \ fi
# For wheels not available, build from source: RUN pip install --no-binary :all: package-name
# Or pre-compile wheels: FROM --platform=$BUILDPLATFORM python:3.11 AS wheel-builder
ARG TARGETARCH ARG TARGETPLATFORM
RUN pip wheel --wheel-dir /wheels \ numpy scipy pandas
FROM --platform=$TARGETPLATFORM python:3.11-slim COPY --from=wheel-builder /wheels /wheels RUN pip install --no-index --find-links=/wheels numpy scipy pandas
# Check if package supports target platform: pip index versions --platform linux/arm64 package-name ```
Step 6: Optimize Multi-Platform Build Cache
```bash # Use buildx cache for faster builds: docker buildx build \ --platform linux/amd64,linux/arm64 \ --cache-from type=registry,ref=myregistry/myapp:buildcache \ --cache-to type=registry,ref=myregistry/myapp:buildcache,mode=max \ -t myapp:latest \ --push \ .
# Local cache: docker buildx build \ --platform linux/amd64,linux/arm64 \ --cache-from type=local,src=/tmp/buildx-cache \ --cache-to type=local,dest=/tmp/buildx-cache-new \ -t myapp:latest \ .
# Inline cache: docker buildx build \ --platform linux/amd64,linux/arm64 \ --build-arg BUILDKIT_INLINE_CACHE=1 \ --cache-from myapp:latest \ -t myapp:latest \ --push \ .
# Clear corrupted cache: docker buildx prune --all
# Or clear specific builder: docker buildx use mybuilder docker buildx prune
# Check cache size: docker buildx du
# For GitHub Actions cache: docker buildx build \ --platform linux/amd64,linux/arm64 \ --cache-from type=gha \ --cache-to type=gha,mode=max \ -t myapp:latest \ . ```
Step 7: Build and Push Multi-Platform Manifest
```bash # Build for multiple platforms and push: docker buildx build \ --platform linux/amd64,linux/arm64,linux/arm/v7 \ -t myregistry/myapp:v1.0 \ --push \ .
# Build without push (local load): # Note: Cannot load multi-platform images locally # Must build single platform for local: docker buildx build \ --platform linux/amd64 \ -t myapp:v1.0 \ --load \ .
# Build and create manifest list: docker buildx build \ --platform linux/amd64,linux/arm64 \ -t myregistry/myapp:v1.0 \ -t myregistry/myapp:latest \ --output type=image,name=myregistry/myapp:v1.0,push=true \ .
# Inspect multi-platform image: docker buildx imagetools inspect myregistry/myapp:v1.0
# Output: # MediaTypes: # application/vnd.docker.distribution.manifest.list.v2+json # Manifests: # Name: myregistry/myapp:v1.0@sha256:abc... # Platform: linux/amd64 # Name: myregistry/myapp:v1.0@sha256:def... # Platform: linux/arm64
# Verify pull works on different platforms: docker pull myregistry/myapp:v1.0 docker inspect myregistry/myapp:v1.0 | jq '.Architecture' ```
Step 8: Handle QEMU Performance Issues
```bash # QEMU emulation is slow. Optimize:
# 1. Use cross-compilation instead of emulation when possible: # Go, Rust, Java, Python support cross-compilation natively
# 2. Reduce QEMU overhead in Dockerfile: FROM --platform=$BUILDPLATFORM golang:1.21 AS builder # Build on native platform (fast) ARG TARGETARCH RUN GOARCH=$TARGETARCH go build -o app
FROM --platform=$TARGETPLATFORM alpine COPY --from=builder /app/app /app # Only copy binary to target platform (no emulation)
# 3. Use native runners for CI: # GitHub Actions matrix: strategy: matrix: platform: [linux/amd64, linux/arm64] include: - platform: linux/amd64 runner: ubuntu-latest - platform: linux/arm64 runner: ubuntu-latest-arm64 # Native ARM runner
# 4. Split build and test: # Build multi-platform image on powerful amd64 machine # Test arm64 on native arm64 runner
# 5. Monitor QEMU resource usage: docker stats # If QEMU container uses high CPU, consider: # - More RAM for buildx container # - Native compilation # - Pre-built base images
# Buildx container resources: docker buildx create \ --name mybuilder \ --driver docker-container \ --driver-opt image=moby/buildkit:master \ --driver-opt network=host \ --driver-opt cpu-quota=400000 \ # 4 CPUs --driver-opt memory=8G \ # 8GB RAM --use ```
Step 9: Debug Multi-Platform Build Failures
```bash # Enable verbose build output: docker buildx build \ --platform linux/amd64,linux/arm64 \ --progress=plain \ -t myapp:latest \ .
# Debug specific platform: docker buildx build \ --platform linux/arm64 \ --no-cache \ --progress=plain \ -t myapp:arm64 \ . 2>&1 | tee build.log
# Check buildx logs: docker buildx use mybuilder docker logs buildx_buildkit_mybuilder0
# Test each platform separately: docker buildx build --platform linux/amd64 -t myapp:amd64 . docker buildx build --platform linux/arm64 -t myapp:arm64 . docker buildx build --platform linux/arm/v7 -t myapp:armv7 .
# Debug Dockerfile step: docker buildx build \ --platform linux/arm64 \ --target builder \ -t myapp:debug \ .
# Interactive debugging: docker run --rm --platform linux/arm64 -it alpine sh # Test commands inside ARM64 container
# Check specific package availability: curl -s https://pypi.org/pypi/numpy/json | \ jq '.urls[] | select(.filename | contains("arm64"))'
# Test pip install on target platform: docker run --rm --platform linux/arm64 python:3.11-slim \ pip install package-name ```
Step 10: Implement Production Multi-Platform Build Pipeline
```dockerfile # Complete production Dockerfile: # syntax=docker/dockerfile:1.4
# Build stage (native platform for speed) FROM --platform=$BUILDPLATFORM golang:1.21-alpine AS builder
ARG TARGETPLATFORM ARG TARGETARCH ARG BUILDPLATFORM
WORKDIR /app
# Copy go mod files first (better caching) COPY go.mod go.sum ./ RUN go mod download
# Copy source COPY . .
# Cross-compile (fast, no emulation) RUN CGO_ENABLED=0 \ GOOS=linux \ GOARCH=$TARGETARCH \ go build -ldflags="-w -s" -o /app/server .
# Runtime stage (target platform) FROM --platform=$TARGETPLATFORM alpine:3.19
# Security: non-root user RUN addgroup -g 1000 appgroup && \ adduser -u 1000 -G appgroup -D appuser
WORKDIR /app
# Copy binary from builder COPY --from=builder --chown=appuser:appgroup /app/server /app/server
# Health check HEALTHCHECK --interval=30s --timeout=3s \ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
USER appuser
EXPOSE 8080
ENTRYPOINT ["/app/server"] ```
```bash # Production build script: cat << 'EOF' > build-multiarch.sh #!/bin/bash
set -e
IMAGE="myregistry/myapp" VERSION="${1:-latest}" PLATFORMS="linux/amd64,linux/arm64,linux/arm/v7"
echo "Building $IMAGE:$VERSION for $PLATFORMS"
# Ensure buildx is ready docker buildx use multiarch || docker buildx create --name multiarch --use docker buildx inspect --bootstrap
# Build and push docker buildx build \ --platform "$PLATFORMS" \ --cache-from type=registry,ref="$IMAGE:buildcache" \ --cache-to type=registry,ref="$IMAGE:buildcache",mode=max \ --tag "$IMAGE:$VERSION" \ --tag "$IMAGE:latest" \ --push \ .
# Verify docker buildx imagetools inspect "$IMAGE:$VERSION"
echo "Build complete: $IMAGE:$VERSION" EOF
chmod +x build-multiarch.sh
# CI/CD configuration (GitHub Actions): # .github/workflows/build.yml name: Build Multi-Platform Image
on: push: branches: [main]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
- name: Set up QEMU
- uses: docker/setup-qemu-action@v3
- name: Login to Registry
- uses: docker/login-action@v3
- with:
- registry: myregistry.io
- username: ${{ secrets.REGISTRY_USER }}
- password: ${{ secrets.REGISTRY_PASS }}
- name: Build and Push
- uses: docker/build-push-action@v5
- with:
- context: .
- platforms: linux/amd64,linux/arm64
- push: true
- tags: myregistry.io/myapp:${{ github.sha }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
`
Multi-Platform Build Checklist
| Check | Command | Expected |
|---|---|---|
| Buildx ready | buildx ls | Multi-platform builder |
| QEMU installed | binfmt --display | arm64 enabled |
| Base image platforms | imagetools inspect | All platforms |
| Cross-compilation | GOARCH=$ARCH | Native compile |
| Cache working | buildx du | Cache entries |
| Manifest valid | imagetools inspect | All platforms listed |
Verify the Fix
```bash # After fixing multi-platform build:
# 1. Build all platforms docker buildx build --platform linux/amd64,linux/arm64 -t myapp:v1 --push . # Output: Successfully built and pushed
# 2. Verify manifest docker buildx imagetools inspect myapp:v1 # Output: Manifests for amd64 and arm64
# 3. Pull and test on AMD64 docker pull myapp:v1 docker run --rm myapp:v1 uname -m # Output: x86_64
# 4. Pull and test on ARM64 (if available) docker run --rm --platform linux/arm64 myapp:v1 uname -m # Output: aarch64
# 5. Check image size docker images myapp:v1 # Reasonable size for both platforms
# 6. Run application docker run myapp:v1 # Application starts correctly
# 7. Verify health check docker ps # Container healthy
# Compare before/after: # Before: QEMU segfault, platform not found # After: Successful build for all platforms ```
Related Issues
- [Fix Docker Build Failed](/articles/fix-docker-build-failed)
- [Fix Docker Image Pull Failed](/articles/fix-docker-image-pull-failed)
- [Fix Kubernetes ImagePullBackOff Error](/articles/fix-kubernetes-imagepullbackoff-error)