⚠Commit 2d13e55 tells about working Docker image. It actually refers to the fact of obtaining a complete multi-platform Docker image. As it was actually complied for ARM64 architecture, it will likely not work on AMD64 hosts.
Setup
When we build on a machine where Docker was installed with Docker Desktop, everything is ready to go.
On other OS (especially Linux) extra content needs to be installed.
docker run --privileged --rm tonistiigi/binfmt --install all
Builder
Since version 18.09 there is a new builder bundled with Docker.
It comes with a default builder so that it could be ready to use. That said the documentation recommends to create and use a custom one for the sake of ease of use. Then custom builders can be deleted and recreated at will to restart fresh in case of trouble.
We use buildx and a custom builder.
docker buildx create --name dotnetbuilder --driver docker-container --bootstrap --driver-opt "network=dotnet" --use
--driver-opt "network=dotnet" means we will use the dotnet custom docker network with that builder.
Useful commands are
docker buildx ls: Listing the available builders can be handy especially to check that it is up and running
docker buildx use {builderName}: The ls command above displays a star next to the default builder. Hence we can check if it needs to be changed with the use command
docker buildx inspect --bootstrap: Displays information about a builder. Handy --bootstrap switch allows to start a builder should it be in inactive state.
docker buildx build {options}: The main command. Builds in Docker cache is neither --push (Push to Docker registry, likely Docker hub) nor --load (load in the local instance of Docker) are given. A warning message will appear then.
Dockerfile
The principle is to build from AMD64 images yet being able to build images for different platforms especially ARM64.
⚠ NB: The different dotnet CLI command explicitely mention ARM64 as a target. Hence as is we are compiling for ARM64 architecture yet containerize into images for different platforms. The string to represent platform between Docker platforms and .NET RID differ.
| Architecture |
.NET |
Docker |
| AMD64 |
linux-amd64 |
linux/amd64 |
| ARM64 |
linux-arm64 |
linux/arm64 |
This is currently the missing part to make fully functional multi-platform images
Docker uses 2 variables to manage cross-building for several architectures.
BUILDPLATFORM: Refers to the platform from which be build the images
TARGETPLATFORM: Refers to the platforms we aim for.
We can specify the platform for an image in a Dockerfile by precising the --platform switch before the image name.
In the following Dockerfile, we take advantage of those informations to prepare a container for the target platform on the .NET runtime image.
For the time being, it is just preparing a target location to put our application and exposing the necessary ports.
On the next image we enforce the use of the build platform on the .NET SDK image.
This is important because otherwise specifying target platforms that differ from your building platform may lead to issues otherwise.
The SDK image indeed has dotnet CLI for us to use.
There are sequential steps in order to publish a .NET application from the CLI.
- Restore: It is about gathering dependencies in which NuGet packages.
- Build: It is about compiling a runnable executable most likely for development purpose.
- Publish: It is about compiling the application and gathering any assets so it becomes ready to deploy.
Kind of like Maven, asking for a further stage will trigger previous stages.
Hence build will trigger a restore as well as asking for a publish will trigger a build (and by extension a restore).
However in the context of pipelines it is advised to run those commands separately let alone to segregate the details for each step.
Notice that for the restore step we only need the .NET project file. So for the sake of build performance, only that file is copied to the SDK image. The rest is copied for the need of the build later on.
The final step is to transfer the published application to the target .NET runtime image and precise what application should be run when the container is run.
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["rasp-test/rasp-test.csproj", "."]
RUN dotnet restore "rasp-test.csproj" -r linux-arm64
COPY rasp-test/. .
RUN dotnet build "rasp-test.csproj" -c Release -r linux-arm64 --no-self-contained -o /app/build
FROM build AS publish
RUN dotnet publish "rasp-test.csproj" -r linux-arm64 -c Release --no-self-contained -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "rasp-test.dll"]
Locally I ran the following command:
docker buildx build --platform linux/amd64,linux/arm64 -t uchitesting/rasp-test:multi -f .\Dockerfile-multi . --push
Source:
Multi-platform images @Docker Docs
Setup
When we build on a machine where Docker was installed with Docker Desktop, everything is ready to go.
On other OS (especially Linux) extra content needs to be installed.
docker run --privileged --rm tonistiigi/binfmt --install allBuilder
Since version 18.09 there is a new builder bundled with Docker.
It comes with a default builder so that it could be ready to use. That said the documentation recommends to create and use a custom one for the sake of ease of use. Then custom builders can be deleted and recreated at will to restart fresh in case of trouble.
We use buildx and a custom builder.
docker buildx create --name dotnetbuilder --driver docker-container --bootstrap --driver-opt "network=dotnet" --useUseful commands are
docker buildx ls: Listing the available builders can be handy especially to check that it is up and runningdocker buildx use {builderName}: Thelscommand above displays a star next to the default builder. Hence we can check if it needs to be changed with theuse commanddocker buildx inspect --bootstrap: Displays information about a builder. Handy--bootstrapswitch allows to start a builder should it be in inactive state.docker buildx build {options}: The main command. Builds in Docker cache is neither--push(Push to Docker registry, likely Docker hub) nor--load(load in the local instance of Docker) are given. A warning message will appear then.Dockerfile
The principle is to build from AMD64 images yet being able to build images for different platforms especially ARM64.
Docker uses 2 variables to manage cross-building for several architectures.
BUILDPLATFORM: Refers to the platform from which be build the imagesTARGETPLATFORM: Refers to the platforms we aim for.We can specify the platform for an image in a Dockerfile by precising the
--platformswitch before the image name.In the following Dockerfile, we take advantage of those informations to prepare a container for the target platform on the .NET runtime image.
For the time being, it is just preparing a target location to put our application and exposing the necessary ports.
On the next image we enforce the use of the build platform on the .NET SDK image.
This is important because otherwise specifying target platforms that differ from your building platform may lead to issues otherwise.
The SDK image indeed has dotnet CLI for us to use.
There are sequential steps in order to publish a .NET application from the CLI.
Kind of like Maven, asking for a further stage will trigger previous stages.
Hence
buildwill trigger arestoreas well as asking for apublishwill trigger abuild(and by extension arestore).However in the context of pipelines it is advised to run those commands separately let alone to segregate the details for each step.
Notice that for the restore step we only need the .NET project file. So for the sake of build performance, only that file is copied to the SDK image. The rest is copied for the need of the build later on.
The final step is to transfer the published application to the target .NET runtime image and precise what application should be run when the container is run.
Locally I ran the following command:
docker buildx build --platform linux/amd64,linux/arm64 -t uchitesting/rasp-test:multi -f .\Dockerfile-multi . --pushSource:
Multi-platform images @Docker Docs