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

176 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 部署手册(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. 服务器准备(只做一次)
```bash
# 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. 首次部署(只做一次)
```bash
./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. 日常发布
```bash
./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. 回滚
```bash
./deploy.sh --rollback
# 回滚 backend:b → a(该槽镜像 fashion-backend:20261018-2210-9f3e1a2)
```
不动代码、不重建容器,只改 nginx 指向 + reload,秒级生效。
前提是该槽容器还在(正常交替发布时,非活跃槽就是上一版)。
---
## 5. 版本与镜像管理
```bash
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. 管理后台
```bash
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. 备份
```bash
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. 排障
```bash
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` |