Building Multi-Platform Docker Images Using Multiple Hosts
Here’s a very quick, not exactly comprehensive tutorial on building Docker images using multiple hosts (useful for building multiple architectures).
If you’re an expert on docker buildx
, you may know all of this already, but if you’re not, hopefully you find this useful.
We’ll make some assumptions in this tutorial:
- We want to build a single Docker image with both
linux/amd64
andlinux/arm64
architectures. - We’ll be building the
linux/arm64
image on the local machine, andlinux/amd64
on a remote machine (accessible via SSH). - We’ll call this builder instance “my-builder”
We’re going to accomplish this by building a buildx
builder instance for the local machine and architecture, then append a configuration for another machine. And then we’ll activate that instance.
This is easy.
Step 1: Create your builder instance for localhost and arm64
$ docker buildx create \
--name my-builder \
--platform linux/arm64
This will create our my-builder
instance, defaulting it to using our local Docker setup for linux/arm64
.
If we wanted, we could provide a comma-separated list of platforms that the local Docker should be handling (e.g., --platform linux/arm64,darwin/arm64
).
(This doesn’t have to be arm64
. I’m just using this as an example.)
Step 2: Add your amd64 builder
$ docker buildx create \
--name my-builder \
--append \
--platform linux/amd64 \
ssh://<user>@<remotehost>
This will update our my-builder
, informing it that linux/amd64
builds are supported and must go through the Docker service over SSH.
Note that we could easily add additional builders if we wanted (whether for the same architectures or others) by repeating this command and choosing new --platform
values and remote hosts
Step 3: Verify your builder instance
Let’s take a look and make sure we have the builder setup we expect:
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
my-builder * docker-container
my-builder0 desktop-linux inactive linux/arm64*
my-builder1 ssh://myuser@example.com inactive linux/amd64*
Yours may look different, but it should look something like that. You’ll also see default
and any other builders you’ve set up.
Step 4: Activate your builder instance
Now we’re ready to use it:
$ docker buildx use my-builder
Just that easy.
Step 5: Build your image
If all went well, we can now safely build our image:
$ docker buildx build --platform linux/arm64,linux/amd64 .
You should see build output for each architecture stream by.
If we want to make sure the right builder is doing the right thing, you can re-run docker buildx ls
in another terminal. You should see running
as the status for each, along with an inferred list of other architectures that host can now build (pretty much anything it natively supports that you didn’t explicitly configure above).
Step 6: Load your image into Docker
You probably want to test your newly-built image locally, don’t you? When you run the build, you might notice this message:
WARNING: No output specified with docker-container driver. Build
result will only remain in the build cache. To push result image
into registry use --push or to load image into docker use --load
And if you try to start it up, you might notice it’s missing (or that you’re running a pre-buildx
version of your image).
What you need to do is re-run docker buildx build
with --load
and a single platform, like so:
$ docker buildx build --load --platform linux/arm64 .
That’ll rebuild it (it’ll likely just reuse what it built before) and then make it available in your local Docker registry.
Hope that helps!