State of the art on using .NET + Docker + Apple M1 #3848
Replies: 10 comments 11 replies
-
Note: On the Rosetta for Linux implementation present on macOS Ventura, .NET is functional.
I'd vote for approach 1. Servers on the cloud are not always x86 either. :) And then override via --platform when required, that's a task to be done by the user. |
Beta Was this translation helpful? Give feedback.
-
Very nice! This is great to see. I specifically posted this here in the hope that I'd learn something. This is better than I was expecting. 100% agree on all your points. I guess I need to upgrade to Ventura! |
Beta Was this translation helpful? Give feedback.
-
Got a cheatsheet on that @woachk? I installed Ventura but don't see a difference in behavior. I'm sure there is more to it. I looked around and didn't see any instructions anywhere. Also, why do you use |
Beta Was this translation helpful? Give feedback.
-
@richlander the cheat sheet is at https://developer.apple.com/documentation/virtualization/running_intel_binaries_in_linux_vms_with_rosetta?language=objc and https://developer.apple.com/documentation/virtualization/running_gui_linux_in_a_virtual_machine_on_a_mac?language=objc for the overall VM test project. (Adding Rosetta tidbits to it is quite trivial, as explained on the Rosetta page) Docker Desktop didn’t pick that up yet (and i’m currently writing an alternative to it anyway, because of licensing reasons notably, but not only that.) Why I use sudo is because the account that I’m calling Docker from isn’t part of the docker group, and as such can’t communicate with the dockerd daemon otherwise. |
Beta Was this translation helpful? Give feedback.
-
OK. I saw all that. I was wondering if there was something more productized from Docker. Good to know that I wasn't missing anything. OK, the usual reason for using Do you just install Docker on Linux (in the VM) and then re-direct your docker daemon to it? |
Beta Was this translation helpful? Give feedback.
-
Yeah, I just ssh or execute directly from the VM. |
Beta Was this translation helpful? Give feedback.
-
Oh. I see. I was fixated on docker desktop (for macOS). Thanks! |
Beta Was this translation helpful? Give feedback.
-
I'm not able to make it works using Rancher Desktop. |
Beta Was this translation helpful? Give feedback.
-
I'm surprised not to see any mention of using The complication is that the platform names .NET uses differ from the ones Go uses, so you have to use an annoying translation step. My FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0 as build
ARG BUILDPLATFORM
ARG TARGETPLATFORM
RUN mkdir /src /app
WORKDIR /src
COPY xlate-platform.sh .
RUN sh -x xlate-platform.sh
COPY . /src
RUN . ./.targetplatform; dotnet build -r $RUNTIME --no-self-contained -o /app
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build /app /app
#!/bin/sh
# .NET platform names are different from the ones Docker (i.e., Go) uses, so we
# can't just say dotnet build -r $TARGETPLATFORM. We have to transform the name
# and use the new one.
#
# This script does the mapping and creates a shell-sourceable file setting the
# variable $RUNTIME, for use in later RUN invocations; e.g.,
#
# RUN sh /xlate-platform.sh
# RUN . ./.targetplatform; dotnet publish -r $RUNTIME
# If $TARGETPLATFORM isn't defined, just assume amd64 linux.
case $TARGETPLATFORM in
"" | "linux/amd64")
RUNTIME=linux-x64 ;;
"linux/arm64")
RUNTIME=linux-arm64 ;;
*)
echo "Unsupported target platform \"$TARGETPLATFORM\""
exit 1
esac
echo "RUNTIME=$RUNTIME" > .targetplatform If there's a cleaner way of introducing |
Beta Was this translation helpful? Give feedback.
-
https://github.com/kurt-mueller-osumc/dotnet-amd64 This is a simple repository that demonstrates that commands like This is frustrating because I'd love to develop dotnet-isolated Azure Functions in docker on my Mac. |
Beta Was this translation helpful? Give feedback.
-
Update: See https://devblogs.microsoft.com/dotnet/improving-multiplatform-container-support/
A friend of mine asked for an update on what the story was on using .NET container images on Apple M1, assuming your goal was to deploy to x64 services in Azure (or pick your cloud).
There are various challenges, some specific to .NET and others more general. Windows Arm64 (with x64 emulation) is likely identical to this.
Here's what you want:
Today, it is very easy to fall into an Arm64-centric experience on M1 (for any app plat, not just .NET) and then push an Arm64 image to your registry, and then realize it won't work on your x64 cloud hardware. And then you are not sure what happened. Ughh.
Docker desktop defaults to Arm64
Docker on Apple M1 defaults to native architecture, which is Arm64. If the images you are pulling are multi-arch, you'll pull Arm64. If they are single-arch (x64 or Arm64), you'll pull whatever that arch is. That's the right design choice, but also confusing if your deployment target in x64.
All .NET images are multi-arch. We want to enable using the same tags in a variety of environments. That's all good. It however means that you'll always get Arm64 images by default, on Apple M1 machines. Other app platforms will be the same.
I'll show you, using dotnetapp:
That's clearly Arm64. We can force building as x64.
That's x64. That's what we wanted for this scenario.
That error is coming from Docker. It's there to tell that you're using emulation.
If you want to live the x64 lifestyle on your Apple M1 machine, you need to use the
--platform linux/amd64
flag. Perhaps there is a way to enable amd64 as the default. I don't know..NET isn't supported in QEMU
The bigger issue is that .NET isn't supported in QEMU. QEMU is the emulator that Docker Desktop uses for emulation, on both x64 (to emulate Arm64) and Arm64 (to emulate x64) machines.
I'll show you the problem, using aspnetapp (building and running as x64):
That's not pretty. We're hoping this QEMU issue gets resolved.
Workaround 1
Use the multi-arch tags as intended, just like in the aspnetapp Dockerfile. Run .NET in containers as Arm64 in Apple M1. .NET has excellent fidelity across architectures so you will get an experience. If you want to deploy images to a registry, either build with
--platform linux/amd64
or build in a CI service like GitHub Actions. They will naturally build as x64.This approach 100% works. You get the best performance on Apple M1 and straightforward gestures. It's the no-compromises option, since emulated QEMU will always be a lot slower than native architecture.
Workaround 2
This workaround forces your Dockerfile to produce x64 assets by default. The SDK runs in whatever arch is chosen for
docker build
. It enables you to pivot the final image pretty easily with a--build-arg
. The intent of this is thatdocker build
will produce an asset that runs in your x64 cloud by default.I modified the aspnetapp Dockerfile a bit:
I added the two
ARG
lines at the start and added$TAG
in the lastFROM
statement. By default, this Dockerfile will produce x64 images by default, even when built on Apple M1 machines.However, if you build that image and
docker run
it, it will still fail, as I demonstrated earlier. If you want a good dev experience, you can opt into building and running it as Arm64.Like this:
% docker build --pull --build-arg ARCH=arm64v8 -t aspnetapp . % docker run --rm -p 8000:80 aspnetapp
That approach allows you to build an image on your M1 machine -- x64 by default -- and then push to a registry. For some folks, that's might be what they are looking for.
Beta Was this translation helpful? Give feedback.
All reactions