mcpField
D
dotnet-dockerfile

dotnet-dockerfile

github.com/jkappersCloud & DevOps045 installsUpdated 36w ago
Repository

About dotnet-dockerfile

.NET Dockerfile Generator is a skill for generating multi-stage Dockerfiles for .NET applications. It helps developers select an image and deployment pattern based on the .NET version and application type, including options such as chiseled images and Native AOT.

Key features

  1. 01Determine .NET version and application type
  2. 02Select standard, chiseled, or Native AOT patterns
  3. 03Generate multi-project solution build patterns
  4. 04Support self-contained deployment guidance
  5. 05Provide cache, digest-pinning, and verification guidance

Use cases

  1. 01Create a Dockerfile for an ASP.NET Core app
  2. 02Containerize a multi-project .NET solution
  3. 03Choose an image for Native AOT publishing

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/jkappers/agent-skills --skill dotnet-dockerfile

After installing, type/dotnet-dockerfilein Claude Code to confirm it loaded.

Details

From the project README

.NET Dockerfile Generator

Generate production-ready multi-stage Dockerfiles for .NET applications.

Workflow

  1. Determine .NET version (8, 9, or 10) from project file or ask user
  2. Identify project type: ASP.NET Core web app, API, worker service, or console app
  3. Locate project file path (e.g., src/MyApp/MyApp.csproj)
  4. Choose optimization: standard, chiseled (smaller), or native AOT (smallest/fastest startup)

Breaking Change in .NET 10: Ubuntu is now the default Linux distribution for all .NET container images. Debian images are no longer provided. Tags like 10.0, 10.0-noble, and 10.0-noble-chiseled all use Ubuntu 24.04 "Noble Numbat".

Image Selection Guide

ScenarioRuntime ImageCompressed Size
Standard ASP.NETaspnet:10.0~92 MB
Smaller footprintaspnet:10.0-alpine~52 MB
Production (recommended)aspnet:10.0-noble-chiseled~53 MB
Azure Linux distrolessaspnet:10.0-azurelinux3.0-distroless~55 MB
Self-containedruntime-deps:10.0-noble-chiseled~22 MB
Native AOTruntime-deps:10.0-noble-chiseled~12 MB

Chiseled images: Ubuntu-based, no shell, no package manager, non-root by default. Recommended for production.

Azure Linux distroless: Alternative to chiseled with Microsoft supply chain security. Similar benefits: no shell, non-root by default.

Standard Pattern

# syntax=docker/dockerfile:1

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

# Copy project files and restore (cache layer)
COPY *.csproj ./
RUN dotnet restore

# Copy source and publish
COPY . .
RUN dotnet publish -c Release -o /app/publish

# Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]

Multi-Project Solution Pattern

For solutions with multiple projects, copy all .csproj files first:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

# Copy solution and project files (cache layer)
COPY *.sln ./
COPY src/MyApp/*.csproj ./src/MyApp/
COPY src/MyApp.Core/*.csproj ./src/MyApp.Core/
COPY tests/MyApp.Tests/*.csproj ./tests/MyApp.Tests/
RUN dotnet restore

# Copy everything and publish
COPY . .
RUN dotnet publish src/MyApp -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]

Self-Contained Deployment

Bundles .NET runtime with app, enables smallest runtime-deps images:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish \
    --self-contained true \
    -r linux-x64

FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["./MyApp"]

Native AOT (Fastest Startup)

Compiles to native code. Smallest image (~12 MB), fastest startup:

FROM mcr.microsoft.com/dotnet/sdk:10.0-aot AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["./MyApp"]

Dedicated AOT SDK images include native compilation prerequisites:

  • mcr.microsoft.com/dotnet/sdk:10.0-aot (Ubuntu, also tagged 10.0-noble-aot)
  • mcr.microsoft.com/dotnet/sdk:10.0-alpine-aot
  • mcr.microsoft.com/dotnet/sdk:10.0-azurelinux3.0-aot

Requires in .csproj:

<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>

Limitations: No runtime reflection, not all libraries compatible.

Dockerfile-less Container Publishing

.NET 10 supports publishing containers directly from the SDK—no Dockerfile required:

# Publish to local container runtime
dotnet publish --os linux --arch x64 /t:PublishContainer

# Publish directly to a registry (no Docker needed)
dotnet publish --os linux --arch x64 /t:PublishContainer \
    -p ContainerRegistry=ghcr.io \
    -p ContainerRepository=myorg/myapp

# Multi-architecture publishing
dotnet publish /t:PublishContainer \
    -p ContainerRuntimeIdentifiers="linux-x64;linux-arm64"

Project file configuration:

<PropertyGroup>
  <!-- Control image format: Docker or OCI -->
  <ContainerImageFormat>OCI</ContainerImageFormat>
  <!-- Customize base image -->
  <ContainerBaseImage>mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled</ContainerBaseImage>
  <!-- Set image name and tag -->
  <ContainerRepository>myapp</ContainerRepository>
  <ContainerImageTag>1.0.0</ContainerImageTag>
</PropertyGroup>

Development Stage

Add a development stage for local dev with hot reload:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS base
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore

FROM base AS development
COPY . .
ENTRYPOINT ["dotnet", "watch", "run"]

FROM base AS build
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS production
WORKDIR /app
COPY --from=build /app/publish .
USER app
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]

Build development: docker build --target development -t myapp:dev .

Cache Optimization

Use BuildKit cache mount for NuGet packages:

RUN --mount=type=cache,target=/root/.nuget/packages \
    dotnet restore

SHA Pinning for Production

Pin exact image digests for reproducibility and security:

FROM mcr.microsoft.com/dotnet/sdk:10.0@sha256:abc123... AS build

To find the current digest, run:

docker pull mcr.microsoft.com/dotnet/sdk:10.0
docker inspect --format='{{index .RepoDigests 0}}' mcr.microsoft.com/dotnet/sdk:10.0

Required .dockerignore

Always create .dockerignore:

**/bin/
**/obj/
**/.vs/
**/.vscode/
**/node_modules/
**/*.user
**/*.userosscache
**/*.suo
*.md
.git
.gitignore
Dockerfile*
docker-compose*

Verification Checklist

  • SDK image for build stage, runtime/aspnet for production
  • .NET 8+ uses port 8080 (not 80)
  • Copy .csproj files before source for cache efficiency
  • Use USER app for non-root execution (chiseled images have this user)
  • Chiseled images have no shell—use exec form only, no && chains in final stage
  • Include .dockerignore to exclude build artifacts
  • Match runtime identifier (-r linux-x64) for self-contained builds
  • Consider SHA pinning for production reproducibility

Comments

Markdown supported