docker
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDocker
Docker
Core Principles
核心原则
- Multi-stage builds always — Separate build and runtime stages. Build in the SDK image, run in the ASP.NET runtime image.
- Non-root by default — .NET container images support by default since .NET 8. Never run as root in production.
USER app - Layer caching matters — Copy files and restore before copying source code. This caches NuGet dependencies across builds.
.csproj - Health probes at the orchestrator level — Expose a endpoint and let Kubernetes/Compose probe it. Chiseled and default aspnet images have no shell or curl, so in-image
/health/livecommands have nothing to run with.HEALTHCHECK
- 始终使用多阶段构建 —— 分离构建阶段与运行时阶段。在SDK镜像中构建,在ASP.NET运行时镜像中运行。
- 默认使用非根用户 —— 自.NET 8起,.NET容器镜像默认支持。生产环境中绝不要以根用户身份运行。
USER app - 分层缓存至关重要 —— 在复制源代码前,先复制文件并执行还原操作。这样可以在多次构建间缓存NuGet依赖。
.csproj - 在编排器层面配置健康探针 —— 暴露端点,让Kubernetes/Compose对其进行探测。精简版(Chiseled)和默认aspnet镜像不包含shell或curl,因此镜像内的
/health/live命令没有可执行的工具。HEALTHCHECK
Patterns
实践模式
Multi-Stage Dockerfile for Web API
Web API的多阶段Dockerfile
dockerfile
undefineddockerfile
undefinedStage 1: Build
Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
Copy project files and restore (cached layer)
Copy project files and restore (cached layer)
COPY ["src/MyApp.Api/MyApp.Api.csproj", "src/MyApp.Api/"]
COPY ["src/MyApp.Domain/MyApp.Domain.csproj", "src/MyApp.Domain/"]
COPY ["Directory.Build.props", "."]
COPY ["Directory.Packages.props", "."]
RUN dotnet restore "src/MyApp.Api/MyApp.Api.csproj"
COPY ["src/MyApp.Api/MyApp.Api.csproj", "src/MyApp.Api/"]
COPY ["src/MyApp.Domain/MyApp.Domain.csproj", "src/MyApp.Domain/"]
COPY ["Directory.Build.props", "."]
COPY ["Directory.Packages.props", "."]
RUN dotnet restore "src/MyApp.Api/MyApp.Api.csproj"
Copy everything and build
Copy everything and build
COPY . .
RUN dotnet publish "src/MyApp.Api/MyApp.Api.csproj"
-c Release
-o /app/publish
--no-restore
-c Release
-o /app/publish
--no-restore
COPY . .
RUN dotnet publish "src/MyApp.Api/MyApp.Api.csproj"
-c Release
-o /app/publish
--no-restore
-c Release
-o /app/publish
--no-restore
Stage 2: Runtime
Stage 2: Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
Non-root user (default in .NET 8+ images)
Non-root user (default in .NET 8+ images)
USER app
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.Api.dll"]
undefinedUSER app
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.Api.dll"]
undefinedContainer Health Probes
容器健康探测
Prefer orchestrator-level probes (Kubernetes , Compose
) over a Dockerfile — the standard and
chiseled images ship no shell, no curl, and no wget, so there is nothing inside
the container to run the probe with. Point the orchestrator at :
livenessProbehealthcheckHEALTHCHECKaspnet/health/liveyaml
undefined优先使用编排器层面的探测(Kubernetes 、Compose
),而非Dockerfile中的——标准和
精简版镜像不包含shell、curl和wget,因此容器内没有可执行探测命令的工具。将编排器指向:
livenessProbehealthcheckHEALTHCHECKaspnet/health/liveyaml
undefineddocker-compose — probe from outside the app process
docker-compose — probe from outside the app process
services:
api:
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health/live || exit 1"]
interval: 30s
timeout: 3s
retries: 3
services:
api:
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/health/live || exit 1"]
interval: 30s
timeout: 3s
retries: 3
Note: CMD-SHELL requires a shell + wget in the image. Use a non-chiseled
Note: CMD-SHELL requires a shell + wget in the image. Use a non-chiseled
variant for this, or better: let Kubernetes httpGet probes do it —
variant for this, or better: let Kubernetes httpGet probes do it —
they run from the kubelet, needing nothing inside the image.
they run from the kubelet, needing nothing inside the image.
If you must have an in-image HEALTHCHECK, base the runtime stage on a
non-chiseled image that includes `wget` — never re-run the app binary as the
probe command; that starts a second instance instead of checking the first.
如果必须在镜像内配置HEALTHCHECK,请将运行时阶段基于包含`wget`的非精简版镜像——绝不要将应用二进制文件作为探测命令重新运行;这会启动第二个实例,而非检查第一个实例的状态。.dockerignore
.dockerignore配置
**/.git
**/.vs
**/bin
**/obj
**/node_modules
**/Dockerfile*
**/docker-compose*
**/tests**/.git
**/.vs
**/bin
**/obj
**/node_modules
**/Dockerfile*
**/docker-compose*
**/testsDocker Compose for Local Development
本地开发的Docker Compose配置
Key .NET-specific concerns — pass connection strings via environment, use with health checks:
depends_onyaml
services:
api:
build:
context: .
dockerfile: src/MyApp.Api/Dockerfile
ports:
- "5000:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__Default=Host=postgres;Database=myapp;Username=postgres;Password=postgres
- ConnectionStrings__Redis=redis:6379
depends_on:
postgres:
condition: service_healthy
# Add postgres/redis services with healthcheck — standard boilerplate.NET特有的关键注意事项——通过环境变量传递连接字符串,结合健康检查使用:
depends_onyaml
services:
api:
build:
context: .
dockerfile: src/MyApp.Api/Dockerfile
ports:
- "5000:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__Default=Host=postgres;Database=myapp;Username=postgres;Password=postgres
- ConnectionStrings__Redis=redis:6379
depends_on:
postgres:
condition: service_healthy
# Add postgres/redis services with healthcheck — standard boilerplateOptimized Build with .slnx
使用.slnx的优化构建
For solutions with multiple projects, restore only the necessary projects.
dockerfile
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src对于包含多个项目的解决方案,仅还原必要的项目。
dockerfile
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /srcCopy solution and all project files
Copy solution and all project files
COPY .slnx .
COPY Directory.Build.props .
COPY Directory.Packages.props .
COPY src/**/.csproj ./src/
COPY .slnx .
COPY Directory.Build.props .
COPY Directory.Packages.props .
COPY src/**/.csproj ./src/
Restore project structure
Restore project structure
RUN for file in src/**/*.csproj; do
mkdir -p $(dirname $file) && mv $file $(dirname $file)/;
done RUN dotnet restore
mkdir -p $(dirname $file) && mv $file $(dirname $file)/;
done RUN dotnet restore
COPY . .
RUN dotnet publish src/MyApp.Api -c Release -o /app/publish --no-restore
undefinedRUN for file in src/**/*.csproj; do
mkdir -p $(dirname $file) && mv $file $(dirname $file)/;
done RUN dotnet restore
mkdir -p $(dirname $file) && mv $file $(dirname $file)/;
done RUN dotnet restore
COPY . .
RUN dotnet publish src/MyApp.Api -c Release -o /app/publish --no-restore
undefinedHealth Check Endpoint
健康检查端点
csharp
// In Program.cs — lightweight health endpoint for Docker
app.MapGet("/health/live", () => Results.Ok("healthy"))
.ExcludeFromDescription();csharp
// In Program.cs — lightweight health endpoint for Docker
app.MapGet("/health/live", () => Results.Ok("healthy"))
.ExcludeFromDescription();Anti-patterns
反模式
Don't Use SDK Image for Runtime
不要将SDK镜像用于运行时
dockerfile
undefineddockerfile
undefinedBAD — SDK image is 900MB+, includes compilers
BAD — SDK image is 900MB+, includes compilers
FROM mcr.microsoft.com/dotnet/sdk:10.0
COPY . .
RUN dotnet run
FROM mcr.microsoft.com/dotnet/sdk:10.0
COPY . .
RUN dotnet run
GOOD — separate build and runtime, runtime image is ~200MB
GOOD — separate build and runtime, runtime image is ~200MB
FROM mcr.microsoft.com/dotnet/aspnet:10.0
undefinedFROM mcr.microsoft.com/dotnet/aspnet:10.0
undefinedDon't Copy Everything Before Restore
不要在还原前复制所有内容
dockerfile
undefineddockerfile
undefinedBAD — any source change invalidates the NuGet cache
BAD — any source change invalidates the NuGet cache
COPY . .
RUN dotnet restore
COPY . .
RUN dotnet restore
GOOD — copy only project files first, then restore
GOOD — copy only project files first, then restore
COPY ["src/MyApp.Api/MyApp.Api.csproj", "src/MyApp.Api/"]
RUN dotnet restore "src/MyApp.Api/MyApp.Api.csproj"
COPY . .
undefinedCOPY ["src/MyApp.Api/MyApp.Api.csproj", "src/MyApp.Api/"]
RUN dotnet restore "src/MyApp.Api/MyApp.Api.csproj"
COPY . .
undefinedDon't Run as Root
不要以根用户身份运行
dockerfile
undefineddockerfile
undefinedBAD — running as root (security risk)
BAD — running as root (security risk)
FROM mcr.microsoft.com/dotnet/aspnet:10.0
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.Api.dll"]
FROM mcr.microsoft.com/dotnet/aspnet:10.0
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.Api.dll"]
GOOD — use the built-in non-root user
GOOD — use the built-in non-root user
FROM mcr.microsoft.com/dotnet/aspnet:10.0
USER app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.Api.dll"]
undefinedFROM mcr.microsoft.com/dotnet/aspnet:10.0
USER app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.Api.dll"]
undefinedDecision Guide
决策指南
| Scenario | Recommendation |
|---|---|
| Web API container | Multi-stage build with aspnet runtime image |
| Worker service | Multi-stage build with dotnet/runtime image |
| Local development | Docker Compose with service dependencies |
| CI builds | Multi-stage build (self-contained) |
| Image size optimization | Use Alpine variant + trimming for small images |
| Health monitoring | |
| Secrets | Environment variables or mounted secrets, never in image |
| 场景 | 推荐方案 |
|---|---|
| Web API容器 | 使用aspnet运行时镜像的多阶段构建 |
| 工作服务 | 使用dotnet/runtime镜像的多阶段构建 |
| 本地开发 | 包含服务依赖的Docker Compose |
| CI构建 | 多阶段构建(自包含模式) |
| 镜像大小优化 | 使用Alpine变体+裁剪功能生成小体积镜像 |
| 健康监控 | |
| 密钥管理 | 环境变量或挂载密钥,绝不要存入镜像 |