Below is an example Dockerfile
that we recommend at Depot for building images for .NET ASP.NET Core applications.
# syntax=docker/dockerfile:1
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY src/WebApp/WebApp.csproj src/WebApp/
COPY src/WebApp.Core/WebApp.Core.csproj src/WebApp.Core/
COPY Directory.Build.props ./
COPY *.sln ./
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet restore
COPY src/ src/
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet publish "src/WebApp/WebApp.csproj" \
--no-restore \
--configuration Release \
--output /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
RUN groupadd -g 1001 appgroup && \
useradd -u 1001 -g appgroup -m -d /app -s /bin/false appuser
WORKDIR /app
COPY --from=build --chown=appuser:appgroup /app/publish .
USER appuser
ENV DOTNET_RUNNING_IN_CONTAINER=true \
DOTNET_EnableDiagnostics=0 \
HTTP_PORT=8080 \
ASPNETCORE_ENVIRONMENT=Production
ENTRYPOINT ["dotnet", "WebApp.dll"]
At a high level, here are the things we're optimizing in our Docker build for a .NET ASP.NET Core application:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
We use the official .NET 8 SDK image for the build stage, providing all necessary tools for compilation and publishing.
COPY src/WebApp/WebApp.csproj src/WebApp/
COPY src/WebApp.Core/WebApp.Core.csproj src/WebApp.Core/
COPY Directory.Build.props ./
COPY *.sln ./
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet restore
We copy only the project files and solution file first for optimal layer caching. This pattern ensures that package restoration only runs when dependencies change, not when source code changes. The cache mount persists NuGet packages between builds.
COPY src/ src/
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet publish "src/WebApp/WebApp.csproj" \
--no-restore \
--configuration Release \
--output /app/publish
After copying the source code, we publish the application:
--no-restore
skips restoration since we've already restored packages--configuration Release
builds in release mode for production--output /app/publish
specifies the output directory for the published filesFROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
RUN groupadd -g 1001 appgroup && \
useradd -u 1001 -g appgroup -m -d /app -s /bin/false appuser
WORKDIR /app
COPY --from=build --chown=appuser:appgroup /app/publish .
The runtime stage uses the ASP.NET Core runtime image, which is much smaller than the SDK. We create a non-root user for security and copy only the published application files.
USER appuser
ENV DOTNET_RUNNING_IN_CONTAINER=true \
DOTNET_EnableDiagnostics=0 \
HTTP_PORT=8080 \
ASPNETCORE_ENVIRONMENT=Production
ENTRYPOINT ["dotnet", "WebApp.dll"]
We configure the runtime environment:
DOTNET_RUNNING_IN_CONTAINER=true
enables container-optimized settingsDOTNET_EnableDiagnostics=0
disables diagnostics for productionHTTP_PORT=8080
sets the HTTP portASPNETCORE_ENVIRONMENT=Production
sets the environmentCache mounts are one of the most powerful features for optimizing Docker builds with Depot. This Dockerfile uses the following cache mount syntax:
RUN --mount=type=cache,target=/root/.nuget/packages \
--mount=type=cache,target=/root/.local/share/NuGet/v3-cache \
--mount=type=cache,target=/root/.local/share/NuGet/plugins-cache \
--mount=type=cache,target=/tmp/NuGetScratchroot \
dotnet restore
type=cache
: Specifies this is a cache mount that persists across builds.
Multiple cache targets:
/root/.nuget/packages
: Global NuGet package cache/root/.local/share/NuGet/v3-cache
: NuGet v3 API cache/root/.local/share/NuGet/plugins-cache
: NuGet plugins cache/tmp/NuGetScratchroot
: Temporary extraction directoryFor more information regarding NuGet cache mounts, please visit the official Microsoft documentation.