DEV Community

Cover image for Building a Linux Based Minimal and Efficient .NET 8 Application Docker Image
Mofajjal Rasul
Mofajjal Rasul

Posted on • Edited on

1

Building a Linux Based Minimal and Efficient .NET 8 Application Docker Image

In this article, we will walk through a multi-stage Dockerfile optimized for building and running a .NET 8 application targeted for Linux. This setup emphasizes performance, size, and compatibility, particularly for applications running in Linux-based environments.


Dockerfile Breakdown

Stage 1: Build Stage

FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
ARG BUILD_CONFIGURATION=Release
ARG RUNTIME=linux-musl-x64
WORKDIR /src
Enter fullscreen mode Exit fullscreen mode

We start with the official .NET 8 SDK image (mcr.microsoft.com/dotnet/sdk:8.0-alpine) for the build stage. The alpine variant is chosen for its small size and compatibility with the lightweight Linux musl runtime.

  • BUILD_CONFIGURATION: Set to Release for optimized production builds.
  • RUNTIME=linux-musl-x64: Targets the linux-musl runtime, specifically tailored for Alpine Linux. This ensures compatibility with musl-based systems commonly used in containerized environments like Kubernetes.
COPY ["MyApplication.WebAPI/MyApplication.WebAPI.csproj", "MyApplication.WebAPI/"]
RUN dotnet restore "./MyApplication.WebAPI/MyApplication.WebAPI.csproj" -r "$RUNTIME"
Enter fullscreen mode Exit fullscreen mode

We copy only the project file first to take advantage of Docker’s caching mechanism, which avoids re-downloading dependencies unless the csproj file changes. The runtime (linux-musl-x64) ensures the restored packages are compatible with the target Linux environment.

COPY . .
Enter fullscreen mode Exit fullscreen mode

After restoring dependencies, the full source code is copied. This order reduces unnecessary rebuilds during development.

RUN dotnet publish "./MyApplication.WebAPI/MyApplication.WebAPI.csproj" \
    -c "$BUILD_CONFIGURATION" \
    -r "$RUNTIME" \
    --self-contained false \
    -o /app/publish \
    /p:UseAppHost=false \
    /p:PublishReadyToRun=true
Enter fullscreen mode Exit fullscreen mode

Here’s a breakdown of the key options used in the dotnet publish command:

  • -r "$RUNTIME": Ensures the published app is optimized for the specified runtime (linux-musl-x64).
  • --self-contained false: Keeps the application lightweight by relying on the shared .NET runtime instead of bundling it.
  • /p:PublishReadyToRun=true: Precompiles assemblies to improve startup performance, which is crucial for production workloads.

Stage 2: Final Stage

FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine
Enter fullscreen mode Exit fullscreen mode

The runtime stage uses mcr.microsoft.com/dotnet/aspnet:8.0-alpine, which is purpose-built for hosting ASP.NET Core applications and is significantly smaller than the SDK image.

ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT false
RUN apk add --no-cache icu-libs tzdata
Enter fullscreen mode Exit fullscreen mode
  • DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: Set to false to enable full globalization support, such as culture-specific formatting.
  • icu-libs: Installed to provide ICU libraries required for globalization.
  • tzdata: Adds timezone data, ensuring the application handles time zones correctly.
WORKDIR /app
USER app
EXPOSE 8080
Enter fullscreen mode Exit fullscreen mode
  • USER app: Enhances security by running the application as a non-root user.
  • EXPOSE 8080: Exposes port 8080, commonly used for ASP.NET Core applications.
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApplication.WebAPI.dll"]
Enter fullscreen mode Exit fullscreen mode

The published application is copied from the build stage, and the entry point specifies the main DLL file to start the application.


Complete Dockerfile

# Build Stage
FROM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
ARG BUILD_CONFIGURATION=Release
ARG RUNTIME=linux-musl-x64
WORKDIR /src

# Copy only project files for caching
COPY ["MyApplication/MyApplication.csproj", "MyApplication/"]

# Restore dependencies
RUN dotnet restore \
    "./MyApplication/MyApplication.csproj" \
    -r "$RUNTIME"

# Copy the entire source after restore to prevent re-restoring
COPY . .

# Publish the application
RUN dotnet publish \
    "./MyApplication/MyApplication.csproj" \
    -c "$BUILD_CONFIGURATION" \
    -r "$RUNTIME" \
    --self-contained false \
    -o /app/publish \
    /p:UseAppHost=false \
    /p:PublishReadyToRun=true

# Final Stage
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine

ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT false
RUN apk add --no-cache icu-libs tzdata

WORKDIR /app
USER app
EXPOSE 8080

COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApplication.dll"]
Enter fullscreen mode Exit fullscreen mode

Why Use the linux-musl Runtime?

Targeting Linux Images

The linux-musl-x64 runtime is specifically designed for environments that use musl as the standard C library (such as Alpine Linux). By targeting this runtime:

  • Compatibility: Ensures the application runs seamlessly in musl-based environments like Kubernetes or Docker containers using Alpine Linux.
  • Size Efficiency: Produces smaller binaries compared to glibc-based Linux distributions.
  • Performance: Musl is known for its lightweight and efficient design, making it ideal for containerized workloads.

Why Alpine Linux?

Alpine Linux is widely used in containerized environments due to its:

  • Small Size: A base image is typically less than 5 MB.
  • Security: A minimal surface area reduces vulnerabilities.
  • Performance: Optimized for resource-constrained environments.

Conclusion

This Dockerfile is optimized for creating lightweight and efficient containers for .NET 8 applications targeted for Linux. By using the linux-musl-x64 runtime and Alpine Linux, you ensure a small, compatible, and high-performing application that's ready for modern cloud-native deployments.

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay