Multi-Stage Dockerfiles for .NET Services

Cutting image size from 1.2 GB to 210 MB and why chiseled images matter for pull time on Kubernetes.

Our gateway image started as FROM mcr.microsoft.com/dotnet/sdk:8.0 — fine for dev, painful in prod.

Before

FROM mcr.microsoft.com/dotnet/sdk:8.0
WORKDIR /app
COPY . .
RUN dotnet publish -c Release -o out
ENTRYPOINT ["dotnet", "out/Gateway.dll"]

Image size: 1.2 GB. Every deploy pulled the full SDK layer across 30 nodes.

After

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Gateway.csproj", "./"]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false

FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled AS final
WORKDIR /app
COPY --from=build /app/publish .
USER $APP_UID
ENTRYPOINT ["dotnet", "Gateway.dll"]

Image size: 210 MB. Pull time on cold nodes dropped from ~90s to ~15s.

docker , dotnet , images · Docker , .NET

More in Docker