This document demonstrates how to publish .NET console apps as container images. The workflows for ASP.NET Core apps are largely the same. These instructions are part of a container workshop, which details fundamental workflows for using .NET in containers.
Related:
The easiest way to publish an app to a container image is with .NET SDK OCI image publish. Console apps require installing a NuGet package to use OCI publish. The NuGet package isn't required for ASP.NET Core apps.
Create the app.
$ dotnet new console -n hello-dotnet
$ cd hello-dotnet
$ dotnet run
Hello, World!Change Program.cs (so that it prints the name of the operating system):
using System.Runtime.InteropServices;
Console.WriteLine($"Hello, {RuntimeInformation.OSDescription} on {RuntimeInformation.OSArchitecture}!");Re-run:
$ dotnet run
Hello, Ubuntu 24.04.3 LTS on X64!Your operating system will likely be different.
Publish and run app image.
$ dotnet publish -t:PublishContainer
$ docker run --rm hello-dotnet
Hello, Ubuntu 24.04.3 LTS on X64!Inspect the image:
$ docker images hello-dotnet
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-dotnet latest 53444c11ae48 About a minute ago 203MBIt is straightforward to create smaller images using Alpine, Ubuntu Chiseled, and various .NET SDK publishing options.
Summary:
- Ubuntu is used for default base images starting with .NET 10.
- .NET 8+ images come with a new user, app.
dotnet publishsets the user toapp.- The user is set via UID, as explained in Running non-root .NET containers with Kubernetes.
Images are configured to use a non-root user, following secure by default principles.
$ docker run --rm --entrypoint bash hello-dotnet -c "cat /etc/os-release | head -n 1"
PRETTY_NAME="Ubuntu 24.04.3 LTS"
$ docker run --rm --entrypoint bash hello-dotnet -c "whoami"
app
$ docker run --rm --entrypoint bash hello-dotnet -c "cat /etc/passwd | grep app"
app:x:1654:1654::/home/app:/bin/sh
$ docker inspect hello-dotnet | grep User
"User": "1654",ContainerUser=root can be used to configure images to use the root user.
Audit the image, with anchore/syft.
$ docker run --rm anchore/syft mcr.microsoft.com/dotnet/runtime:8.0 | grep dotnet | wc -l
1
$ docker run --rm anchore/syft mcr.microsoft.com/dotnet/runtime:8.0 | grep deb | wc -l
92There are 1 .NET and 92 .deb packages/libraries installed.