Install Docker Buildx

Recently, I had to add a Docker image supporting ARM architecture in our ElasticMQ project. It’s possible with buildx — a Docker CLI plugin that extends the Docker build command. In this post, I will show you how to automate creating Docker images for different architectures using sbt-native-packager.

Installing Additional Platforms With Docker Buildx I'm working on using docker buildx to be able to cross-build docker images for my raspberry pi and my laptop. While reading a few tutorials on the internet, some of them show the output for docker buildx ls to show the available platforms that can be used. Either a Host installation or Docker image-based installation of QEMU must be done on the host machine. Docker buildx build command can be used to build the multi architecture images. Along with the command, the –platform flag can be used to specify the target architecture for the build output, (e.g. Linux/amd64, linux/arm64, darwin/amd64).

After installation, buildx can be accessed through the docker buildx command with Docker 19.03. Docker buildx build is the command for starting a new build. With Docker versions older than 19.03 buildx binary can be called directly to access the docker buildx subcommands.

Firstly, what we need is the SBT Native Packager plugin, so add it in project/plugins.sbt:

and also docker plugin, so moving to build.sbt:

We may provide many additional settings like dockerRepository or dockerUsername to change the repository or username to which the image is pushed when the docker:publish task is run. We may also override the Docker build options dockerBuildOptions which are passed to docker build command and by default is

The Docker plugin provides many useful commands like docker:stage to generate a directory with the Dockerfile and an environment prepared for creating a Docker image. Running docker:publishLocal builds an image using the local Docker server. If you want to build and also push an image to the configured remote repository — simply run docker:publish. But inspecting the image Architecture will reveal that we have a single value like amd64. To extend it — let’s use buildx!

Docker Buildx is included in Docker Desktop and Docker Linux packages when installed using the DEB or RPM packages. You can check if it is already installed running docker buildx version. To use it, we may set buildx as the default builder with docker buildx install. This results in the ability to have docker build use the current buildx builder. Or we may create a new builder instance with

Now let’s switch to build.sbt and see the final configuration. I will analyze its parts afterwards.

Finally value dockerBuildxSettings is provided for an appropriate project type like that:

The first part defines the ensureDockerBuildx task. It is just creating a new buildx instance. Before that, we are checking whether the instance already exists. Calling Process(...).! results with an Int. In that case, 0 means that the instance exists. For 1 — we should create a new one.

The second part defines dockerBuildWithBuildx — that is the main action. Here for every dockerAlias we have to execute building and pushing the image. Each docker alias has the form of:

In our case, we have two aliases because of two (versions) tags: 1.1.1 and latest. To specify the target platform, we have to provide flag with the desired values:

Since we are using a docker-container driver with buildx (thanks to creating a new buildx instance), the flag --platform can accept multiple values as an input separated by a comma. We are also providing the flag --push to push images to the remote repository. It’s shorthand for --output=type=registry. You have to remember that images built like that won’t be available when you type docker images! If you want to load the build result to docker images use the flag --load instead of --push. However, that works only for single-platform builds.

We are executing building and pushing in the directory /target/docker/stage because there is a Dockerfile generated by the command docker:publishLocal.

Lastly, we are redefining the task docker:publish. Using the Def.sequential function, we can run tasks under semi-sequential semantics. In the beginning, we need to execute Docker / publishLocal to create the needed Dockerfile. Remember that the base image in Dockerfile must also support configured architectures with flag --platform. Next, there are ensureDockerBuildx and dockerBuildWithBuildx. After that, executing docker:publish will generate all images for configured architectures.

Hope that it is clear and helpful. For more information about Docker plugin for sbt and buildx, you may find documentation here and here.

Please enable JavaScript to view the comments powered by Disqus.Blog Comments powered by Disqus.

I just bought my new M1 Apple Silicon Mac Mini, and after about a week of using it I ran into an issue related to different architectures and deployment of Docker containers. I can build and run images on my M1 Mac fine, but when I try and push the image built on the Apple Silicon Mac to a cloud server running Linux distro, I see the following error:
standard_init_linux.go:211: exec user process caused 'exec format error'

This was troubling to say the least. So for awhile I just used my old AMD64 Mac to compile and push my containers. But this is not ideal, so how can we fix this?

Docker Buildx Install Windows

System requirements

You must install Rosetta 2 as some binaries are still Darwin/AMD64. To install Rosetta 2 manually from the command line, run the following command:
softwareupdate --install-rosetta

Using buildx

Buildx comes with a default builder that you can see by typing docker buildx ls into your terminal. However, we want to make and use a builder ourselves.

Make a builder

Install Docker Buildx

You will need a new builder, to make one use docker buildx create --name m1_builder. Now you should see the new builder when running docker buildx ls.

Bootstrap the Builder

The next steps are to use the new builder then bootstrap it. To allow docker to use new builder run, docker buildx use m1_builder and then docker buildx inspect --bootstrap, which will inspect and bootstrap the builder instance you’re using.

Build with the builder

Now, navigate to where you want to build and push an image so you can run this pseudo-command:
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --tag <remote image repository> --push ./

View Manifest

Install Docker Buildx

Docker Install Build Tools

Once your image has been built and pushed, you can inspect the manifest by running: docker buildx imagetools inspect <remote image repository>
You should see a manifest printout with all your different architectures.

Install Docker Buildx

Clean up

Docker Install Build Dependencies

Finally, to clean up any extra disk space usage you can run docker buildx prune --all to reduce the Docker footprint.