生产节点访问 GitHub Release 失败时,改由本机下载 v1.36.2+k3s1 amd64 二进制,使用固定官方 SHA-256 校验后分发到三节点,再让官方安装器跳过远端下载。 同时将运行手册顺序改为先完成公网端口隔离,再安装 K3s。 验证:bash -n、ShellCheck、官方 checksum 获取与节点失败现场。
130 lines
5.4 KiB
Markdown
130 lines
5.4 KiB
Markdown
# EasyAI Gateway 三节点 K3s 高可用运行手册
|
||
|
||
## 范围与目标
|
||
|
||
本手册覆盖宁波、香港、洛杉矶三节点迁移。宁波和香港承载 API、Web、River Worker 与
|
||
CloudNativePG;洛杉矶只作为 K3s server/etcd 仲裁节点,并带
|
||
`easyai.io/witness=true:NoSchedule` 污点。
|
||
|
||
- 健康双库:同步复制,RPO=0。
|
||
- 单库降级:`dataDurability: preferred` 保持写入,`archive_timeout=60s`,灾难 RPO 目标不超过 5 分钟。
|
||
- 数据库故障 RTO:不超过 5 分钟。
|
||
- 应用发布:香港验收后再滚动宁波,计划内零停机。
|
||
- 公网入口:双 NGINX 加人工 AliDNS 切换。接入带健康检查的 GTM 前,不宣称公网入口自动高可用。
|
||
|
||
所有命令从仓库根目录执行。生产凭据仅从 `0600` 的 `.env.local` 和
|
||
`.local-secrets/cluster/` 读取,不进入 Git、发布 manifest 或验收输出。
|
||
|
||
## 实施顺序
|
||
|
||
### 1. 源码与镜像门禁
|
||
|
||
```bash
|
||
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 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 固定镜像:
|
||
|
||
```bash
|
||
./scripts/publish-release-images.sh --components auto
|
||
```
|
||
|
||
### 2. WireGuard 与 K3s
|
||
|
||
```bash
|
||
./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-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。
|
||
|
||
### 3. 平台和入口预置
|
||
|
||
```bash
|
||
./scripts/cluster/bootstrap-platform.sh prepare dist/releases/<SHA>.json
|
||
./scripts/cluster/install-nginx-edges.sh prepare
|
||
./scripts/cluster/install-certificate-sync.sh
|
||
./scripts/cluster/install-legacy-cleaner.sh
|
||
```
|
||
|
||
`prepare` 将应用副本保持在 0,但启动 CNPG 双实例、WAL 归档和每日备份。SecretStore
|
||
的 4 个值从旧 volume 直接导入 Kubernetes Secret,脚本只校验数量与总字节数,不打印值。
|
||
|
||
### 4. 02:00–04:00 切换
|
||
|
||
先执行只读预检:
|
||
|
||
```bash
|
||
./scripts/cluster/migrate-production.sh preflight dist/releases/<SHA>.json
|
||
```
|
||
|
||
进入北京时间窗口后执行:
|
||
|
||
```bash
|
||
./scripts/cluster/migrate-production.sh cutover dist/releases/<SHA>.json
|
||
```
|
||
|
||
脚本依次启用维护页、停止旧 API、完整备份旧 PostgreSQL、上传 OSS、恢复 CNPG、比对数据库
|
||
版本/扩展/catalog/表数/序列/关键行数/抽样 ID、运行 digest 固定 migrator、冻结 Worker 启动
|
||
两地应用、做 NodePort 验收,再切换双 NGINX。公开流量提交后,先启用香港 Worker,再启用宁波
|
||
Worker。旧 Docker PostgreSQL 和数据卷停止但保留,不自动删除。
|
||
|
||
在公共流量提交前,任一步失败或耗时超过 10 分钟都会恢复旧 Docker 与旧 NGINX。公共流量
|
||
提交后禁止自动切回旧数据库,避免双写分叉。
|
||
|
||
## 上线验收
|
||
|
||
```bash
|
||
./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`。日常发布仍使用:
|
||
|
||
```bash
|
||
./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。恢复后不自动回切;确认连接和任务稳定后再择时切回。
|