Dockerfile for .NET Core Application

I am preparing a post for Creating a Dockerfile for a .NET Core application which is a common and important task for containerization. 

I'll provide you reference with a multi-stage Dockerfile that efficiently builds and publishes your .NET Core application, resulting in a smaller, more secure final image.

This Dockerfile assumes a typical .NET Core web application structure where your .csproj file is located in a subdirectory (e.g., src/WebApp/WebApp.csproj). Please adjust the paths (src/WebApp/) if your project structure is different.

Here is the Dockerfile:


# Stage 1: Build the application
# This stage uses the .NET SDK image to compile and publish your application.
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build

# Set the working directory inside the container. All subsequent commands will run relative to this directory.
WORKDIR /src

# Copy the .csproj file(s) first and restore dependencies.
# This is a crucial optimization for Docker caching. If only source code changes,
# but project dependencies (defined in .csproj) remain the same, Docker can reuse
# the layer from `dotnet restore`, speeding up subsequent builds.
# Adjust the path 'src/WebApp/WebApp.csproj' to match your actual project file location.
COPY ["src/WebApp/WebApp.csproj", "src/WebApp/"]

# Restore NuGet packages. '--no-cache' is generally not needed with multi-stage builds
# as the build stage is ephemeral, but it's good practice for clarity.
RUN dotnet restore "src/WebApp/WebApp.csproj"

# Copy the rest of the application source code into the container.
COPY . .

# Change the working directory to your specific project's directory.
# This ensures that 'dotnet publish' runs in the correct context.
WORKDIR /src/src/WebApp

# Publish the application.
# -c Release: Builds in Release configuration.
# -o /app/publish: Publishes the output to the /app/publish directory inside the container.
# --no-restore: Prevents re-running restore, as it was already done in a previous step.
RUN dotnet publish "WebApp.csproj" -c Release -o /app/publish --no-restore

# Stage 2: Create the final runtime image
# This stage uses a smaller, more secure .NET ASP.NET Core Runtime image.
# It only contains the necessary components to run the application, not the SDK.
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final

# Set the working directory for the final application.
WORKDIR /app

# Copy the published output from the 'build' stage to the 'final' runtime image.
COPY --from=build /app/publish .

# Expose the ports that your application listens on.
# ASP.NET Core applications typically listen on port 80 (HTTP) and 443 (HTTPS).
EXPOSE 80
EXPOSE 443

# Define the entry point for the application.
# This command will be executed when the container starts.
# Replace 'WebApp.dll' with the actual name of your compiled application's DLL.
ENTRYPOINT ["dotnet", "WebApp.dll"]



Explanation of the Dockerfile:

  • Multi-Stage Build: This Dockerfile uses a multi-stage build approach, which is a best practice for Dockerizing applications.

    • build stage: This stage uses the mcr.microsoft.com/dotnet/sdk:8.0 image, which contains all the tools needed to compile your .NET Core application. It compiles the code and publishes the ready-to-run binaries to a specific directory (/app/publish).

    • final stage: This stage uses the much smaller mcr.microsoft.com/dotnet/aspnet:8.0 runtime image. It only copies the published output from the build stage. This results in a significantly smaller final Docker image, which is faster to pull, more secure (less attack surface), and more efficient to deploy.

  • Layer Caching Optimization:

    • COPY ["src/WebApp/WebApp.csproj", "src/WebApp/"] and RUN dotnet restore: By copying only the project file(s) first and running dotnet restore, Docker can cache this layer. If only your source code changes (but not your project dependencies), Docker won't need to re-run dotnet restore, saving build time.

  • WORKDIR: Sets the working directory inside the container for subsequent commands.

  • COPY . .: Copies all the remaining source code from your local directory into the container.

  • dotnet publish: Compiles your application and prepares it for deployment.

    • -c Release: Specifies the Release build configuration.

    • -o /app/publish: Specifies the output directory for the published application.

    • --no-restore: Prevents dotnet publish from re-running dotnet restore, as we already did it in an earlier step.

  • EXPOSE 80 and EXPOSE 443: Informs Docker that the container listens on these specified network ports at runtime. This is purely informational; you'll still need to map ports when running the container.

  • ENTRYPOINT ["dotnet", "WebApp.dll"]: Defines the command that will be executed when the container starts. It tells Docker to run your compiled .NET application's DLL. Remember to replace WebApp.dll with the actual name of your application's main DLL.

How to Build and Run Your Docker Image:

  1. Navigate to your project's root directory: Open your terminal or PowerShell and change the directory to where your .sln file and the Dockerfile are located.

  2. Build the Docker image:

    Bash
    docker build -t mydotnetapp:latest .
    
    • -t mydotnetapp:latest: Tags your image with the name mydotnetapp and the tag latest. You can choose any name.

    • .: Specifies the build context, which is the current directory.

  3. Run the Docker container:

    Bash
    docker run -p 8080:80 -d mydotnetapp:latest
    
    • -p 8080:80: Maps port 8080 on your host machine to port 80 inside the container. If your app listens on 443, you might also map -p 8443:443.

    • -d: Runs the container in detached mode (in the background).

This setup provides a robust and efficient way to containerize your .NET Core application! 

No comments: