Appearance
58|Docker 构建与部署发布
开发环境前后端分开跑,生产环境需要打包成可部署的形态:前端构建为静态文件,后端打包成 Docker 镜像,Nginx 统一对外提供入口,静态资源和 API 请求都走 80/443 端口。这一篇把整个构建和部署链路串起来。
一、前端构建
bash
cd frontend
npm run build构建产物在 frontend/dist/ 目录:
text
dist/
├── index.html
├── assets/
│ ├── index-xxxx.js
│ ├── index-xxxx.css
│ └── logo.pngindex.html 引用了带哈希的 JS 和 CSS 文件,浏览器会长期缓存。Vite 自动处理文件名哈希,代码改动后客户端会加载新版本。
二、后端多阶段构建
dockerfile
# backend/Dockerfile
FROM python:3.12-slim as builder
WORKDIR /app
COPY pyproject.toml .
RUN pip install uv && uv venv && uv pip install -r pyproject.toml
# 生产镜像
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /app/.venv /app/.venv
COPY app/ ./app/
ENV PATH="/app/.venv/bin:$PATH"
ENV PYTHONPATH=/app
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]| 阶段 | 作用 |
|---|---|
builder | 安装依赖,构建虚拟环境 |
| 生产镜像 | 只复制虚拟环境和源码,体积小 |
构建:
bash
cd backend
docker build -t ops-console-backend .三、Nginx 配置
Nginx 做两件事:
- 对外暴露 80 端口
/api请求转发给后端,/请求返回前端静态文件
nginx
# nginx.conf
server {
listen 80;
server_name localhost;
# 前端静态资源
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# API 请求转发给后端
location /api/ {
proxy_pass http://backend:8000/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}try_files $uri $uri/ /index.html 是单页应用的关键——Vue Router 的 history 模式下,刷新页面时 Nginx 需要返回 index.html,让前端路由接管。
四、Docker Compose
yaml
# docker-compose.yml
version: "3.8"
services:
backend:
build: ./backend
environment:
- DATABASE_URL=sqlite:///data/ops.db
- SECRET_KEY=${SECRET_KEY}
volumes:
- ./data:/app/data
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./frontend/dist:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- backend
restart: unless-stopped| 服务 | 作用 |
|---|---|
backend | FastAPI 应用 |
nginx | 反向代理 + 静态文件服务 |
启动:
bash
docker-compose up -d五、部署检查清单
部署前
- [ ] 前端
npm run build成功,无报错 - [ ] 后端
docker build成功 - [ ] 环境变量
SECRET_KEY已设置(生产环境必须随机生成) - [ ]
docker-compose.yml中restart: unless-stopped已配置
部署后
- [ ] 首页能打开,无 404
- [ ] 登录接口正常,Token 能获取
- [ ] 刷新页面不报错(Nginx try_files 配置正确)
- [ ] 数据库文件已挂载到宿主机(
volumes: ./data:/app/data)
六、生产环境调整
HTTPS
生产环境必须用 HTTPS。可以用 Nginx 配置 SSL:
nginx
server {
listen 443 ssl;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
...
}
server {
listen 80;
return 301 https://$host$request_uri; # HTTP 强制跳转 HTTPS
}或用反向代理(云负载均衡、Traefik)处理 TLS 终止,Nginx 只跑 80。
多 Worker
dockerfile
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]Worker 数通常设为 CPU 核心数 × 2 + 1。
数据库换 PostgreSQL
SQLite 不适合生产并发:
yaml
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: ops
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ops_console
volumes:
- pg_data:/var/lib/postgresql/data
backend:
environment:
- DATABASE_URL=postgresql://ops:${DB_PASSWORD}@db/ops_console七、常见错误
前端刷新 404
nginx
# 错误:没有 try_files,刷新时 Nginx 找 /assets/123 这个文件,不存在就 404
location / {
root /usr/share/nginx/html;
}
# 正确
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html; # 找不到文件时回退到 index.html
}后端数据库文件没持久化
yaml
# 错误:容器删除后数据丢失
services:
backend:
build: ./backend
# 正确:挂载宿主机目录
services:
backend:
build: ./backend
volumes:
- ./data:/app/dataSECRET_KEY 用默认值
python
# 错误:生产环境用硬编码的弱密钥
SECRET_KEY = "dev-key"
# 正确:从环境变量读取
SECRET_KEY = os.environ["SECRET_KEY"]