Files
backend_v2/DEPLOY.md
toom1996 5db90af73a update
2026-10-19 00:33:25 +08:00

6.1 KiB
Raw Permalink Blame History

部署手册(Docker · 蓝绿零停机)

0. 一图看懂

浏览器 ──▶ proxy(nginx:80,常驻,发布时从不重建)
             ├─ /api  ──▶ backend_a 或 backend_b
             ├─ /     ──▶ web_a     或 web_b
             ├─ 18090(仅容器网络)SSR 取数 → 当前活跃后端
             ├─ 127.0.0.1:18091 前端构建期取 SSG
             └─ 127.0.0.1:18092 管理后台(SSH 隧道)

发布时只重建空闲槽,等它健康后改写切换文件并 nginx -s reload,在途请求由旧槽跑完。 镜像以 RELEASE(时间戳-后端提交号)打标签,不可变,历史版本不会被覆盖。

部署入口在本仓库(后端仓),脚本会自动把前端仓也拉到位。


1. 服务器准备(只做一次)

# Ubuntu 22.04 / 24.04,2 核 4G 起
curl -fsSL https://get.docker.com | sh
apt install -y docker-compose-plugin git

mkdir -p /opt/fashion && cd /opt/fashion
git clone <后端仓库> backend
git clone <前端仓库> test        # 必须与 backend 同级

cd backend
cp .env.example .env && vi .env
chmod +x deploy.sh init-db.sh

私有仓库需要配好拉取凭据:SSH deploy key,或 HTTPS token + git config credential.helper store。


2. 首次部署(只做一次)

./init-db.sh /path/to/your.sql   # 建库(传入与当前代码匹配的 SQL)
./deploy.sh all                  # 启动全部服务
curl http://127.0.0.1/api/health # {"status":"ok"}

.env 必填 6 项:

变量 说明
DB_PASSWORD 数据库口令,别沿用开发库的
HASHID_SECRET 公开 ID 混淆盐,上线后不要改(改了所有旧链接失效)
JWT_SECRET 登录令牌密钥
INGEST_SECRET 爬虫上报密钥,须与爬虫端一致
S4_AK / S4_SK 对象存储密钥,缺了图片全 404

3. 日常发布

./deploy.sh                     # 拉 main + 只更新后端(默认)
./deploy.sh all                 # 拉 main + 前后端都更新
./deploy.sh web                 # 只更新前端
./deploy.sh all --no-pull       # 不拉代码,用服务器现有代码构建
GIT_BRANCH=dev ./deploy.sh all  # 临时指定分支(优先于 .env)

拉代码(.env 的 GIT_BRANCH,默认 main):

  • 后端仓 . 和前端仓 $WEB_DIR(默认 ../test)都会 fetch → 必要时 checkout → pull --ff-only
  • 不能快进就报错退出,不会硬覆盖(有本地改动时会提示 reset --hard 命令)
  • 每次打印实际提交:后端:main @ a1b2c3d fix: xxx

发布过程:

步 动作 用户感受
1 生成 RELEASE,拉代码 无感
2 docker compose build 构建 fashion-*:$RELEASE 无感(旧槽在跑)
3 重建空闲槽 无感
4 轮询 health,未通过则直接退出 旧槽继续服务
5 改切换文件 → nginx -t → nginx -s reload 在途请求不丢
6 写 .deploy/releases.log —

4. 回滚

./deploy.sh --rollback
# 回滚 backend:b → a(该槽镜像 fashion-backend:20261018-2210-9f3e1a2)

不动代码、不重建容器,只改 nginx 指向 + reload,秒级生效。 前提是该槽容器还在(正常交替发布时,非活跃槽就是上一版)。


5. 版本与镜像管理

cat .deploy/releases.log                                                  # 发布历史
docker inspect -f '{{.Config.Image}}' $(docker compose ps -q backend_a)   # 线上版本
./deploy.sh --prune                                                       # 清理旧镜像
KEEP_IMAGES=3 ./deploy.sh --prune                                         # 只留 3 个

镜像标签形如 fashion-backend:20261019-153012-a1b2c3d(时间 + 提交号),不会被自动清理。 latest 只是手动执行 compose 命令的别名,deploy.sh 从不依赖它。


6. 必须记住的规则

  1. 默认发布 main,日常开发在 dev —— 直接 ./deploy.sh all 会部署 main 上的旧代码。要么先 merge,要么 GIT_BRANCH=dev ./deploy.sh all。
  2. 改表要向后兼容 —— 切换的几十秒里新旧代码同时在跑。加字段/加表可以;改类型、删字段要拆两次发布。
  3. HASHID_SECRET 上线后别动。
  4. 镜像会占磁盘(前端约 250MB/版),每 5 版跑一次 ./deploy.sh --prune。

7. 管理后台

ssh -L 18092:127.0.0.1:18092 user@server
# 本机浏览器打开 http://localhost:18092/admin

8. 域名 / HTTPS

前端只监听 80,二选一:

  • 宿主机 nginx / 宝塔:.env 里 HTTP_PORT=8080,外层反代到 127.0.0.1:8080,证书在外层做
  • Caddy(自动证书):同 compose 加 caddy 容器,reverse_proxy 127.0.0.1:80

9. 备份

docker compose exec -T db pg_dump -U fashion fashion | gzip > backups/db-$(date +%F).sql.gz

每天 4 点自动备份并保留 7 天:

0 4 * * * cd /opt/fashion/backend && docker compose exec -T db pg_dump -U fashion fashion | gzip > backups/db-$(date +\%F).sql.gz && find backups -name 'db-*.sql.gz' -mtime +7 -delete

10. 排障

docker compose ps                    # 各容器状态与健康
docker compose logs -f proxy         # 切换失败先看这里
docker compose logs -f backend_a
docker compose logs --tail 100 web_b
现象 原因
全站接口 404 nginx/default.conf 的 proxy_pass 带了 URI/斜杠(会剥掉 /api 前缀)
详情页 500 前端 BASE_API_SSR 必须是 http://proxy:18090(容器里的 localhost 是它自己)
图片全 404 S4_AK/S4_SK 没填或填错
前端构建失败 构建期要连 18091 取 SSG:确认 proxy 在跑、backend_a healthy
发布后仍是旧版本 分支不对(默认 main,日常在 dev);或 docker compose logs proxy 里 reload 报错
回滚提示"槽不可用" 该槽被更早的发布重建过,回滚只能退一格
登录后跳回登录页 JWT_SECRET 改过,旧 token 失效
磁盘涨得快 ./deploy.sh --prune