• Courses
  • TutorialsFree
  • Learning Paths
  • Blogs
  • Authors
  • Dometrain Pro
  • Shopping Basket

    Your basket is empty

  • Business Portal
  • Introduction to Docker for .NET Developers

    8/15/2025

    Containers package your app with everything it needs and run it the same way everywhere. No fiddling with machine-specific setups, no "works on my machine" jokes.

    This guide keeps things hands-on: images vs containers, writing a Dockerfile,docker run basics, and a small docker-compose.yml to run your API plus a database.


    Images vs containers (quick mental model)

    • Image → a read-only snapshot of your app and its dependencies (like a recipe).
    • Container → a running instance of that image (like a prepared dish). You can start/stop/remove containers without changing the image.

    Build an image once, run containers many times.


    A tiny .NET Minimal API to containerize

    Create a folder HelloApi and drop this Program.cs inside:

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    
    app.MapGet("/", () => "API is up");
    app.MapGet("/hello/{name}", (string name) => new { message = $"Hello, {name}" });
    
    app.Run();
    

    .dockerignore (do this first)

    Prevent large and irrelevant files from bloating your image:

    bin/
    obj/
    *.user
    *.suo
    .vscode/
    .idea/
    **/*.Secrets.json
    

    Dockerfile (multi-stage build for .NET 9)

    Create Dockerfile next to your .csproj:

    # 1) Build stage
    FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
    WORKDIR /src
    
    # copy csproj first to take advantage of layer caching
    COPY HelloApi.csproj .
    RUN dotnet restore
    
    # copy the rest and publish
    COPY . .
    RUN dotnet publish -c Release -o /app /p:UseAppHost=false
    
    # 2) Runtime stage
    FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime
    WORKDIR /app
    EXPOSE 8080
    ENV ASPNETCORE_URLS=http://+:8080
    
    COPY --from=build /app ./
    ENTRYPOINT ["dotnet", "HelloApi.dll"]
    

    Why this layout?

    • Multi-stage keeps the final image small (SDK isn’t in the runtime layer).
    • Copying the .csproj before source allows restore caching until dependencies change.

    Build and run

    # build the image (note the trailing dot)
    docker build -t helloapi:dev .
    
    # run a container mapping port 8080 in the container to 8080 on your machine
    docker run --rm -p 8080:8080 helloapi:dev
    

    Browse to http://localhost:8080/hello/Dotnet and you should see JSON.

    Handy flags:

    • --rm removes the container when it exits.
    • -e KEY=VALUE sets environment variables (useful for connection strings, etc.).

    Common Dockerfile instructions (short list)

    • FROM — base image (e.g., aspnet:9.0, sdk:9.0).
    • WORKDIR — sets the working folder for subsequent commands.
    • COPY — copies files into the image.
    • RUN — executes a command at build time (e.g., dotnet publish).
    • ENV — defines environment variables.
    • EXPOSE — documents the port your app listens on.
    • ENTRYPOINT / CMD — what runs when the container starts.

    Docker Compose: API + Postgres locally

    Create docker-compose.yml at the solution root to run multiple containers together:

    services:
      api:
        build:
          context: .
          dockerfile: Dockerfile
        image: helloapi:dev
        ports:
          - "8080:8080"
        environment:
          ASPNETCORE_URLS: http://+:8080
          ConnectionStrings__Default: Host=db;Port=5432;Database=hello;Username=postgres;Password=postgres
        depends_on:
          - db
    
      db:
        image: postgres:16-alpine
        environment:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: hello
        volumes:
          - pgdata:/var/lib/postgresql/data
        ports:
          - "5432:5432"
    
    volumes:
      pgdata:
    

    Run everything:

    docker compose up --build
    
    • depends_on starts the database before the API (you should still add retry logic in your app).
    • The pgdata volume keeps your database files between restarts.

    Dev workflow tips

    • Rebuild fast: keep your Dockerfile steps cache-friendly (copy .csproj, restore, then copy source).
    • Hot reload (local only): run dotnet watch on your host, and use a bind mount to share files into the container if you need the app to run inside Docker during dev:
      services:
        api:
          volumes:
            - ./:/src
          command: ["dotnet", "watch", "--project", "/src/HelloApi.csproj", "run", "--urls", "http://0.0.0.0:8080"]
      
    • Prune old stuff: docker system prune -f removes stopped containers and dangling images. Careful when using this as this will delete images and containers.

    Quick troubleshooting

    • Port already in use
      Change the host mapping: -p 9090:8080 and browse http://localhost:9090.

    • File not found at runtime
      Ensure you COPY files into the runtime stage (or from the build stage). Check paths.

    • Slow builds
      Make sure .dockerignore is in place and you copy the .csproj separately to benefit from restore caching.

    • “Works outside Docker, fails inside”
      Check environment variables. Containers are isolated; they do not see your host’s env unless you pass them in (-e or environment: in Compose).


    A tiny checklist

    • [ ] Use a multi-stage Dockerfile for .NET.
    • [ ] Keep a tidy .dockerignore.
    • [ ] Treat images as immutable—rebuild for changes.
    • [ ] Map ports explicitly and pass env vars consciously.
    • [ ] Use Compose when you have more than one container.
    • [ ] Persist data with volumes in Compose.

    More!

    # one-liners you’ll remember
    docker build -t app:dev .
    docker run --rm -p 8080:8080 app:dev
    docker compose up --build
    docker ps -a
    docker logs <container>
    docker exec -it <container> sh
    

    About the Author

    Nick Chapsas

    Nick Chapsas

    Nick Chapsas is a .NET & C# content creator, educator and a Microsoft MVP for Developer Technologies with years of experience in Software Engineering and Engineering Management.

    He has worked for some of the biggest companies in the world, building systems that served millions of users and tens of thousands of requests per second.

    Nick creates free content on YouTube and is the host of the Keep Coding Podcast.

    View all courses by Nick Chapsas

    What's New

    What's new in C# 14
    blog

    What's new in C# 14

    This guide covers every new C# 14 feature, explains its benefits, and provides practical code examples to help you navigate how you can use them.

    Learn More
    Let's Build It: AI Chatbot with RAG in .NET Using Your Data
    course

    Let's Build It: AI Chatbot with RAG in .NET Using Your Data

    Build a Retrieval-Augmented Generation (RAG) chatbot that can answer questions using your data.

    Learn More
    Working with Large Language Models
    tutorial

    Working with Large Language Models

    Learn how to work with Large Language Models (LLMs). Understand the fundamentals of how GPT works, the transformer architecture, and master prompt engineering techniques to build AI agents.

    Learn More
    From Zero to Hero: SignalR in .NET
    course

    From Zero to Hero: SignalR in .NET

    Enable enterprise-grade real-time communication for your web apps with SignalR.

    Learn More
    Deep Dive: Solution Architecture
    course

    Deep Dive: Solution Architecture

    Master solution architecture and turn business needs into scalable, maintainable systems.

    Learn More
    Migrating: ASP.NET Web APIs to ASP.NET Core
    course

    Migrating: ASP.NET Web APIs to ASP.NET Core

    A step-by-step process to migrate ASP.NET Web APIs from .NET Framework to ASP.NET Core.

    Learn More
    Getting Started: Caching in .NET
    course

    Getting Started: Caching in .NET

    Let's make the hardest thing in programming easy for .NET software engineers.

    Learn More
    From Zero to Hero: Testing with xUnit in C#
    course

    From Zero to Hero: Testing with xUnit in C#

    Learn how to test any codebase in .NET with the latest version of xUnit, the industry-standard testing library.

    Learn More
    Create a ChatGPT Console AI Chatbot in C#
    blog

    Create a ChatGPT Console AI Chatbot in C#

    This walkthrough is your hands-on entry point to create a basic C# console application that talks to ChatGPT using the OpenAI API.

    Learn More