Appearance
ASP.NET项目Docker构建指南
目标:在 30 分钟内完成任意 ASP.NET Web 项目(含前端与数据库)的标准化 Docker 部署。 核心策略:流程固定化、配置模板化、快速复用。
📋 部署检查清单
在开始部署前,请确保环境满足以下要求:
- [ ] 环境:Docker Engine ≥ 24.x + Docker Compose v2。
- [ ] 源码:包含后端代码及前端构建产物(
dist目录)。 - [ ] 数据库:明确使用容器内 SQL Server 还是外部数据库。
- [ ] 网络:提前规划宿主机端口,避免与现有服务冲突。
- [ ] 域名:如需外网访问,请提前完成域名解析及 Hub 反代规划。
1. 标准目录结构
推荐使用以下结构组织代码与部署配置,实现“配置即代码”与数据隔离。
text
project-root/
├── server/ # 后端 API 源码
│ └── API/
│ ├── Dockerfile # ✅ 后端镜像构建定义
│ └── appsettings.json # 生产环境配置文件
├── admin/ # 前端源码 (Vue/React 等)
│ └── dist/ # ✅ 前端编译产物 (构建后生成)
├── deploy/ # ✅ 容器化部署配置 (核心)
│ ├── nginx/
│ │ ├── nginx.conf # Nginx 全局优化配置
│ │ └── conf.d/
│ │ └── app.conf # 站点反代与动静分离配置
│ ├── logs/nginx/ # 挂载运行日志
│ └── data/mssql/ # 挂载 SQL Server 持久化数据
└── docker-compose.yml # ✅ 多服务编排定义快速初始化命令:
bash
mkdir -p deploy/nginx/conf.d deploy/logs/nginx deploy/data/mssql2. 后端 Dockerfile (多阶段构建)
如果你使用 Visual Studio / Rider 等 IDE,也可以先生成项目默认的 Docker 支持,再按本文模板做标准化收敛。最终应以仓库中的 Dockerfile 与 docker-compose.yml 为准,而不是依赖本地 IDE 向导配置。
采用多阶段构建,确保最终镜像仅包含运行所需的 Runtime,体积最小化。
dockerfile
# ========================================
# ASP.NET Web API 镜像构建(多阶段)
# 适用于:.NET 6/7/8 项目
# ========================================
# --- 阶段 1: 构建 (Build) ---
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
# 执行还原与发布 (替换为实际项目路径)
RUN dotnet restore "Server/API/API.csproj" \
&& dotnet publish "Server/API/API.csproj" -c Release -o /app/publish --no-restore
# --- 阶段 2: 运行 (Runtime) ---
FROM mcr.microsoft.com/dotnet/aspnet:8.0
# 优化:切换国内镜像源并安装字体 (解决 PDF/图片生成中的乱码)
RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g;s|security.debian.org|mirrors.aliyun.com|g' \
/etc/apt/sources.list.d/debian.sources \
&& apt-get update \
&& apt-get install -y --no-install-recommends fonts-dejavu-core \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/publish .
# 生产环境环境变量
ENV ASPNETCORE_URLS=http://0.0.0.0:5000 \
ASPNETCORE_ENVIRONMENT=Production \
TZ=Asia/Shanghai
EXPOSE 5000
# 替换为实际的输出 DLL 名称
ENTRYPOINT ["dotnet", "API.dll"]修改要点:
- 替换
Server/API/API.csproj为实际项目路径。 - 替换
API.dll为实际输出文件。 - 根据项目需求调整 SDK/Runtime 版本。
2.1 .dockerignore 模板
为了避免把 .git、bin/、obj/、前端依赖等无关文件打进构建上下文,建议同时维护一份 .dockerignore:
text
**/.dockerignore
**/.git
**/.gitignore
**/.vs
**/.vscode
**/bin
**/obj
**/node_modules
**/docker-compose*
**/Dockerfile*
README.md经验建议:
Dockerfile管的是“怎么构建镜像”,.dockerignore管的是“哪些文件根本不要进构建上下文”。这两个文件应成对维护。
3. Nginx 配置模板
3.1 全局配置 (deploy/nginx/nginx.conf)
包含 Gzip 压缩、字符集优化及大文件上传限制。
nginx
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 全局 UTF-8 (解决中文乱码)
charset utf-8;
charset_types text/plain text/css text/xml application/json;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
client_max_body_size 50m; # 调整上传限制
# Gzip 压缩优化
gzip on;
gzip_types text/plain application/json text/css application/javascript;
include /etc/nginx/conf.d/*.conf;
}3.2 站点配置 (deploy/nginx/conf.d/app.conf)
nginx
server {
listen 80;
server_name _;
# 前端静态资源托管 (Vue/React SPA)
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# 后端 API 反向代理
location /api/ {
# 注意:使用 docker-compose 中定义的后端服务名
proxy_pass http://app-api:5000/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
}
}4. Docker Compose 编排
yaml
version: '3.8'
networks:
app-net:
driver: bridge
services:
# 1. 数据库:SQL Server 2019
sqlserver:
image: mcr.microsoft.com/mssql/server:2019-latest
container_name: app-sqlserver
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=YourStrong!Pass123 # 请修改为强密码
- MSSQL_PID=Developer
- TZ=Asia/Shanghai
volumes:
- ./deploy/data/mssql:/var/opt/mssql
ports:
- '14333:1433' # 宿主机映射端口
networks:
- app-net
healthcheck:
test: [CMD-SHELL, "bash -c 'echo > /dev/tcp/127.0.0.1/1433' || exit 1"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
restart: unless-stopped
# 2. 后端:ASP.NET Core API
app-api:
build:
context: .
dockerfile: Server/API/Dockerfile
container_name: app-api
environment:
- ASPNETCORE_ENVIRONMENT=Production
- TZ=Asia/Shanghai
depends_on:
sqlserver:
condition: service_healthy # 确保数据库就绪后再启动 API
networks:
- app-net
restart: unless-stopped
# 3. 前端 + Nginx 反代
app-nginx:
image: nginx:1.25-alpine
container_name: app-nginx
ports:
- '18080:80' # 内网暴露端口,由 Hub 接入
volumes:
- ./deploy/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./deploy/nginx/conf.d:/etc/nginx/conf.d:ro
- ./admin/dist:/usr/share/nginx/html:ro # 挂载前端产物
- ./deploy/logs/nginx:/var/log/nginx
depends_on:
- app-api
networks:
- app-net
restart: unless-stopped5. 快速部署流程 (30 分钟)
5.1 准备与构建 (5 分钟)
- 代码准备:克隆项目并进入根目录。
- 前端编译:
cd admin && npm run build。 - 创建目录:执行上文的
mkdir命令。
5.2 配置调整 (10 分钟)
- 修改 Dockerfile:确认项目路径与 DLL 名称。
- 修改 docker-compose.yml:调整服务名、端口及数据库密码。
- 配置数据库:修改
appsettings.json中的连接字符串。- 容器内连接:
Server=app-sqlserver,1433;User Id=sa;Password=...
- 容器内连接:
5.3 启动与验证 (15 分钟)
- 启动:
docker compose up -d --build。 - 验证 API:
curl http://127.0.0.1:18080/api/health。 - 接入 Hub:在全局网关 Nginx 中添加对应的
proxy_pass http://127.0.0.1:18080/配置。
6. 常用运维命令
bash
# 1. 启停与状态
docker compose ps # 查看运行状态
docker compose logs -f app-api # 实时查看后端日志
docker compose restart # 重启所有服务
# 2. 更新发布
docker compose build app-api # 仅重新构建后端镜像
docker compose up -d app-api # 平滑更新单个服务
# 3. 容器内调试
docker exec -it app-api bash # 进入 API 容器执行命令
docker exec -it app-sqlserver /opt/mssql-tools/bin/sqlcmd \
-S localhost -U sa -P 'YourStrong!Pass123' # 连接数据库7. 常见故障排除
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 502 Bad Gateway | API 容器未启动或端口不通 | 检查 docker compose ps 及后端日志 |
| 前端 404/空白 | Nginx root 挂载路径错误 | 确认 admin/dist 路径与 volumes 一致 |
| 数据库连接超时 | 网络隔离或防火墙拦截 | 确保服务在同一 networks 下,使用服务名访问 |
| 中文乱码 | Nginx 字符集配置缺失 | 确保 nginx.conf 中包含 charset utf-8 |
| 上传文件失败 | Nginx 大小限制 | 调大 client_max_body_size 参数 |
