I am trying to build and run docker image with dotnet on arm64
architecture. I can see that the image was properly built as a MULTI-PLATFORM
, see this Docker Hub image. It contains both amd64
and arm64
.
I have a K8s cluster that is running on arm64
, so I expected this should be compatible. However, running this image gives me:
exec /opt/czertainly/entry.sh: exec format error
which seems to be wrong architecture according to multiple sources. I am not able to figure out what is wrong.
This is the Dockerfile:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
ARG TARGETARCH
WORKDIR /app
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG TARGETARCH
WORKDIR /
COPY ["src/Czertainly.Auth/Czertainly.Auth.csproj", "Czertainly.Auth/"]
RUN dotnet restore "Czertainly.Auth/Czertainly.Auth.csproj" -a $TARGETARCH
COPY . .
WORKDIR "/src/Czertainly.Auth"
RUN dotnet build "Czertainly.Auth.csproj" -c Release -o /app/build -a $TARGETARCH
FROM build AS publish
ARG TARGETARCH
RUN dotnet publish "Czertainly.Auth.csproj" -c Release -o /app/publish -a $TARGETARCH
FROM base AS final
ARG TARGETARCH
MAINTAINER CZERTAINLY <[email protected]>
RUN addgroup --system --gid 10001 czertainly && adduser --system --home /opt/czertainly --uid 10001 --ingroup czertainly czertainly
#RUN addgroup --group czertainly --gid 10001 && adduser --uid 10001 --gid 10001 "czertainly"
COPY --from=publish /app/publish /opt/czertainly
COPY ./docker /opt/czertainly
WORKDIR /opt/czertainly
ENV COMPlus_EnableDiagnostics=0
ENV AUTH_DB_CONNECTION_STRING=
ENV AUTH_CREATE_UNKNOWN_USERS=false
ENV AUTH_CREATE_UNKNOWN_ROLES=false
USER 10001
ENTRYPOINT ["/opt/czertainly/entry.sh"]
Can it be connected somehow with the entry.sh
? This is the content of entry.sh
, it is ok from my perspective:
#!/bin/bash
czertainlyHome="/opt/czertainly"
source ${czertainlyHome}/static-functions
log "INFO" "Launching the Auth service"
dotnet Czertainly.Auth.dll
Any clue what can be wrong?
Build is executed using GitHub action:
name: Publish Docker image
on:
push:
branches: [develop]
tags:
- '*'
workflow_dispatch:
jobs:
push_to_registry:
name: Push Docker images
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Install Cosign
uses: sigstore/[email protected]
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Log in to Harbor
uses: docker/login-action@v3
with:
registry: harbor.3key.company
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: |
3keycompany/czertainly-auth
harbor.3key.company/czertainly/czertainly-auth
tags: |
type=ref,event=tag
type=raw,value=develop-latest
type=sha,prefix=develop-,format=long
- name: Build and push Docker image
uses: docker/build-push-action@v5
id: build-and-push
with:
context: .
platforms: linux/amd64,linux/arm64
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Sign images with a key
run: |
images=""
for tag in ${TAGS}; do
images+="${tag}@${DIGEST} "
done
cosign sign --yes --key env://COSIGN_PRIVATE_KEY ${images}
env:
TAGS: ${{ steps.meta.outputs.tags }}
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}
- name: Push README to Docker Hub
uses: christian-korneck/update-container-description-action@v1
env:
DOCKER_USER: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASSWORD }}
with:
destination_container_repo: 3keycompany/czertainly-auth
provider: dockerhub
- name: Push README to Harbor
uses: christian-korneck/update-container-description-action@v1
env:
DOCKER_USER: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKER_PASS: ${{ secrets.DOCKER_HUB_PASSWORD }}
with:
destination_container_repo: harbor.3key.company/czertainly/czertainly-auth
provider: harbor2
2
Answers
Follow the platforms in this build:
The
base
stage is configured with--platform=$BUILDPLATFORM
which means the filesystem used for that image comes from the architecture of the build platform. The same goes for the build stage. Then the publish and final stages use the filesystem of those previous stages which means you always output an image containing binaries of the build platform, regardless of the target platform you assign to the image.If you want to build a proper multi-platform image, the resulting image cannot have binaries in it that are compiled for the build platform, they must all be compiled for the target platform.
You can see this by inspecting the layers of the recently generated image:
You can see the first several layers are identical because they include binaries from the same image, binaries that are platform specific because they are for the build platform.
It seems to be due to the way you define ENTRYPOINT, try :