Files
caiwuzongzhang/deploy/README.md
T

127 lines
7.0 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.
# 部署与运维手册(与 `release/prod` 基线一致)
最后核对:2026-08-30,总工 HEL-270 上线前总验收。本手册是测试与正式环境唯一的部署/回滚/备份/巡检操作依据,取代散落在宿主机 `DEPLOYMENT.txt` 里的历史记录(旧记录仅作存档)。
## 1. 物料与目录
| 物料 | 说明 |
|---|---|
| `deploy/Dockerfile` | python:3.12-slim-bookworm,非 rootuid 10001 `app`),只读根文件系统 |
| `deploy/compose.yaml` | cap_drop ALL、no-new-privileges、pids 128、mem 512m、cpu 1.0、healthcheck |
| `deploy/.env.example` | 配置模板;`deploy/.env` 已 gitignore,口令永不入库 |
| `deploy/deploy.sh` | `TAG=<tag> ./deploy.sh`,默认镜像 tag=当前提交 sha |
| `deploy/rollback.sh` | `./rollback.sh <tag>`,只换应用不动数据 |
| `deploy/backup.sh` | 在线热备 + 保留策略(30 天日备 + 12 个月月备) |
| `deploy/monitor.sh` | 每 5 分钟健康 + 磁盘 ≥80% 告警,写 `ALERT.log` |
数据目录:`deploy/../data/``app.db` + `files/`)。银行原始文件按 SHA-256 内容哈希不可变保存,任何操作不得改写。
## 2. 正式配置铁律
- **不得出现 `admin/admin123`**`APP_BOOTSTRAP_ADMIN_PASSWORD` 正式环境不设值,首启由控制台读取随机生成的一次性初始口令,首登立即改密;管理员用户名避开 `admin`
- **登录失败限流默认开启**(5 次/10 分钟锁账号+IP)。`APP_LOGIN_RATE_LIMIT_DISABLED=1` 仅限本地调试,正式 .env 不得携带。
- 密钥/口令/证书私钥不进仓库、不进评论、不进任务元数据。
- **HTTPS**:正式暴露一律经反向代理(推荐同机 Caddy 容器,内网自签或内部 CA 证书,反代到容器 4173);不占用 NAS 系统 nginx 的 80/443。公司电脑分发根证书即可。
- **日志**:容器 stdout 走 docker json-file,限幅 `max-size=10m, max-file=3`daemon 或 compose `logging` 配置);审计日志在库内(append-only 触发器保护)。
## 3. 部署步骤(测试与正式一致)
```bash
git fetch && git checkout release/prod && git pull
cd deploy
cp .env.example .env # 首次;按上面铁律填写
# .env 必设 APP_UID/APP_GID = data/ 目录属主的 uid/gid(宿主机 `id <用户>`),
# 否则 SQLite WAL 写库报 readonly
TAG=$(git rev-parse --short HEAD) ./deploy.sh
curl -fsS http://127.0.0.1:4173/ >/dev/null && echo healthy
```
部署前手工备份(四件套 + 镜像 tag 存档):
```bash
STAMP=$(date +%Y%m%d-%H%M%S)
tar -C .. -czf ../backups/source-$STAMP.tar.gz --exclude='../data' --exclude='../.git' .
cp .env ../backups/env-$STAMP
docker exec caiwuzongzhang-app python -c "import sqlite3; s=sqlite3.connect('/app/data/app.db'); d=sqlite3.connect('/tmp/b.db'); s.backup(d); d.close(); s.close()"
docker cp caiwuzongzhang-app:/tmp/b.db ../backups/app.db.$STAMP
```
## 3.1 正式环境部署(同宿主机隔离,2026-08-30 首次上线采用)
测试与正式同宿主机并行,靠 compose 项目名/容器名/端口三隔离:
| 项 | 测试环境 | 正式环境 |
|---|---|---|
| 目录 | `/home/leefer/caiwuzongzhang-test` | `/home/leefer/caiwuzongzhang-prod` |
| compose 项目 | `deploy`(默认) | `COMPOSE_PROJECT_NAME=caiwuzongzhang-prod` |
| 应用容器 | `caiwuzongzhang-app` | `caiwuzongzhang-prod-app` |
| 端口 | `4173`(对外) | `127.0.0.1:4174`(仅本机,反代上游) |
| HTTPS | 无 | nginx 反代 `8443``COMPOSE_PROFILES=tls` |
| 访问 | http://192.168.200.36:4173/ | https://192.168.200.36:8443/ |
首次部署顺序:
```bash
git clone <repo> /home/leefer/caiwuzongzhang-prod && cd /home/leefer/caiwuzongzhang-prod
git checkout release/prod
mkdir -p data/files backups && chown -R 10001:10001 data # 容器内 app uid
cd deploy
cp .env.example .env # 按下述差异填写
./tls/gen-cert.sh # 生成内部 CA + 服务器证书(SAN 含对外 IP)
TAG=<发布镜像tag> docker compose up -d # 不带 --build,直接用已验收镜像
docker logs <应用容器> 2>&1 | grep "shown once" # 首启一次性初始口令,只出现一次
```
正式 `.env` 与测试的差异(铁律):
- `COMPOSE_PROJECT_NAME=caiwuzongzhang-prod``APP_CONTAINER_NAME=caiwuzongzhang-prod-app``APP_PORT_MAP=127.0.0.1:4174:4173`
- `COMPOSE_PROFILES=tls``PROXY_CONTAINER_NAME=caiwuzongzhang-proxy``PROXY_PORT_MAP=8443:8443`
- `APP_UID=10001` / `APP_GID=10001`data/ 已 chown 10001
- 管理员用户名自定(如 `jinniu-admin`);**不设** `APP_BOOTSTRAP_ADMIN_PASSWORD`(首启控制台取随机一次性口令,首登立即改密)
- **不设** `APP_LOGIN_RATE_LIMIT_DISABLED`(限流默认开启)
证书与信任分发:
- `tls/certs/ca.crt` 发给各公司电脑安装到「受信任的根证书颁发机构」(安装指引见交接文档);`ca.key`/`server.key` 永不离开宿主机。
- 服务器证书有效期 5 年,到期前用 `./tls/gen-cert.sh` 重签并 `docker compose restart proxy`
## 4. 回滚(应用层,5 分钟内)
```bash
cd deploy && ./rollback.sh <上一个镜像tag>
```
数据层恢复见下节。两套动作互不干扰:应用回滚不改数据;数据恢复不换镜像。
## 5. 备份与恢复演练
- 备份:cron `15 2 * * *` 运行 `deploy/backup.sh`;月结后再手动跑一次。
- 恢复步骤(已演练,隔离环境验证):
1. `mkdir -p /tmp/restore/data && cp backups/daily/app.db.<stamp> /tmp/restore/data/app.db`
2. `tar -C /tmp/restore/data -xzf backups/daily/files.<stamp>.tar.gz`(解出 `files/`
3. 用一份独立 `deploy-restore` 目录(`.env` 指向 `/tmp/restore`、端口错开)`docker compose up -d --build`
4. 核对:`PRAGMA integrity_check`、各表行数、金额合计、`source_files` 哈希清单与生产一致后才可顶替。
- 演练频率:上线前 1 次(HEL-270 已做),之后每季度 1 次,结果记入本文件末尾。
## 6. 巡检与告警
cron `*/5 * * * *` 运行 `deploy/monitor.sh`;连续失败或磁盘 ≥80% 时查看 `deploy/ALERT.log` 并按需扩容/清理。容器重启策略 `unless-stopped`
宿主机 crontableefer2026-08-30 起,正式环境):
```cron
15 2 * * * cd /home/leefer/caiwuzongzhang-prod/deploy && CONTAINER=caiwuzongzhang-prod-app ./backup.sh >> backup.log 2>&1
*/5 * * * * cd /home/leefer/caiwuzongzhang-prod/deploy && CONTAINER=caiwuzongzhang-prod-app HEALTH_URL=http://127.0.0.1:4174/ ./monitor.sh >/dev/null 2>&1
01 3 1 * * rsync -a /home/leefer/caiwuzongzhang-prod/backups/monthly/ /vol1/caiwuzongzhang-backups/monthly/
```
(第三行为月度异盘副本:`/vol1` 是与系统盘不同的物理卷;如后续提供真正的异机目标,改为该目标。)
## 7. 升级数据库
应用启动时自动执行迁移(`MIGRATIONS`,当前版本 10)。迁移只前不改写历史;回退 schema 用对应 down 迁移,先备份后操作。
## 8. 演练记录
- 2026-08-30 HEL-270:备份恢复演练 + 版本回滚演练各 1 次,隔离环境完成,原始证据未改动。详见 HEL-270 验收评论。