Choosing a .NET Base Image: Chiseled, Distroless or Alpine
Distroless, Chiseled and Alpine are often treated as interchangeable, but they differ in C library and runtime model. This guide explains how to pick a .NET base image by libc, globalization, publish model and diagnostics before image size. It matters for anyone shipping containers, since a smaller image that breaks native libraries or culture formatting is incompatible rather than optimized.
Key points
- For a typical ASP.NET Core service, start with Ubuntu Chiseled; Azure Linux Distroless fits when the platform already runs on Azure Linux.
- If Alpine is chosen, publish with musl RIDs (linux-musl-x64, linux-musl-arm64) whenever native assets are involved.
- Minimal tags omit ICU and tzdata; choose the -extra tag for culture-sensitive or time-zone-dependent code.
- Match the repository to the publish model: aspnet for framework-dependent ASP.NET Core, runtime-deps for self-contained and Native AOT.
- Replace kubectl exec shell troubleshooting with health probes, a dotnet-monitor sidecar and ephemeral debug containers, tested before an incident.
- Preview tags are mutable; pin final serviced .NET 11 tags and immutable digests before production.
Distroless, Chiseled and Alpine are frequently lumped together, yet they differ. Alpine is built on musl, BusyBox and apk, while Distroless describes a runtime image with no shell or package manager; Ubuntu Chiseled and Azure Linux Distroless apply that model on glibc. Start with compatibility: which C library native assets need, ICU and time-zone needs, and the publish model, with image size last.
For a typical ASP.NET Core service the guidance favors Ubuntu Chiseled, with Azure Linux Distroless a sound choice when the platform already runs on Azure Linux, and Alpine reserved for deliberately tested musl support. Minimal variants omit ICU and tzdata, so culture-sensitive apps should use the -extra tags. Without a shell, troubleshooting depends on health probes, diagnostic sidecars and ephemeral debug containers prepared in advance.
Real-world use
- A minimal, non-root ASP.NET Core API running on Azure Kubernetes Service.
- A service that loads an imaging or database native library supporting only glibc.
- A Native AOT console tool built with the -aot SDK image and run on a runtime-deps base.
Why it matters
A smaller image only helps if libc, globalization and diagnostics still work inside the final container, so test those there before switching.
Related stories
- A secure enterprise chat with React, .NET 10 and Microsoft FoundryDEV Community: #dotnet1 d ago
- ASP.NET Core Authentication & Authorization Explained: What to Use, When, and How to Ship It SafelyDEV Community: #aspnetcore1 d ago
- Mastering Rate Limiting and Resource Governance for MCP Servers at ScaleDEV Community: #aspnetcore1 d ago