跳到主要内容

Docker 部署 ASP.NET Core

本页演示一个与具体仓库无关的 ASP.NET Core 容器化流程。示例使用 .NET 10,项目名为 Sample.Api;实际使用时应替换项目路径、程序集名、端口和镜像地址。

多阶段 Dockerfile

假设仓库结构如下:

.
├── Dockerfile
└── src/
└── Sample.Api/
├── Sample.Api.csproj
└── Program.cs

在仓库根目录创建 Dockerfile

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

.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 注入:

sample-api.env
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

compose.yaml
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_PORTSEXPOSE-p 右侧端口是否一致
依赖连接失败容器间使用 Compose 服务名;宿主机服务按实际网络地址访问
Linux 中找不到文件Linux 文件系统区分大小写,检查配置和静态文件路径
镜像体积过大确认最终阶段基于 aspnet,并完善 .dockerignore
容器权限错误保持非 root 用户运行,并为挂载目录配置最小必要权限

官方参考