.NET & DevOps Engineer | Cloud Specialist | Team Enabler
My name is Miha and I've been tinkering with computers for some time now. I remember getting Pentium 100 in the late '90s and that's how it all started.
Specialities:
by Miha J.
Nowadays, we run .NET 5,6,7,8, … apps on the Linux operating system almost without any issues. We can use Alpine MUSL linux Docker image, put the self contained .NET executable in it, install few libraries and we are good to go.
Default architecture we normally use is AMD64
with switch --platform linux-must-64
in the dotnet publish
command. We can run the containers in Kubernetes on Linux, or we run it on Linux VM. No problems there.
Lately we have some developers using MacBook M2 with ARM CPU architecture, and we were struggling to run this docker container on it. You will probably not run your production on MacBook, but you can already run your apps on ARM virtual machines, so it makes sense to do that.
And because of that, we decided we needed to built a multi-arch docker image of our .NET 8 application with docker buildx. We are using MUSL Alpine Linux
docker image for AMD64 and ARM64 and we build .NET assemblies outside of docker build process. You could use multi-staged Dockerfile build process.
These are the steps:
First you need to check if you have buildx
module installed:
docker buildx build --help
Then create a new builder:
docker buildx create --name my-app-builder --use --bootstrap
This will run buildx container on your machine used to build the multi-arch docker images.
AMD64 CPU architecture:
dotnet publish "./App.csproj" -c Release --framework net8.0 --self-contained True --runtime linux-musl-x64 -o "./publish/amd64" -p:PublishTrimmed=False -p:PublishSingleFile=True -p:IncludeNativeLibrariesForSelfExtract=True -p:DebugType=None -p:DebugSymbols=False -p:EnableCompressionInSingleFile=True
To define the AMD64 CPU architecture use the
--runtime linux-musl-x64
.
ARM64 CPU architecture:
dotnet publish "./App.csproj" -c Release --framework net8.0 --self-contained True --runtime linux-musl-arm64 -o "./publish/arm64" -p:PublishTrimmed=False -p:PublishSingleFile=True -p:IncludeNativeLibrariesForSelfExtract=True -p:DebugType=None -p:DebugSymbols=False -p:EnableCompressionInSingleFile=True
To define the ARM64 CPU architecture use the
--runtime linux-musl-arm64
.
FROM --platform=$TARGETPLATFORM alpine:3.19 AS base
EXPOSE 80
ARG TARGETARCH
WORKDIR /app
COPY --chmod=755 ["publish/${TARGETARCH}/App", "./"]
ENTRYPOINT ["./App"]
TARGETPLATFORM is injected from the
--platform linux/amd64,linux/arm64
below in the buildx command.
TARGETARCH is defined by the build process and has values of
amd64
orarm64
. Assemblies from step 2 are copied to the correct image.
Now you can run the build process below. It will build a multi-arch Docker image for amd64
and arm64
.
--tag
assignes a tag to an image.--file
references a Dockerfile above.--platform
defines the platforms you want to build your apps for.--push
command automatically pushes the built docker image to your selected docker registry.docker buildx build --tag my.dockerhub.com/app:latest --file ./Dockerfile --platform linux/amd64,linux/arm64 --push .
Now that you have an multi-arch docker image you can run it on ARM64 CPU system with:
docker run -p 80:80 --name app --platform linux/arm64 -t my.dockerhub.com/app:latest
I hope this will help you to run your .NET apps in docker for multiple CPU architectures :)!
tags: docker, - docker - buildx, - multi-arch - images, - multi - architecture, - arm64, - amd64, - dotnet, - .NET