Files
codex-app-server/deploy/new-host-checklist.md
2026-10-27 00:30:32 +08:00

5.2 KiB
Raw Permalink Blame History

新主机入网清单(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 传镜像,流程已实弹验过:
# 老机导出(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 即可回单机。