112 lines
5.2 KiB
Markdown
112 lines
5.2 KiB
Markdown
# 新主机入网清单(HA 阶段 4)
|
||
|
||
新机加入前,老机继续全量服务;新机全部验证通过后才切流量。
|
||
清单里的路径与实测值以 2026-10-26 主机为准,变了同步改。
|
||
|
||
## 1. 系统与用户
|
||
|
||
- Ubuntu 24.04、Python 3.12、git、Docker(与老机同大版本)、
|
||
Node 18(装 codex 用)。
|
||
- 建 `codexsvc`(uid 1003、gid 1004)并加入 `docker` 组。
|
||
- NTP:`timedatectl` 确认 `NTPSynchronized=yes`(心跳、超时、
|
||
sweep 全依赖时钟,不同步会出现“活任务被误扫”)。
|
||
|
||
## 2. 代码与目录
|
||
|
||
- `/opt/codex-app-server`:部署 tar 解包,`chown -R codexsvc`。
|
||
- `/var/lib/codex-app-server/`:建 `tenants/`、`repos/`、
|
||
`codex-home/`(模板)、`backups/`(700)。
|
||
- `/etc/codex-app-server/env`(0600 root):与老机一致,尤其
|
||
`CLOUD_DB_PASSWORD`(新卷 Postgres 的初始化口令必须等于它,
|
||
见 `postgres-rebuild.md` 场景 B)、relay key、GitHub OAuth
|
||
secret、webhook secret。密钥绝不进仓库、不进部署 tar。
|
||
|
||
## 3. 数据库
|
||
|
||
- 有现成 Postgres 时:env 里改 `CLOUD_DB_HOST/PORT` 指向它。
|
||
- 没有时:按 `postgres-rebuild.md` 场景 B 重建(新卷 + 最新备份
|
||
恢复 + 四表校验),再起 server。
|
||
|
||
## 4. 服务 units(都在 `deploy/` 里有参考文件,unit 文件不在
|
||
## deploy tar 里,须单独 scp 到 `/etc/systemd/system/` 再
|
||
## daemon-reload + enable + start)
|
||
|
||
- `codex-cloud-server`(8765)与 `codex-cloud-server-2`(8766)
|
||
双机;`codex-autoscaler`(min 1 / max 2、per-worker capacity 2、
|
||
`--docker-runtime runsc`);`codex-host-worker`(local,
|
||
`--claim-executor-only`,经 `aa-exec -p codex-host` 跑);
|
||
`codex-pg-backup.timer`(每天 03:00 CST);
|
||
`monitor.timer`(每 5 分钟)。
|
||
- 注意:`codex-cloud-worker` 已停用(autoscaler 接管),绝不能
|
||
与 autoscaler 同时跑。
|
||
|
||
## 5. 沙箱与隔离
|
||
|
||
- AppArmor:加载 `docker-codex` 与 `codex-host` 两个 profile
|
||
(`deploy/apparmor/` 下);`codex-host` 的坑已修过(capability
|
||
放行只是 userns 内假 root;`network netlink raw` 必须允许且
|
||
deny raw 须写明 inet/inet6;`/tmp` 不隔离,见 HA-DESIGN)。
|
||
- Docker:`daemon.json` 注册 runsc(`/usr/local/bin/runsc` +
|
||
**必须成对**的 `/usr/local/bin/gvisor-bin/`,只拷 runsc 会报
|
||
sidecar 不可用);默认仍 runc,生产任务经 worker flag 走 runsc。
|
||
- 镜像:见第 7 节。
|
||
|
||
## 6. 出口代理(每机一份,改动时同批下发,不要手工各改各的)
|
||
|
||
- 拷 `/etc/tinyproxy/tinyproxy.conf` 与
|
||
`/etc/tinyproxy/tinyproxy-filter`(**644**,tinyproxy 用户可读;
|
||
Filter 是 **POSIX BASIC regex**,extended 写法会把允许域名也
|
||
挡成 403;没有合法的 `Upstream none` 写法,直接连接就是默认)。
|
||
- 白名单只放行 xcmapi.org、github.com、pypi.org、npmjs.org
|
||
及子域;iptables 只放行 `172.16.0.0/12` 与 `127.0.0.1`
|
||
(`iptables-save` 导出、到新机 `iptables-restore`)。
|
||
- Docker 任务容器出口走宿主 8888 代理(worker 的
|
||
`--egress-proxy-port 8888`)。
|
||
|
||
## 7. 镜像传输(现阶段:docker save/load,不建无鉴权 registry)
|
||
|
||
- 没有带鉴权 + TLS 的 registry 时,**不要**在本机跑无鉴权
|
||
registry(谁都能推恶意镜像,等于把 worker 的执行环境交给
|
||
任何人)。新机用 save/load 传镜像,流程已实弹验过:
|
||
|
||
```sh
|
||
# 老机导出(919MB,注意磁盘余量)
|
||
docker save codex-app-server:latest -o /tmp/codex-image.tar
|
||
# 传到新机(scp 或 chunk_send,传完 sha256 比对)
|
||
# 新机导入(幂等,已有同名镜像时只是重加已有层,不删东西)
|
||
docker load -i /tmp/codex-image.tar
|
||
docker images codex-app-server
|
||
```
|
||
|
||
- host 2 落地后,再评估带鉴权 + TLS 的 registry(或云厂商的
|
||
容器镜像服务),届时把“新机拉镜像”一步换成 `docker pull`。
|
||
|
||
## 8. 入口(nginx)
|
||
|
||
- 拷 vhost(含三个 codex location)与 `codex-upstream.conf`
|
||
(upstream 块只能在 http 段,不能放进 server 块)。
|
||
- 宝塔重生成 vhost 会吃掉 location,备份在
|
||
`/etc/codex-app-server/` 与 vhost 目录的 `.pre-*` 文件里,
|
||
被吃时从备份贴回,再 `nginx -t` + reload。
|
||
- 双机 nginx(浮动 IP keepalived,同机房;或 DNS 轮询 + 健康
|
||
检查,跨机房)**需要第二台主机才能演练**,现阶段单机 nginx
|
||
仍是单点,见 HA-DESIGN 阶段 4。
|
||
|
||
## 9. 入网验证(全部通过才切流量)
|
||
|
||
1. `monitor.sh` 全过(含 backup 项)。
|
||
2. 双 server health(8765、8766)均为 ok 且 db_ok。
|
||
3. autoscaler 正常(`--host-name` 已传宿主名,见 worker 进程
|
||
命令行),worker 注册表里有新机 worker。
|
||
4. 一个 Docker 任务端到端完成(worktree_host 应为新机主机名)。
|
||
5. `/pr` 同步路(本机 worktree)与队列路(改写 worktree_host
|
||
后排队、pr-runner 跑通)各一次。
|
||
6. 备份 timer 下次触发时间正常(`systemctl list-timers`)。
|
||
|
||
## 10. 回滚
|
||
|
||
- 新机任何一步失败:停新机服务,老机不受影响(老机从未停过,
|
||
流量也从未切过)。
|
||
- 切流量后发现问题:nginx upstream 先摘掉新机端口(或把三个
|
||
location 的 proxy_pass 指回老机单端口),reload 即可回单机。
|