基于scratch镜像缩减ASP.NET Core Docker分发镜像体积可行吗?
Great question! The approach you’re considering—using a scratch image to package just your ASP.NET Core app files and pairing it with the official microsoft/aspnetcore runtime via Docker Compose—totally works, and it’s a clever way to cut down on the size of the artifact you need to ship to your test servers. Here’s how to implement it step by step:
1. Build a Minimal scratch Image for Your App Files
First, you’ll create a multi-stage Dockerfile to compile your app and copy only the published files into a scratch base image. This results in an extremely small image (just your app’s files, no runtime dependencies):
Create a file named Dockerfile.app with this content:
# Stage 1: Build and publish the ASP.NET Core app FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src # Copy project file first to leverage Docker cache COPY ["YourAppName.csproj", "."] RUN dotnet restore "YourAppName.csproj" # Copy remaining source code COPY . . WORKDIR "/src/." RUN dotnet publish "YourAppName.csproj" -c Release -o /app/publish # Stage 2: Create the minimal app file image FROM scratch WORKDIR /app COPY --from=build /app/publish .
Build this image with:
docker build -t your-app-files:latest -f Dockerfile.app .
This image will only contain your compiled app files—no runtime, no OS libraries—so its size will be just a few MBs (depending on your app) instead of hundreds of MBs like the full microsoft/aspnetcore image.
2. Use Docker Compose to Pair the Runtime and App Files
Next, you’ll create a docker-compose.yml that combines the official ASP.NET Core runtime image with your scratch app file image. The trick here is to use a data container (from your scratch image) to share the app files with the runtime container:
version: '3.8' services: # The runtime container that runs your app app: image: mcr.microsoft.com/dotnet/aspnet:8.0 ports: - "8080:80" # Adjust ports to match your app volumes_from: - app-files # Mounts the /app directory from the data container working_dir: /app command: ["dotnet", "YourAppName.dll"] # Replace with your app's DLL name # The data container that holds your app files app-files: image: your-app-files:latest volumes: - /app # Exposes the /app directory as a volume command: ["tail", "-f", "/dev/null"] # Keeps the container running to share the volume
3. Distribute and Run on Test Servers
Your distribution workflow becomes much lighter now:
- On your build machine, export the small app file image:
docker save -o app-files.tar your-app-files:latest - Transfer this tiny
.tarfile to your test server (via SCP, FTP, etc.—it’ll be way faster than sending the full runtime image). - On the test server, load the image:
docker load -i app-files.tar - Run
docker-compose up -d—Docker will pull themicrosoft/aspnetcoreruntime image if it’s not already present, then start both containers. The runtime container will access your app files from the data container and run the app.
Key Notes to Keep in Mind
- Version Compatibility: Ensure the SDK version used to build your app (in
Dockerfile.app) matches the runtime image version (indocker-compose.yml). For example, if you use SDK 8.0, use theaspnet:8.0runtime image. - Native Dependencies: If your app relies on system-level native libraries (e.g., for image processing or database drivers),
scratchwon’t include these. In that case, usemcr.microsoft.com/dotnet/runtime-deps:8.0instead ofscratch—it’s still much smaller than the fullaspnetimage and includes the necessary system dependencies for .NET apps. - Updating Apps: When you push a new version, rebuild the
your-app-filesimage with a new tag (e.g.,v2), update the tag indocker-compose.yml, then rundocker-compose up -don the test server. You may need to stop and remove the oldapp-filescontainer first to ensure the new files are used. - Alternative Workflow: If your test servers have internet access, consider using a multi-stage build to create a slim runtime image directly (combining the runtime base image with your app files). This avoids the data container complexity, and Docker will only pull the delta when updating:
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["YourAppName.csproj", "."] RUN dotnet restore COPY . . RUN dotnet publish -c Release -o /app/publish FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app COPY --from=build /app/publish . ENTRYPOINT ["dotnet", "YourAppName.dll"]
内容的提问来源于stack exchange,提问作者JohnC

