Have you ever excitedly pulled a Docker image on your Apple Silicon Mac, only to be greeted with a missing manifest error for ARM? It’s like being locked out of your own house. If you’ve hit the dreaded “manifest not available for ARM” message, you’re not alone. Many developers run into this issue when working with Docker images on Apple Silicon Macs. But why does this happen? And more importantly, how do you fix it without losing your cool (or your container)?
Why Does the “Manifest Not Available for ARM” Error Happen?
Docker images aren’t magic bundles of code. They are actually compiled binaries built for specific CPU architectures. Most public images on Docker Hub include a manifest list, mapping different architectures (AMD64, ARM64, etc.) to the right image variant. When you run docker pull image:tag
, Docker checks the manifest to find an image matching your system’s architecture.
On Apple Silicon (which uses ARM64), if no ARM64 variant exists for an image, Docker can’t find a match and throws an error. For example, running the official MySQL 5.7 image on an ARM64 Mac results in:
❯ docker run mysql:5.7
Unable to find image 'mysql:5.7' locally
docker: Error response from daemon: no matching manifest for linux/arm64/v8 in the manifest list entries.
This happens for many different Docker images, a lot remain AMD64-only. However, Apple Silicon, ARM-based servers, and Raspberry Pis are becoming increasingly popular, so it’s important to know how to build multi-architecture Docker images.
Building Multi-Arch Docker Images (Apple Silicon Friendly)
If you maintain Docker images, building images for multiple architectures is the best way to avoid manifest issues. The most convenient way to do this by using Docker Buildx in a GitHub Actions pipeline. This way, you can automate the building of the multi-arch images. The steps you need to include in your GitHub Actions file are as follows:
1. Set Up QEMU for Emulation
QEMU allows GitHub Actions (or local builds) to emulate non-native architectures:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
2. Enable Docker Buildx
Buildx extends Docker’s capabilities to support multi-architecture builds:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
3. Authenticate with a Container Registry
Log into Docker Hub or GitHub Container Registry:
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
4. Build and Push Multi-Arch Images
- name: Build and push Docker image
uses: docker/build-push-action@v2
with:
context: .
file: Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: YOUR_REPO/YOUR_IMAGE:latest
5. Verify the Manifest
After pushing, confirm your image supports multiple architectures:
docker manifest inspect YOUR_REPO/YOUR_IMAGE:latest
And that’s it, you’re good to go!
Troubleshooting Common ARM Image Issues
Even with multi-arch images, problems arise. Here are some common problems you may run into and how to fix them:
-
Missing Manifest vs. Image Not Found: If the error references manifest list entries, it’s an architecture issue. If it simply says manifest not found, the image may not exist so double-check your image tag.
-
Forcing Emulation: If no ARM version exists, try running an x86 image with QEMU:
docker pull --platform=linux/amd64 some_image:tag
-
Specifying Architecture in Docker Compose: To make sure you pull the right image, specify the architecture in your Docker Compose file:
services: db: image: mysql:5.7 platform: "linux/amd64"
-
Checking Supported Architectures Before Pulling: Before pulling an image, check the manifest to ensure it supports the architecture you need:
docker manifest inspect image_name:tag
-
Finding ARM-Friendly Alternatives: Some images lack ARM support, so you’ll have to find other options. For example, MYSQL doesn’t have ARM support, so you’ll have to use Maria Db instead. Try:
docker pull mariadb:latest
Debugging Remote Phoenix Apps with docker run
Once you’ve built an ARM-compatible image, you may notice a bug that happens in your production enviornment but not when you run your app locally. To debug that issue, it’s useful to know how to run remote Docker images locally.
First, try running your container locally, this will help you discover any configurations and/or environment variables that you need to use:
1. Run Your Container to Discover Runtime Configurations
❯ docker run ghcr.io/beamops/kanban:non-distributed
ERROR! Config provider Config.Reader failed with:
** (RuntimeError) environment variable DATABASE_URL is missing.
2. Start a PostgreSQL Database
Most Phoenix apps need a database to be able to start properly. If you don’t already have a running PostgreSQL instance, launch one with:
❯ docker run -d --name postgres-container \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
postgres:latest
3. Bypass Docker Network with Your Local IP
Docker containers are isolated by default, so you cannot connect a containerised Phoenix app to a local database out of the box. To be able to do this, you need to populate your DATABASE_URL
environment variable with your machine’s IP address. To get your IP address on macOS (Wi-Fi) run:
❯ ipconfig getifaddr en0
If using Ethernet, replace en0
with the correct interface.
4. Run Your Phoenix App with Environment Variables
Use your local IP to configure DATABASE_URL
when running the container:
❯ docker run --rm \
-e "DATABASE_URL=ecto://postgres:postgres@192.168.1.178:5432/postgres" \
-e "SECRET_KEY_BASE=YOUR_SECRET_KEY" \
-p 4000:4000 \
ghcr.io/beamops/kanban:non-distributed
5. Access the App
Visit http://localhost:4000 in your browser to check if it’s running. And there you have it, your remote image running locally. You can now reproduce any bugs that are happening in production.
Conclusion
Apple Silicon and ARM are now mainstream, yet many Docker images still lack ARM support. By leveraging multi-arch builds and emulation tricks, you can ensure your images work everywhere.
Remember to inspect manifests, force emulation, and check supported architectures to avoid common pitfalls. And when debugging Phoenix apps, always start with environment variables and local database connectivity.
Do you have any more ideas or an ARM debugging war story? If so, we’d love to hear them about Docker, DevOps, and Elixir! 🚀
Happy debugging—and may all your manifests be multi-arch!
P.S for more insights like these, check out Engineering Elixir Applications.