Docker 部署 ASP.NET Core
本页演示一个与具体仓库无关的 ASP.NET Core 容器化流程。示例使用 .NET 10,项目名为 Sample.Api;实际使用时应替换项目路径、程序集名、端口和镜像地址。
多阶段 Dockerfile
假设仓库结构如下:
.
├── Dockerfile
└── src/
└── Sample.Api/
├── Sample.Api.csproj
└── Program.cs
在仓库根目录创建 Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["src/Sample.Api/Sample.Api.csproj", "src/Sample.Api/"]
RUN dotnet restore "src/Sample.Api/Sample.Api.csproj"
COPY . .
WORKDIR "/src/src/Sample.Api"
RUN dotnet publish "Sample.Api.csproj" \
-c Release \
-o /app/publish \
/p:UseAppHost=false
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
ENV ASPNETCORE_HTTP_PORTS=8080
EXPOSE 8080
USER $APP_UID
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "Sample.Api.dll"]
多阶段构建把 SDK 留在构建阶段,最终镜像只包含 ASP.NET Core 运行时和发布产物。先复制项目文件再执行 restore,可以在依赖未变化时复用 Docker 构建缓存。
如果解决方案有多个项目引用,应在 dotnet restore 前复制所有参与还原的项目文件、Directory.Build.*、NuGet 配置和锁定文件。构建上下文必须覆盖 Dockerfile 中所有 COPY 的来源。
忽略不需要的构建内容
在构建上下文根目录创建 .dockerignore:
**/bin/
**/obj/
.git/
.idea/
.vs/
.vscode/
TestResults/
*.user
*.suo
不要把 .env、私钥、证书密码和生产配置复制进镜像。若仓库中可能存在这些文件,应继续把对应路径加入 .dockerignore。
构建与运行
在仓库根目录执行:
docker build -t sample-api:1.0.0 .
docker run -d \
--name sample-api \
--restart unless-stopped \
-p 8080:8080 \
--env-file ./sample-api.env \
sample-api:1.0.0
环境文件只放非机密示例;真实 Secret 应由部署平台或 Secret Store 注入:
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_HTTP_PORTS=8080
验证容器:
docker ps --filter name=sample-api
docker logs --tail 200 sample-api
curl --fail http://localhost:8080/health
/health 只是示例端点,应用需要自行实现健康检查。如果应用没有该端点,应改用真实的轻量级可用性地址。
使用 Docker Compose
services:
api:
build:
context: .
dockerfile: Dockerfile
image: sample-api:1.0.0
restart: unless-stopped
env_file:
- sample-api.env
ports:
- "8080:8080"
docker compose config
docker compose up -d --build
docker compose logs --tail 200 -f api
数据库、缓存等依赖应通过 Compose 网络中的服务名访问,不要在容器连接串中使用 localhost 指代其他容器。
推送镜像仓库
使用明确、不可变的发布标签,并通过标准输入登录,避免密码进入命令历史:
printf '%s' '<registry-password>' | \
docker login <registry-host> \
--username '<registry-user>' \
--password-stdin
docker tag sample-api:1.0.0 \
<registry-host>/<namespace>/sample-api:1.0.0
docker push <registry-host>/<namespace>/sample-api:1.0.0
CI 中应从 Secret 管理系统读取凭据。生产部署可以再记录镜像 digest,以避免同名标签被覆盖后产生歧义。
HTTPS 与反向代理
常见生产架构是在 Nginx、Ingress 或云负载均衡器终止 TLS,再把转发协议通过 X-Forwarded-* 请求头传给应用。应用应正确启用 Forwarded Headers,并限制可信代理来源。
若必须让 Kestrel 在容器内直接提供 HTTPS,应在运行时只读挂载证书并通过 Secret 注入密码;不要把证书和密码写进 Dockerfile 或镜像层。详见 ASP.NET Core Docker HTTPS 官方说明。
常见问题
| 现象 | 检查项 |
|---|---|
| 构建时找不到项目 | 检查 build context、COPY 路径和文件名大小写 |
| 容器启动后无法访问 | 检查 ASPNETCORE_HTTP_PORTS、EXPOSE 与 -p 右侧端口是否一致 |
| 依赖连接失败 | 容器间使用 Compose 服务名;宿主机服务按实际网络地址访问 |
| Linux 中找不到文件 | Linux 文件系统区分大小写,检查配置和静态文件路径 |
| 镜像体积过大 | 确认最终阶段基于 aspnet,并完善 .dockerignore |
| 容器权限错误 | 保持非 root 用户运行,并为挂载目录配置最小必要权限 |