I have a go web service that I’ve been building with docker build
and running with docker run
on my M1 Mac and on various Linux machines for a while. It’s a simple binary installed on a distroless base and works great. Now I want to make a multi-platform image export to send to co-workers to run on their computers (M1 and Intel Macs). I’ve made an OC export like so:
docker buildx build --platform linux/amd64,linux/arm64 -t toy -o type=oci,dest=toy.oci .
And importing works fine:
docker image import toy.oci toy
sha256:02f7342d9d6ec2a1b66440aedb8d9a6ae0e968373fc8f2b698f7c8e73e6747e0
Running it is another matter:
docker run -d --name toy -p 4242:4242 toy:latest
docker: Error response from daemon: No command specified.
See 'docker run --help'.
This is odd, because my Dockerfile has an ENTRYPOINT
. Whatever, I try to tell it the command to run:
docker run -d --name toy -p 4242:4242 toy:latest /bin/toy
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "/bin/toy": stat /bin/toy: no such file or directory: unknown.
It’s almost as if the container has no files in it! docker image ls
shows my 32MB image, so I know there’s something there, but where is it? Is there a layer missing?
FWIW I tried type=tar
, too, and got the same result.
I assume I’m missing a step, but my DuckDuckGo-foo fails me. How does one build exportable multi-platform Docker images that actually work?
3
Answers
@BMitch's answer nicely addresses the various issues here, enough to get me to where I could get things to work purely with Docker. The kicker is the lack of support for loading multiplatform images, so there must be separate images per platform. The incantation for that is:
Then the individual tar files can be shared with whomever, and loaded with:
Switch to
toy-amd64.tar
on AMD64 platforms.For kicks, I made
make
targets to do the builds and load like so:Several things happening at once here:
docker load
. Thedocker import
command loads a filesystem export from a container, and will not have any image metadata.docker load
command expects its own metadata that is different from an OCI Layout.I have functionality in
regctl
to pull out the specific platform and do the conversion that just got checked into main (so it will be released in v0.4.5, or you can pull the binaries direct from GHA if you don’t want to build it yourself). The commands to do this look like:This behavior from docker will change with the transition to containerd for image management. When that happens, multi-platform images can be loaded directly into docker and their import command should support the OCI Layout directly. As of this update, that is experimental in Docker Desktop and not yet released with the docker engine on Linux.
The way that I’ve been building images with multi-arch support on my M1 is:
docker buildx create --bootstrap
docker buildx ls
and that is selected, there is an asterisk next to the name of the node, otherwise run:docker buildx use [node]
.docker buildx build --platform linux/amd64,linux/arm64 -t sample:v1 . --push
. This will push the images to a registry.Once the image is in the registry, your co-workers can start pulling it. This is the simplest way, as I’ve had issues in the past trying other destination outputs.