Files
easyai-ai-gateway/docs/operations/k3s-ha-runbook.md
T
wangbo 3053ba4925 feat(acceptance): 增加生产同构媒体压力验收模式
引入动态流量门禁、隔离验收身份与协议级 Gemini/Volces 模拟器,覆盖双站点 API、Worker、PostgreSQL、River、账务、回调和媒体物化链路。

新增 P24/P28/P32 容量阶梯、Worker 强杀恢复、真实小流量 canary、CAS 放量和失败保持 validation 的生产编排;Worker 执行槽、连接池、媒体并发和双站点副本数改为环境配置。

验证:Go 全量测试、真实 PostgreSQL 迁移集成测试、迁移安全检查、OpenAPI 生成、ShellCheck、Kustomize、gofmt 和 git diff --check。
2026-07-30 23:06:19 +08:00

6.8 KiB
Raw Blame History

EasyAI Gateway 三节点 K3s 高可用运行手册

范围与目标

本手册覆盖宁波、香港、洛杉矶三节点迁移。宁波和香港承载 API、Web、River Worker 与 CloudNativePG;洛杉矶只作为 K3s server/etcd 仲裁节点,并带 easyai.io/witness=true:NoSchedule 污点。

生产上线前的双节点高媒体负载、Worker 强杀和 P24/P28/P32 容量搜索见 生产同构验收模式与高媒体压力测试

  • 健康双库:同步复制,RPO=0。
  • 单库降级:dataDurability: preferred 保持写入,archive_timeout=60s,灾难 RPO 目标不超过 5 分钟。
  • 数据库故障 RTO:不超过 5 分钟。
  • 应用发布:香港验收后再滚动宁波,计划内零停机。
  • 公网入口:双 NGINX 加人工 AliDNS 切换。接入带健康检查的 GTM 前,不宣称公网入口自动高可用。

所有命令从仓库根目录执行。生产凭据仅从 0600.env.local.local-secrets/cluster/ 读取,不进入 Git、发布 manifest 或验收输出。

实施顺序

1. 源码与镜像门禁

cd apps/api && env -u AI_GATEWAY_TEST_DATABASE_URL go test ./... -count=1
cd apps/api && go vet ./...
pnpm install --frozen-lockfile
pnpm lint
pnpm test
pnpm build
shellcheck -x -P . scripts/cluster/*.sh deploy/kubernetes/easyai-ai-gateway-cluster-release
kubectl kustomize deploy/kubernetes/production >/dev/null
./tests/ci/migrations-test.sh
node scripts/ci-validate-migrations.mjs <当前线上完整GitSHA>

代码提交并推送到 origin/main 后,发布 digest 固定镜像:

./scripts/publish-release-images.sh --components auto

2. WireGuard 与 K3s

./scripts/cluster/bootstrap-wireguard.sh
./scripts/cluster/bootstrap-k3s.sh backup
./scripts/cluster/harden-node-network.sh
./scripts/cluster/bootstrap-k3s.sh install
./scripts/cluster/verify-k3s-quorum.sh --execute
./scripts/cluster/verify-cluster.sh precutover

backup 会在卸载旧 K3s 前,将 SQLite、manifests 和 staging 资源归档并校验后上传 OSS easyai-ai-gateway/production/pre-ha/install 固定 v1.36.2+k3s1,使用 embedded etcd、静态 Secret 加密、500ms heartbeat 和 5s election timeout。 K3s containerd 同时配置 Docker Hub、GHCR 与 Quay 的镜像端点;已有集群需要滚动刷新时执行:

./scripts/cluster/configure-k3s-registries.sh

verify-k3s-quorum.sh 会依次停止并恢复洛杉矶、香港、宁波 K3s,确认每次剩余两个 server 都保持 etcd quorum。宁波停机可能令香港数据库副本晋升;首次切换前如需恢复宁波 初始主库,显式执行 promote-cnpg-primary.sh,故障恢复流程不得自动回切。

3. 平台和入口预置

./scripts/cluster/bootstrap-platform.sh prepare dist/releases/<SHA>.json
./scripts/cluster/install-cnpg-plugin.sh
./scripts/cluster/install-etcdutl.sh
./scripts/cluster/install-nginx-edges.sh prepare
./scripts/cluster/install-certificate-sync.sh
./scripts/cluster/install-legacy-cleaner.sh

prepare 将应用副本保持在 0,但启动 CNPG 双实例、WAL 归档和每日备份。OSS 的 Barman 链路使用 s3.oss-cn-shanghai.aliyuncs.com、virtual-hosted addressing 和 boto3 Signature V2AWS_CONFIG_FILE 通过 CNPG projected ConfigMap 同时挂载到主库、副本及恢复 集群。预检会强制产生并归档一个新 WAL,并要求 48 小时内至少存在一份完成的全量备份。 SecretStore 的 4 个值从旧 volume 直接导入 Kubernetes Secret,脚本只校验数量与总字节数,不打印值。

首次切换前如滚动安装令主库落在香港,可显式切回宁波。故障晋升后禁止自动执行该命令:

./scripts/cluster/promote-cnpg-primary.sh easyai-postgres-1

4. 02:0004:00 切换

先执行只读预检:

./scripts/cluster/migrate-production.sh preflight dist/releases/<SHA>.json

进入北京时间窗口后执行:

./scripts/cluster/migrate-production.sh cutover dist/releases/<SHA>.json

脚本依次启用维护页、停止旧 API、完整备份旧 PostgreSQL、上传 OSS、恢复 CNPG、比对数据库 版本/扩展/catalog/表数/序列/关键行数/抽样 ID、运行 digest 固定 migrator、冻结 Worker 启动 两地应用、做 NodePort 验收,再切换双 NGINX。公开流量提交后,先启用香港 Worker,再启用宁波 Worker。脚本等待切换后的 CNPG 全量备份状态变为 completed 后,才停止旧 Docker PostgreSQL;数据卷继续保留,不自动删除。

在公共流量提交前,任一步失败或耗时超过 10 分钟都会恢复旧 Docker 与旧 NGINX。公共流量 提交后禁止自动切回旧数据库,避免双写分叉。

上线验收

./scripts/cluster/verify-cluster.sh postcutover
./scripts/cluster/run-cross-node-file-e2e.sh
./scripts/cluster/failure-drill.sh api --execute
./scripts/cluster/failure-drill.sh database --execute
./scripts/cluster/failure-drill.sh witness --execute
./scripts/cluster/restore-backup-drill.sh --execute
./scripts/cluster/verify-etcd-backup.sh

跨节点 E2E 通过宁波私有 NGINX 固定进入宁波 API,关闭宁波 River Worker,由香港 Worker 执行真实 multipart 图片编辑任务;校验输入和输出 URL 在两节点下载的长度与 SHA-256 一致,并检查 river_job.attempted_by、唯一成功 attempt、唯一结算/扣费及无重复回调。

数据库故障演练会强制删除当前主 Pod,确认 5 分钟内晋升;在副本恢复前写入一条专用 system_settings 探针,恢复同步后删除。备份恢复演练会从 OSS 创建一个独立 CNPG Cluster, 验证数据库登录、schema、行数和抽样值后删除临时 Cluster 与 PVC。

发布与回滚

切换成功后,本地环境自动设置 AI_GATEWAY_DEPLOY_MODE=kubernetes。日常发布仍使用:

./scripts/deploy-production-release.sh dist/releases/<SHA>.json
./scripts/deploy-production-release.sh --status
./scripts/deploy-production-release.sh --rollback <历史完整SHA>

集群 helper 从 easyai-gateway-release ConfigMap 读取当前 release,数据库迁移前先等待一次 CNPG 备份,然后香港滚动、验收,再滚动宁波。--rollback 只恢复应用 digest,绝不逆向执行迁移。

旧文件与公网故障

宁波每小时执行一次清理,以当前时间减文件 mtime 严格大于 86,400 秒为删除条件。未过期 文件由宁波只读 NGINX 提供,香港通过 WireGuard 回源。清理结果持续为 0 个存量文件后,删除 两个 legacy static include 和宁波 18080 origin;历史过期 URL 返回 410。

公网入口故障时,先使用 curl --resolve 确认香港入口健康,再人工将 ai.51easyai.com AliDNS A 记录切到香港 IP。恢复后不自动回切;确认连接和任务稳定后再择时切回。