I am trying to build a docker image and publish it to Github Container Registery that can be started on my Raspberry Pi with Ubuntu 22.04, ARM64/v8.
Build for amd64 forks perfectly, but whenever i want to build it for ARM I am getting
...
#13 [build 5/8] RUN dotnet restore "./Imagenerator.Api/Imagenerator.Api.csproj"
#13 6.095 Segmentation fault (core dumped)
#13 ERROR: process "/bin/sh -c dotnet restore \"./Imagenerator.Api/Imagenerator.Api.csproj\"" did not complete successfully: exit code: 139
------
> [build 5/8] RUN dotnet restore "./Imagenerator.Api/Imagenerator.Api.csproj":
6.095 Segmentation fault (core dumped)
------
Dockerfile:15
--------------------
13 | COPY ["Directory.Build.props", "."]
14 | COPY ["Imagenerator.Api/Imagenerator.Api.csproj", "Imagenerator.Api/"]
15 | >>> RUN dotnet restore "./Imagenerator.Api/Imagenerator.Api.csproj"
16 | COPY . .
17 | WORKDIR "/src/Imagenerator.Api"
--------------------
ERROR: failed to solve: process "/bin/sh -c dotnet restore \"./Imagenerator.Api/Imagenerator.Api.csproj\"" did not complete successfully: exit code: 139
Docker file
ARG DOTNET_VERSION=8.0
FROM mcr.microsoft.com/dotnet/aspnet:$DOTNET_VERSION AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
ARG DOTNET_VERSION
FROM mcr.microsoft.com/dotnet/sdk:$DOTNET_VERSION AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Directory.Build.props", "."]
COPY ["Imagenerator.Api/Imagenerator.Api.csproj", "Imagenerator.Api/"]
RUN dotnet restore "./Imagenerator.Api/Imagenerator.Api.csproj"
COPY . .
WORKDIR "/src/Imagenerator.Api"
RUN dotnet build "./Imagenerator.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Imagenerator.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Imagenerator.Api.dll"]
Workflow file
name: Imagenerator Build & Publish
on:
# release:
# types: [published]
workflow_dispatch
env:
REGISTRY: ghcr.io
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ${{ vars.DOCKERFILE_PATH }}
push: true
tags: |
"${{ vars.IMAGE_NAME }}:latest"
platforms: ${{ vars.BUILD_PLATFORM }}
build-args: |
"DOTNET_VERSION=${{ vars.DOTNET_VERSION }}"
Variables
BUILD_PLATFORM=linux/arm64/v8
DOCKERFILE_PATH=Imagenerator.Api/Dockerfile
DOTNET_VERSION=8.0-jammy
IMAGE_NAME=ghcr.io/managerbot-net/imagenerator
I am expecting to build & publish docker image to Github registery. I tried to change architectures to ARM64/v7, play with the .NET version to use something different than 8.0-jammy but with no success
The segmentation fault occurs because .NET doesn't support running in emulation with QEMU, which is what is being used here on the build agents in this case.
Try this Dockerfile instead:
ARG DOTNET_VERSION=8.0
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:$DOTNET_VERSION AS base
ARG TARGETARCH
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
ARG DOTNET_VERSION
FROM mcr.microsoft.com/dotnet/sdk:$DOTNET_VERSION AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Directory.Build.props", "."]
COPY ["Imagenerator.Api/Imagenerator.Api.csproj", "Imagenerator.Api/"]
RUN dotnet restore -a $TARGETARCH "./Imagenerator.Api/Imagenerator.Api.csproj"
COPY . .
WORKDIR "/src/Imagenerator.Api"
RUN dotnet build -a $TARGETARCH "./Imagenerator.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish -a $TARGETARCH "./Imagenerator.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Imagenerator.Api.dll"]
The only changes I made here are the use of --platform=$BUILDPLATFORM in the FROM instruction and -a $TARGETARCH in the restore and publish commands.
When targeting arm64 from your workflow, this uses an amd64 version of the sdk image to build the app, which matches the host, but then uses the arm64 version of the aspnet image to create your final image. This pattern is explained in detail in https://devblogs.microsoft.com/dotnet/improving-multiplatform-container-support/.