6.1 KiB
6.1 KiB
部署手册(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. 必须记住的规则
- 默认发布
main,日常开发在dev—— 直接./deploy.sh all会部署 main 上的旧代码。要么先 merge,要么GIT_BRANCH=dev ./deploy.sh all。 - 改表要向后兼容 —— 切换的几十秒里新旧代码同时在跑。加字段/加表可以;改类型、删字段要拆两次发布。
HASHID_SECRET上线后别动。- 镜像会占磁盘(前端约 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 |