12 Running containers on different platforms
Modern container workloads must account for two major axes of variation: CPU architecture (primarily Intel/AMD and Arm) and operating system (Linux and Windows). Because binaries and container images are platform-specific, an image that runs on one combination may fail on another. Docker’s answer is multi-platform images: a single image name published with multiple platform variants, so users pull the correct one automatically for their machine. Interest in this capability has surged with the rise of Apple Silicon and cost-efficient Arm instances in the cloud. While Docker Desktop can emulate other CPUs to build and run images cross-architecture, emulation is slower and not always instruction-accurate, so it’s best treated as a convenience for development rather than a production build strategy.
There are two main ways to produce multi-platform artifacts. The simplest is a single, multi-stage Dockerfile that compiles from source and relies on multi-platform base images, yielding different variants when built on different platforms. When base images or requirements differ by platform, you can maintain multiple Dockerfiles tailored to each OS/CPU, trading extra maintenance for precise control. It’s critical to keep commands platform-appropriate: the engine only pulls images that match its OS/architecture, and mixing OS-specific commands in startup paths can produce runtime failures. To publish a true multi-platform image, you push each variant and then create a manifest list that groups them under one tag; registries store platform metadata so Docker can deliver the right variant transparently.
For scalable, repeatable builds, you can use native build farms or Docker Buildx. Buildx extends docker build with a high-performance engine that fans out work to multiple builder nodes (defined via contexts), builds variants concurrently, and pushes both images and the multi-platform manifest in one command. Today it’s strongest for Linux CPU variants (Windows containers aren’t supported), but it dramatically simplifies multi-arch pipelines. Regardless of tooling, follow best practices to future-proof your images: base on multi-platform images, avoid OS-specific commands in RUN/CMD, and keep startup logic portable. Even if you don’t need multiple platforms now, these habits make it easy to add Arm, Windows, or additional architectures later and to leverage CI/CD services or cloud VMs to build and ship accurate, performant multi-platform images.
Using emulation in Docker Desktop to build images for different platforms
You can’t pull an image from a registry if there’s no variant to match your OS and CPU.
Use a multi-stage Dockerfile based on multi-platform images to build multiple image variants
You can also build image variants using Dockerfiles tailored for each platform.
Images built for a specific platform can be run using emulation in Docker Desktop.
It’s easy to build a multi-platform image that fails at runtime on some (or all) platforms.
Pushing all the image variants is the first stage in publishing a multi-platform image.
Multi-platform images have a manifest list, which contains the manifest for each platform variant.
Manifests and manifest lists exist on a Docker registry and contain metadata about images.
A multi-platform image has a single tag but many variants. Docker Hub shows all the variants.
You can use two addresses for a single Docker Engine to host two Buildx builders
Buildx uses contexts to talk to builders—it doesn’t mind if different contexts use the same address.
We’ve created a fake build farm with just a few commands—a real build farm is just as easy
Using the builder—each node builds one platform, and Buildx pushes the multi-platform manifest.
Projects typically launch with Linux Intel support and add variants as they become popular.
Lab
This chapter’s lab asks you to fix up a Dockerfile so that it can be used to produce multi-platform images. It’s the sort of thing you may come across if you have a Dockerfile that didn’t follow my best-practice suggestions. This Dockerfile is based on an image for a specific architecture, and it uses OS commands that are not portable. I’d like you to fix the Dockerfile in the lab folder for this chapter so that it can build an image targeted for Linux on Intel or Arm, and Windows on Intel. There are lots of ways to solve this; these are just a couple of hints for you:
- Some Dockerfile instructions are cross-platform, whereas equivalent OS commands in a RUN instruction may not be.
- Some Windows commands are the same as Linux, and in the golden base image for the book, there are some aliases to make other Linux commands work in Windows.
You’ll find my approach in the Dockerfile.solution file on GitHub for this chapter: https://github.com/sixeyed/diamol/blob/2e/ch12/lab/README.md.
Learn Docker in a Month of Lunches, Second Edition ebook for free