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. 1.Buildx not properly configured - Missing or misconfigured builder instance
  2. 2.QEMU not installed - Cross-platform emulation not available
  3. 3.Base image missing for platform - Image doesn't support target architecture
  4. 4.Native compilation fails - Code compiled for wrong architecture
  5. 5.Package not available for platform - Dependency missing for target arch
  6. 6.Build cache corrupted - Cross-platform cache issues
  7. 7.Dockerfile not platform-aware - Commands assume specific architecture
  8. 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

CheckCommandExpected
Buildx readybuildx lsMulti-platform builder
QEMU installedbinfmt --displayarm64 enabled
Base image platformsimagetools inspectAll platforms
Cross-compilationGOARCH=$ARCHNative compile
Cache workingbuildx duCache entries
Manifest validimagetools inspectAll 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 ```

  • [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)