DeveloperHA / Learn / Docker + .NET
Docker + .NET learning path

Docker for a .NET app, without the mystery

Understand images, containers and a production-minded multi-stage Dockerfile for ASP.NET Core.

Beginner to practical30–45 min4 lessons

Outcome: Read a Dockerfile line by line, build a smaller .NET image, pass configuration safely and connect the app to Compose services.

Your local progress0 / 4 complete

Docker becomes less intimidating when each instruction has one job. Start with the mental model, then read the Dockerfile as a build pipeline.

Work through the path

Open a card when you need it. Marking a lesson complete is optional and stays only in this browser.

1An image is a recipe; a container is a running instance

Mental model4 min

An image packages filesystem layers and metadata; a container is an isolated process created from that image.

Building an image does not start your application. Running a container creates a process with the image filesystem plus networking, environment and volume settings.

The same image can run in different environments with different configuration. Keep environment-specific values outside the image.

Try it

Build, run, stop and remove the container. Notice that the image remains available for another run.

Watch outA container is not a tiny virtual machine; normally it runs one main application process.
Generate a local Compose stack →
Example
# Build an image
docker build -t orders-api:dev .

# Map host port 8080 to container port 8080
docker run --rm -p 8080:8080 orders-api:dev

2Read a .NET Dockerfile line by line

Dockerfile8 min

A multi-stage Dockerfile uses the SDK to publish, then copies only the published app into a smaller runtime image.

The first stage needs compilers and NuGet tooling. The final stage needs only the ASP.NET runtime and published output.

Copy project files and restore before copying the rest of the source when the project layout allows it, so cache reuse survives normal code edits.

Try it

For each line, say whether it affects build dependencies, runtime behavior or both.

Watch outThe SDK and runtime tags must match the supported application version; verify image updates in your release process.
Build the companion Compose file →
Example
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Orders.Api/Orders.Api.csproj", "Orders.Api/"]
RUN dotnet restore "Orders.Api/Orders.Api.csproj"
COPY . .
WORKDIR /src/Orders.Api
RUN dotnet publish -c Release -o /app/publish --no-restore

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app
EXPOSE 8080
ENV ASPNETCORE_HTTP_PORTS=8080
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "Orders.Api.dll"]

3Keep configuration outside the image

Configuration5 min

Build once and configure at runtime through environment variables, secret mounts or the platform secret store.

An image can be promoted from test to production only when environment-specific values are injected at runtime. Never bake passwords, provider keys or private certificates into a Dockerfile layer.

ASP.NET Core maps environment variables using double underscores, so ConnectionStrings__Default can override a nested setting.

Try it

Replace the connection string with a placeholder and move the real value into your local secret mechanism or orchestrator.

Watch outEnvironment variables can still leak through process inspection or logs; use the platform secret facility for sensitive values.
Check configuration risks →
Example
docker run --rm \
  -p 8080:8080 \
  -e ASPNETCORE_ENVIRONMENT=Production \
  -e ConnectionStrings__Default="Server=db;Database=Orders;..." \
  orders-api:dev

4Use Compose to describe local dependencies

Compose7 min

Compose gives a local .NET app a repeatable network, database, volume and health-check definition.

depends_on controls startup ordering but does not by itself mean a database is ready. A health check and application retry behavior make a local stack more realistic.

Keep local credentials clearly marked as development-only. Production needs a deliberate secret and backup strategy.

Try it

Add the file to a small API and watch database health before calling the API.

Watch outHealth checks improve orchestration signals; the app should still handle transient database unavailability.
Generate the Compose starting point →
Example
services:
  api:
    build: .
    ports:
      - "8080:8080"
    environment:
      ConnectionStrings__Default: Host=db;Database=orders;Username=app;Password=dev-only
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d orders"]
      interval: 5s
      retries: 10

No lesson matches that phrase.

Related tools

Turn the concept into a working example with the browser-based tools.

Need a second pair of eyes?

When the quick answer turns into an architecture or delivery decision, use a fixed-price review or talk to DeveloperHA.

See packages All learning paths