Skip to content

部署发布

27 篇用 Docker 打包了前后端,本地 docker-compose up 就能跑。部署到真实服务器还差几步:域名、HTTPS、生产配置、CI/CD 自动化发布。

一、生产环境跟开发的区别

开发生产
数据库SQLite 内存文件PostgreSQL 独立实例或云数据库
前后端分别跑在 5173 和 8000Nginx 统一入口(同域,无 CORS)
CORSallow_origins=["http://localhost:5173"]不需要(同域)或收紧到正式域名
调试模式DEBUG=true--reloadDEBUG=false,多 worker
密钥.env 随便填openssl rand -hex 32 生成
HTTPS不需要需要(Nginx + Let's Encrypt)

生产环境的核心原则:关闭调试、收紧来源、加密通信、密钥安全

二、Nginx 反向代理

生产环境通常在 Docker 前面再放一个 Nginx——它管域名、HTTPS 证书、把请求分发给前端容器和后端容器。

nginx
# /etc/nginx/conf.d/ops.example.com.conf
server {
    listen 80;
    server_name ops.example.com;

    # HTTP 跳 HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name ops.example.com;

    # TLS 证书
    ssl_certificate     /etc/letsencrypt/live/ops.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ops.example.com/privkey.pem;

    # 前端:静态文件 + SPA 路由
    location / {
        proxy_pass http://127.0.0.1:80;  # 前端容器的 Nginx
        proxy_set_header Host $host;
    }

    # 后端:API 请求
    location /api/ {
        proxy_pass http://127.0.0.1:8000;  # 后端容器
        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;
    }
}

外层 Nginx 管域名和 HTTPS。location / 把非 API 请求转发给前端容器(前端容器里的 Nginx 提供静态文件),location /api/ 把 API 请求转发给后端容器。

X-Forwarded-ForX-Forwarded-Proto 必须传——后端需要知道客户端真实 IP(做审计日志)和原始协议(生成正确的回调 URL)。FastAPI 侧要信任这些头(配 ProxyHeadersMiddleware 或在 CORS 里处理)。

HTTPS 证书

用 Let's Encrypt 免费证书:

bash
# 安装 certbot
apt install certbot python3-certbot-nginx

# 申请证书(自动改 Nginx 配置)
certbot --nginx -d ops.example.com

# 自动续期(Let's Encrypt 证书 90 天过期)
certbot renew --dry-run

三、生产环境变量

生产环境不依赖 .env 文件,直接在 docker-compose 里注入:

yaml
# docker-compose.prod.yml
services:
  backend:
    environment:
      - DATABASE_URL=postgresql://appuser:${DB_PASSWORD}@db:5432/opsconsole
      - SECRET_KEY=${SECRET_KEY}          # 从系统环境变量读
      - DEBUG=false
      - CORS_ORIGINS=https://ops.example.com  # 生产用正式域名
    deploy:
      replicas: 2  # 后端跑两个实例(Nginx 负载均衡)

SECRET_KEYDB_PASSWORD 不写在文件里,部署时从密钥管理系统或 .env(不进 Git 的本地文件)注入:

bash
# 部署机器上的 .env(不进 Git)
SECRET_KEY=a3f5e8b2c1d4f7a9e6b3c8d1f4a7b9e2c5d8f1a4b7e9c2d5f8a1b4e7c9d2f5a8
DB_PASSWORD=s3cret_database_password

四、数据库迁移

每次部署新版本,先跑迁移再启动应用:

bash
# 在后端容器里执行迁移
docker-compose exec backend alembic upgrade head

# 然后重启后端(如果代码有变化)
docker-compose restart backend

迁移必须在应用启动前完成——新代码可能依赖新字段。如果应用先起来了但表结构没更新,接口会报错。

五、CI/CD——自动发布

手动 docker-compose up 适合单台机器。团队大了要用 CI/CD 自动化——代码推到 Git,流水线自动构建镜像、推到镜像仓库、部署到服务器。

基本流程:

GitHub Actions 示例(.github/workflows/deploy.yml):

yaml
name: Deploy

on:
  push:
    branches: [main]   # 推到 main 分支触发部署

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      # 1. 拉代码
      - uses: actions/checkout@v4

      # 2. 构建镜像
      - name: Build images
        run: |
          docker-compose build

      # 3. 推到镜像仓库(以 Docker Hub 为例)
      - name: Push images
        run: |
          docker tag ops-console-backend ${{ secrets.DOCKER_USER }}/ops-backend:latest
          docker tag ops-console-frontend ${{ secrets.DOCKER_USER }}/ops-frontend:latest
          docker push ${{ secrets.DOCKER_USER }}/ops-backend:latest
          docker push ${{ secrets.DOCKER_USER }}/ops-frontend:latest

      # 4. SSH 到服务器执行部署
      - name: Deploy to server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /opt/ops-console
            docker-compose pull
            docker-compose exec backend alembic upgrade head
            docker-compose up -d

secrets.SERVER_HOSTsecrets.SSH_KEY 等敏感信息存在 GitHub 仓库的 Secrets 里——不写在代码里、不进 Git 历史

六、发布检查清单

每次发布后验证:

  • [ ] 前端页面能打开(https://ops.example.com
  • [ ] 登录功能正常
  • [ ] 资产列表能加载
  • [ ] 创建/删除资产正常
  • [ ] 任务执行正常(提交任务 → 状态变化 → 有结果)
  • [ ] 事件日志有记录
  • [ ] 数据库迁移执行了(alembic current
  • [ ] HTTPS 证书有效(浏览器地址栏有锁)
  • [ ] 错误日志没有异常(docker-compose logs backend

全通过,发布成功。有问题就回滚——docker-compose 拉旧版本镜像重新 up,数据库用 alembic downgrade 回退迁移。


28 篇到此结束——从 Python 变量到全栈项目部署,一条线走完。前端基础篇(01-09)用文章管理的中性例子打基础,后端基础篇(10-14)用文章 CRUD API 接上前端的 fetch,进阶篇(15-20)补充生产级要用的东西,项目实战篇(21-28)把所有知识合到运维平台 ops-console 上。