Closed mthalman closed 1 year ago
I've been in a good dozen of these threads, all closed, referencing each other with a "tracked in this issue) link...
What is the actual, definitive, .Net 7 solution to building a docker image for AMD64 on an m1/m2 mac?
I've been in a good dozen of these threads, all closed, referencing each other with a "tracked in this issue) link...
What is the actual, definitive, .Net 7 solution to building a docker image for AMD64 on an m1/m2 mac?
@douglasg14b. For me, the solution is to use the .NET 8 preview SDK to build the docker image, but still use .NET 7 as the runtime image.
Excerpt of the Dockerfile (removed a lot of stuff for brevity)
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build
ARG TARGETARCH
WORKDIR /src
RUN dotnet restore "project.csproj" -a $TARGETARCH
RUN dotnet build "project.csproj" -c Release -o /app/build -a $TARGETARCH
FROM build AS publish
RUN dotnet publish "project.csproj" -c Release -o /app/publish -a $TARGETARCH
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "project.dll"]
And the Docker image is being built using a GitHub action like:
- name: Build and push image
uses: docker/build-push-action@v4
with:
file: path/to/Dockerfile
platforms: linux/amd64,linux/arm64
The only problem with using 8 SDK for 7 project is inability to run dotnet test
as part of the build step.
I asked a question to .net's docker experts. Hopefully we get a response:
The solution they posted does work indeed
FROM --platform=linux/amd64 mcr.microsoft.com/dotnet/sdk:8.0-preview AS build
Does not seem to work, the build still hangs on restoring.
@douglasg14b the solution works for me... maybe confirm you're not getting fooled by cache and use --no-cache
argument.
If not, maybe post your Dockerfile, that might help someone identify the issue.
@turowicz doesn't this work?
dotnet test -a $TARGETARCH
My dockerfile that works:
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/nightly/sdk:8.0-preview
ARG TARGETARCH
ARG BUILDPLATFORM
WORKDIR /home/app
# Settings
ENV TZ=Etc/UTC
ENV DEBIAN_FRONTEND=noninteractive
ENV DOTNET_TieredPGO=1
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
RUN echo "Target: $TARGETARCH"
RUN echo "Build: $BUILDPLATFORM"
# Import ASP.NET Core runtime and .NET runtime for 7.0
COPY --from=mcr.microsoft.com/dotnet/aspnet:7.0 /usr/share/dotnet/shared /usr/share/dotnet/shared
ADD src ./src
ADD lib ./lib
RUN dotnet restore src -a $TARGETARCH
RUN for file in $(ls src/*/*.csproj); do dotnet build $file --no-restore -c Release -a $TARGETARCH ; done
RUN if [ "linux/$TARGETARCH" = "$BUILDPLATFORM" ] ; then dotnet test src/VU.Platform.Test/VU.Platform.Test.csproj -c Release --no-build --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura -a $TARGETARCH ; fi
7.0.302 is out!
Problem persist:
> [linux/arm64 build 4/7] RUN dotnet restore "src/EspUpdater/EspUpdater.csproj":
#0 12.89 /usr/share/dotnet/sdk/7.0.302/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.TargetFrameworkInference.targets(55,5): error MSB4184: The expression "[MSBuild]::GetTargetFrameworkVersion(net7.0, 2)" cannot be evaluated. Exception has been thrown by the target of an invocation. [/src/src/EspUpdater/EspUpdater.csproj]
------
Dockerfile:8
--------------------
6 | WORKDIR /src
7 | COPY ["src/EspUpdater/EspUpdater.csproj", "src/EspUpdater/"]
8 | >>> RUN dotnet restore "src/EspUpdater/EspUpdater.csproj"
9 | COPY . .
10 | WORKDIR "/src/src/EspUpdater"
--------------------
ERROR: failed to solve: process "/bin/sh -c dotnet restore \"src/EspUpdater/EspUpdater.csproj\"" did not complete successfully: exit code: 1
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["src/EspUpdater/EspUpdater.csproj", "src/EspUpdater/"]
RUN dotnet restore "src/EspUpdater/EspUpdater.csproj"
COPY . .
WORKDIR "/src/src/EspUpdater"
RUN dotnet build "EspUpdater.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "EspUpdater.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "EspUpdater.dll"]
I can confirm that this isn't working as expected for me with
7.0.302
. Only with8.0-preview
ornightly
.https://github.com/dotnet/dotnet-docker/issues/4388#issuecomment-1556980087
Retracting this... it does work as intended. When replacing the image, I removed the --platform
argument, as @turowicz suggested. Apologies.
--platform=$BUILDPLATFORM
same problem, I'm not sure which issue is getting tracked actively. you can check the debug here:
https://github.com/dotnet/runtime/issues/78340#issuecomment-1576159800
the problem persists even with mcr.microsoft.com/dotnet/sdk:7.0.302-jammy-arm64v8
(which should be an identical image anyways)
I don't want to use 8.0-preview or nightly for production. thank you for your understanding
Can't build any ARM images. Either it eats all 32 GiB of RAM and crashes, or gives errors like this:
System.NullReferenceException: Object reference not set to an instance of an object. [/src/dotnet-arm.csproj]
#0 4.754 /usr/share/dotnet/sdk/7.0.304/NuGet.targets(1238,7): error MSB4018: at InvokeStub_MSBuild.get_TargetOutputs(Object, Object, IntPtr*) [/src/dotnet-arm.csproj]
#0 4.754 /usr/share/dotnet/sdk/7.0.304/NuGet.targets(1238,7): error MSB4018: at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) [/src/dotnet-arm.csproj]
Simple reproducer from scratch:
mkdir dotnet-arm
cd dotnet-arm
dotnet new console
nano Dockerfile
, paste
FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build WORKDIR /src COPY dotnet-arm.csproj . RUN dotnet restore COPY . . RUN dotnet build -c Release -o /app/build
FROM build AS publish RUN dotnet publish -c Release -o /app/publish
FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "dotnet-arm.dll"]
* `docker buildx build --platform linux/arm64 .`
**Environment**
* Ubuntu 22.04.2 LTS
* Docker version 24.0.2, build cb74dfc
@ptupitsyn as posted previously in this issue, the .NET 7 SDK does not work in qemu. You need to use the .NET 8 SDK.
@zivkan the latest SDK does work in qemu (arm). This is how we do it.
@turowicz the official .NET 7 release notes have a qemu heading, which explicitly states that it's not supported: https://github.com/dotnet/core/blob/main/release-notes/7.0/supported-os.md#qemu
I don't know how to reconcile you saying it works, compared to @ptupitsyn's logs showing the same error as before (and the SDK version is the one released yesterday), and the release notes saying qemu is not supported (although .NET 8's release notes also says qemu is not supported).
Are there any active issues in dotnet/runtime regarding this issue? The link posted last week was also closed last week as being an unsupported qemu issue. NuGet runs on the runtime, so when the runtime doesn't work, I don't know what NuGet can change to resolve the issue. Of all the stack traces I've seen reported, NuGet has never even been on the call stack. This issue is still useful to find links to other issues, but additional reports of it not working isn't providing the NuGet team with anything actionable. I hope that people from the runtime team are watching this issue and getting notifications about new comments, but issues in dotnet/runtime (and also to qemu directly) are closer to the teams who can actually fix the problem.
@zivkan and yet I run docker builds on a x86 computer for multiarch platforms (amd64/arm64) and it all works fine since version of the sdk 7.0.304. It has been stated even in this thread that once the new 7 SDK comes out that workflow will be supported. I have posted here on 19th of May that the new SDK is out in confirmation that it started to work. I then changed my dockerfiles to use 7.0-dev instead of 8.0-preview.
@zivkan and yet I run docker builds on a x86 computer for multiarch platforms (amd64/arm64) and it all works fine since version of the sdk 7.0.304. It has been stated even in this thread that once the new 7 SDK comes out that workflow will be supported. I have posted here on 19th of May that the new SDK is out in confirmation that it started to work. I then changed my dockerfiles to use 7.0-dev instead of 8.0-preview.
Two things are true: .NET doesn't support QEMU and you can get this workflow to work with 7.0.304. The reason this workflow can work is because the pattern described in https://devblogs.microsoft.com/dotnet/improving-multiplatform-container-support offers build-time improvements that allow you to run the SDK in the native architecture (no emulation) to produce an application intended for another architecture. But the application container cannot be run on the host system because it would require emulation.
yes correct. actually they answered already on the issue I've linked. so for me this can stay closed
@ptupitsyn as posted previously in this issue, the .NET 7 SDK does not work in qemu. You need to use the .NET 8 SDK.
@zivkan same problem on .NET 8:
> [linux/arm64 build 4/6] RUN dotnet restore:
#0 5.417 Determining projects to restore...
#0 5.466 /usr/share/dotnet/sdk/8.0.100-preview.5.23303.2/NuGet.targets(1241,7): error MSB4018: The "MSBuild" task failed unexpectedly. [/src/dotnet-arm.csproj]
#0 5.466 /usr/share/dotnet/sdk/8.0.100-preview.5.23303.2/NuGet.targets(1241,7): error MSB4018: System.NullReferenceException: Object reference not set to an instance of an object. [/src/dotnet-arm.csproj]
#0 5.466 /usr/share/dotnet/sdk/8.0.100-preview.5.23303.2/NuGet.targets(1241,7): error MSB4018: at InvokeStub_MSBuild.get_TargetOutputs(Object, Object, IntPtr*) [/src/dotnet-arm.csproj]
#0 5.466 /usr/share/dotnet/sdk/8.0.100-preview.5.23303.2/NuGet.targets(1241,7): error MSB4018: at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr) [/src/dotnet-arm.csproj]
Reproducer here: https://gist.github.com/ptupitsyn/d9d7930c4f0d1840919ced5367bffc5e
@ptupitsyn Have you taken a close look at the blog post linked above? I only glanced over it, but I don't see anything obviously different between what it suggests and your repro.
@mthalman @turowicz are either of you able to help?
The exception stack posted is exactly the same as the stack when hitting the qemu bug. It's also before any of NuGet's assemblies are on the call stack, so the NuGet team isn't in a position to fix the issue.
Personally, I'm more interested in the out of memory scenario, since that's something I make changes to improve, but I need a memory dump. Does anyone know how we can get a crash dump out of a docker image? @ptupitsyn by any chance, if you restore on a host machine (so, not in docker), does it also use 30+ GB of RAM? That will make it easier to get a memory dump
My process is as follows, I build several docker images on my CI and deliver the last one to the deployment host. The CI agents are x86 with QEMU enabled.
ALL STEPS BELOW take --platform=amd64,arm64
1) Build SDK (for engineers to work with "VS Code Remote Containers" and for the initial CI Build) registry.surveily.com/developer.dotnet:7.0-sdk
ARG dotnet
FROM mcr.microsoft.com/devcontainers/dotnet:dev-${dotnet}-jammy
ARG TARGETARCH
ARG BUILDPLATFORM
WORKDIR /
# Settings
ENV TZ=Etc/UTC
ENV DEBIAN_FRONTEND=noninteractive
ENV DOTNET_TieredPGO=1
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV PATH=/root/.yarn/bin:/root/.dotnet/tools:$PATH
RUN echo "Target: $TARGETARCH"
RUN echo "Build: $BUILDPLATFORM"
# Import Chromium
ADD src/VU.Infrastructure.Resources.Build.Sdk/vision.sdk.dockerfile.debian.list /etc/apt/sources.list.d/debian.list
ADD src/VU.Infrastructure.Resources.Build.Sdk/vision.sdk.dockerfile.chromium.pref /etc/apt/preferences.d/chromium.pref
# Register Chromium repo
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 605c66f00d6c9793 && \
apt-key export 0d6c9793 | sudo gpg --dearmour -o /usr/share/keyrings/debian-bullseye.gpg
# Base SDK
RUN apt-get update && apt-get upgrade -y --no-install-recommends && apt-get install -y --no-install-recommends ssh apt-transport-https ca-certificates software-properties-common gnupg2 gnupg-agent build-essential git && \
# Installation
sed 's/main$/main universe/' -i /etc/apt/sources.list && \
# Apply Timezone
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \
# Add GPG keys
install -m 0755 -d /etc/apt/keyrings && \
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com A1715D88E1DF1F24 40976EAF437D05B5 3B4FE6ACC0B21F32 A6616109451BBBF2 && \
curl https://baltocdn.com/helm/signing.asc | apt-key add - && \
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
chmod a+r /etc/apt/keyrings/docker.gpg && \
# Setup repositories
echo "deb https://baltocdn.com/helm/stable/debian/ all main" | tee /etc/apt/sources.list.d/helm-stable-debian.list && \
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list && \
# Init PPAs
add-apt-repository ppa:git-core/ppa -y && \
# Install Dependencies
apt-get update && apt-get install -y --no-install-recommends vim xorg libssl-dev libxrender-dev wget gdebi libpng* libpng-dev gcc make autoconf libtool pkg-config nasm default-jre-headless chromium chromium-driver && \
# Install Docker
curl https://get.docker.com | sh && \
# Install Kubectl
apt-get install -y --no-install-recommends kubectl && \
# Install Helm
apt-get install -y --no-install-recommends helm && \
# Install Node
curl -sL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get install -y --no-install-recommends nodejs && \
# Install Yarn
curl -o- -L https://yarnpkg.com/install.sh | bash && \
# Clean up
ldconfig && \
apt-get autoremove -y && \
apt-get clean -y && \
rm -rf /var/lib/apt/lists/*
USER vscode
2) Build Runtime (for the CI to put the packaged dotnet apps on to so they can be deployed to hosts) registry.surveily.com/developer.dotnet:7.0
ARG dotnet
FROM ubuntu/dotnet-deps:${dotnet}_edge
ARG TARGETARCH
ARG BUILDPLATFORM
WORKDIR /app
USER root
# Settings
ENV TZ=Etc/UTC
ENV DEBIAN_FRONTEND=noninteractive
ENV DOTNET_TieredPGO=1
RUN echo "Target: $TARGETARCH"
RUN echo "Build: $BUILDPLATFORM"
3) Build & test my application registry.surveily.com/platform
FROM --platform=$BUILDPLATFORM registry.surveily.com/developer.dotnet:7.0-sdk
ARG TARGETARCH
ARG BUILDPLATFORM
WORKDIR /home/vscode
USER vscode
RUN echo "Target: $TARGETARCH"
RUN echo "Build: $BUILDPLATFORM"
# Restore
COPY --chown=vscode:vscode src/*.sln ./src/
COPY --chown=vscode:vscode src/*/*.csproj ./src/
COPY --chown=vscode:vscode src/nuget.config ./src/
RUN for file in $(ls src/*.csproj); do mkdir -p ${file%.*}/ && mv $file ${file%.*}/; done
RUN dotnet restore src -a $TARGETARCH
# Build
ADD --chown=vscode:vscode src ./src
ADD --chown=vscode:vscode lib ./lib
RUN for file in $(ls src/*/*.csproj); do dotnet build $file --no-restore -c Release -a $TARGETARCH ; done
# Test
RUN if [ "linux/$TARGETARCH" = "$BUILDPLATFORM" ] ; then dotnet test src/VU.Platform.Test/VU.Platform.Test.csproj -c Release --no-build --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura -a $TARGETARCH ; fi
4) Package a shippable container (using images from 2. and 3.)
ARG commit
FROM registry.surveily.com/platform:${commit} AS build-env
ARG project
ARG TARGETARCH
ARG BUILDPLATFORM
ENV PROJECT=${project}
RUN echo "Target: $TARGETARCH"
RUN echo "Build: $BUILDPLATFORM"
RUN dotnet publish src/${project}/${project}.csproj -c Release -o out/ --self-contained true -a $TARGETARCH
RUN cd out && ln -s $PROJECT surveily
# Build runtime image
FROM registry.surveily.com/developer.dotnet:7.0
WORKDIR /app
COPY --from=build-env /home/vscode/out .
USER app
# Prepare Entry
ENTRYPOINT ["/app/surveily"]
5) Result images from step 4. work on AMD64, ARM64 and L4T (Jetson)
NOTICE
In step 3. I am enforcing amd64 platform (FROM --platform=$BUILDPLATFORM
, where $BUILDPLATFORM
is amd64
because the CI agent is that) but I tell the package step to produce a $TARGETARCH. This is the trick that you need. In step 4. then I am copying those binaries onto the shippable multiarch image.
@zivkan the blog post helped! Thank you, I should have paid more attention. Minimal working gist: https://gist.github.com/ptupitsyn/1c0f4d6186f63c0f09689745242ebee5 It works with .NET 7 projects, which is perfect.
The difference is in -a $TARGETARCH
for dotnet
commands and FROM --platform=$BUILDPLATFORM
.
We created a totally new .net webapplication and it does not work.
docker buildx build --platform=linux/arm64 -f ".\WebApplication2\Dockerfile" --build-arg CODEARTIFACT_AUTH_TOKEN --force-rm -t yourname "."
FROM --platform=$BUILDPLATFORM [mcr.microsoft.com/dotnet/aspnet:7.0](http://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](http://mcr.microsoft.com/dotnet/sdk:7.0) AS build
WORKDIR /src
COPY ["WebApplication2/WebApplication2.csproj", "WebApplication2/"]
RUN dotnet restore "WebApplication2/WebApplication2.csproj"
COPY . .
WORKDIR "/src/WebApplication2"
RUN dotnet build "WebApplication2.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "WebApplication2.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication2.dll"]
This is the error we get, any help will be appreciated.
@stealthAngel the error message is about running some container, not dotnet restore
, which is this issue's subject.
You'll have more luck getting support at https://github.com/dotnet/dotnet-docker
Has anyone solved the issue? why this issue has been closed?
docker buildx build --platform linux/amd64,linux/arm64 -t{website}/$dockerImageName -f Dockerfile --push .
gives me
=> [linux/amd64 build-env 4/6] RUN dotnet restore 830.4s
and non-stop.
the dockerfile is simple with
FROM mcr.microsoft.com/dotnet/sdk:8.0 as build-env
WORKDIR /src
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /publish
FROM mcr.microsoft.com/dotnet/aspnet:8.0 as runtime
WORKDIR /publish
COPY --from=build-env /publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "xxx.dll"]
runs from Mac M2, which arm64 and I need to push both arm64 and amd64 images to my docker hub. it is working normally with all other docker files but .net
I've stiched up a solution from numerous answers. Below is my setup, which works on Mac M1
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG TARGETARCH
WORKDIR /src
COPY ["nuget.config", "."]
COPY ["MyApp.Web/MyApp.Web.csproj", "MyApp.Web/"]
RUN dotnet restore "MyApp.Web/MyApp.Web.csproj" -a $TARGETARCH
COPY . .
WORKDIR "/src/MyApp.Web"
RUN dotnet build "MyApp.Web.csproj" -c Release -o /app/build -a $TARGETARCH
FROM build AS publish
RUN dotnet publish "MyApp.Web.csproj" -c Release -o /app/publish -a $TARGETARCH --self-contained false --no-restore
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApp.Web.dll"]
And I run the build like so:
docker build -f MyApp.Web/Dockerfile . --tag=myappweb:latest --platform linux/amd64
Hope this helps!
Copied from post by @zimbres at https://github.com/dotnet/sdk/issues/28971:
When try to build arm64 containers using .Net7 results in a error on restore step.
Just create a new web api for example with .Net7 as target framework and try to build it with buildx. For amd64 build works just fine.
Docker Version
Docker Info