Finding smaller Docker images for your ASP.NET web applications

Posted: (EET/GMT+2)

 

If you need a smaller Docker image for an ASP.NET Core 8 or 9 application, start by comparing the official Microsoft runtime images instead of guessing from the tag name.

For a normal framework-dependent ASP.NET Core app, the base image usually starts from mcr.microsoft.com/dotnet/aspnet:8.0. That said, your Dockerfile could look something like this:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080

That image is convenient, but it is not always the smallest option. You can compare it with the Alpine and chiseled variants:

docker pull mcr.microsoft.com/dotnet/aspnet:8.0
docker pull mcr.microsoft.com/dotnet/aspnet:8.0-alpine
docker pull mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled

docker images mcr.microsoft.com/dotnet/aspnet

For production, the chiseled image is often the interesting one. It is a smaller, more locked down image with no shell and no package manager.

FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled AS base
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "YourApp.dll"]

Tip: starting with .NET 8, ASP.NET Core container images listen on the HTTP port 8080 by default, not port 80. To build and run, say:

docker build -t yourapp .
docker run --rm -p 8080:8080 yourapp

If the application does not start on the chiseled image, test the regular image first. The usual causes are native dependencies, globalization settings, certificate handling, or scripts that assume /bin/sh exists.

Handy tip: keep the SDK image only in the build stage. The final image should use an ASP.NET runtime image, not mcr.microsoft.com/dotnet/sdk.

For the smallest practical production image, test mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled first. Use Alpine when you know your native dependencies work well there, and use the regular image when debuggability matters more than image size.

Hope this helps!