Hello there!
It is a short article about how to build multi-arch docker images in GitHub Actions. For example, you have the following file (the default Dockerfile
, generated by IDE):
and want to build two images. One for linux/amd64
and another one for linux/arm64
, then you need to follow the documentation of setup-buildx-action. You need to install QEMU and Buildx and you will be able to build multi-arch images. For example, here is the workflow yaml file:
Important parts of this yaml file are the setup of QEMU and the platrorms
options in the Build and push
step. After these changes, GitHub Actions should build two images for specified platforms but unfortunately, it doesn’t work for .NET. It will throw you an error:
Error: buildx failed with: ERROR: failed to solve: process “/bin/sh -c dotnet restore “WebApplication1.csproj"" did not complete successfully: exit code: 135
To fix it, you need to specify one parameter in your Dockerfile
: --platform=$BUILDPLATFORM
, so updated Dockerfile
will look like:
BUILDPLATFORM
, TARGETOS
, TARGETARCH
are built-in parameters, and --platform=$BUILDPLATFORM
pins a stage to host architecture. So, the build
stage will always be amd64
(because GitHub Actions runner is amd64
) whereas all other images will be amd64
or arm64
(depends what image you are building). It helps to speed up a build process because .NET compiler supports cross-compilations and you can create one executable (IL binary) and run it on different platforms/runtimes. Also, there is an important part - --runtime $TARGETOS-$TARGETARCH
in dotnet restore
. It is needed to restore the “right” versions of packages, especially when your application relies on native libraries, for example, SQLite
. But after dotnet restore
, we can use our default approach to build and publish the application. Copy it to the final image because it doesn’t have --platform=$BUILDPLATFORM
it will have an appropriate runtime for the current architecture.
Also, you need to keep in mind that this approach relies on the cross-platform nature of .NET and IL, if you need to publish a self-contained application or native, then you might need to remove --platform=$BUILDPLATFORM
to form Docker builder to build a new image for each platform.