Docker for .NET
Package a .NET app into a container image, run it locally, and orchestrate it with its database using Docker Compose.
13 min read
You will learn
- Explain images, containers and registries
- Write a multi-stage Dockerfile for an ASP.NET Core app
- Run an app and its dependencies with docker compose
- Know about .NET's built-in container publishing
Images and containers
You met the idea in Track 7: a container image bundles your app with its runtime and dependencies so it runs identically on every machine. The vocabulary:
| Term | Meaning |
|---|---|
| Image | A read-only, layered template: OS base + .NET runtime + your published app |
| Container | A running instance of an image, isolated from others |
| Dockerfile | The recipe for building an image |
| Registry | Where images are stored and shared: Docker Hub, GitHub Container Registry, Azure Container Registry |
Install Docker Desktop (or Podman) to build and run containers locally.
A multi-stage Dockerfile
# ---- build stage: full SDK ----
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY Shop.Api/Shop.Api.csproj Shop.Api/
RUN dotnet restore Shop.Api/Shop.Api.csproj # cached unless the .csproj changes
COPY . .
RUN dotnet publish Shop.Api/Shop.Api.csproj -c Release -o /app/publish
# ---- runtime stage: small ASP.NET Core runtime image ----
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
COPY --from=build /app/publish .
USER app # don't run as root
EXPOSE 8080
ENTRYPOINT ["dotnet", "Shop.Api.dll"]- The build stage uses the large SDK image; only the published output is copied into the small runtime image.
- Copying the
.csprojand restoring first lets Docker cache the restore layer between builds. - Add a
.dockerignore(bin/,obj/,.git/) so they don't bloat the build context. - .NET 8 images listen on port 8080 by default and include a non-root
appuser.
docker build -t shop-api .
docker run -p 8080:8080 -e ConnectionStrings__Shop="Host=..." shop-apiConfiguration comes in through environment variables — the same Section__Key convention as before.
No Dockerfile needed
The .NET SDK can build container images directly:
dotnet publish --os linux --arch x64 /t:PublishContainer -p ContainerImageName=shop-apiDocker Compose: your local environment
Your API needs PostgreSQL and Redis. Compose starts them all together:
# docker-compose.yml
services:
api:
build: .
ports: ["8080:8080"]
environment:
ConnectionStrings__Shop: "Host=db;Database=shop;Username=shop;Password=dev-only-password"
ConnectionStrings__Redis: "cache:6379"
depends_on: [db, cache]
db:
image: postgres:16
environment:
POSTGRES_USER: shop
POSTGRES_PASSWORD: dev-only-password
POSTGRES_DB: shop
volumes: ["pgdata:/var/lib/postgresql/data"] # survives container restarts
cache:
image: redis:7
volumes:
pgdata:docker compose up -d # start everything in the background
docker compose logs -f api
docker compose down # stop and remove the containers (the volume keeps the data)Services reach each other by name (db, cache) on Compose's private network.
.NET Aspire
For local development of multi-service .NET apps, .NET Aspire orchestrates projects and containers (databases, Redis, queues) from C#, wires up connection strings, and gives you a dashboard with logs, metrics and traces.
Containers in production
Containers are disposable: write persistent data to databases, object storage or volumes — never only to the container's filesystem. In production, an orchestrator (Kubernetes, Azure Container Apps, AWS ECS) pulls your image from a registry, runs replicas, checks health endpoints and rolls out new versions.
Key takeaways
- An image is a template; a container is a running instance; registries store images.
- Use multi-stage Dockerfiles: build with the SDK image, run on the slim runtime image as a non-root user.
- Pass configuration through environment variables; keep data in volumes or external services.
- Docker Compose (or .NET Aspire) runs your app with its dependencies locally.
Quiz
4 questions · 3 correct to pass1.What's the difference between an image and a container?
2.Why use a multi-stage Dockerfile for .NET?
3.What does docker compose help with?
4.Where should a container keep data that must survive restarts, like a database's files?
To complete this lesson
- ○ Pass the quiz (3/4 correct)