# TopFans K8s / Helm 部署手册 (Phase 1) > Phase 1: 单 namespace `topfans` 合并部署, 10 个 Go 服务 + gateway 共享一套基础设施, > Postgres / Redis 走阿里云 RDS / ElastiCache ExternalName。 > > 设计文档: [`../docs/superpowers/specs/2026-06-08-docker-to-k8s-migration-design.md`](../docs/superpowers/specs/2026-06-08-docker-to-k8s-migration-design.md) > > ⚠️ Phase 2 (按组隔离) 不在本手册范围, 见设计文档第十一章。 ## 目录结构 ``` k8s/ ├── README.md # 本文件 ├── deploy.sh # Helm / K8s 部署脚本 (主入口) ├── helm/ │ └── topfans/ # 单个 chart, 覆盖整个 Phase 1 │ ├── Chart.yaml │ ├── values.yaml # 默认值 (CI/Dev 用) │ ├── values-prod.example.yaml # 模板 (空值, 部署时 cp 后填) │ └── templates/ │ ├── _helpers.tpl │ ├── 00-namespace.yaml │ ├── gateway/ ... # 13 个服务各自子目录 │ ├── hpa/ ... # 3 个 HPA │ ├── secrets/ ... # 4 个 Secret │ ├── external-db/ ... # postgres / redis ExternalName │ ├── ingress.yaml │ ├── pg-sequence-sync.yaml # 切流量前必跑的 hook Job │ ├── oss-cors-init/job.yaml │ └── future-services/ ... # 4 个未来服务 .gitkeep └── jobs/ └── pg-sequence-sync/ # 独立手动跑版本 (备份用) ├── script.sh └── job-template.yaml ``` ## 首次部署 (Checklist) 按顺序完成: ### 1. 集群与基础设施 - [ ] 阿里云 ACK 测试集群创建 (按设计文档 §六 Step 1, 推荐) - [ ] 装 `nginx-ingress-controller` (Helm, 集群级别) - [ ] 装 `cert-manager` (Helm, 集群级别) - [ ] 创建 ClusterIssuer `letsencrypt-prod` (用 DNS-01 校验) - [ ] 创建 namespace `topfans` (helm install 时自动 create, 也可提前 `kubectl create ns topfans`) - [ ] 创建阿里云 RDS (PostgreSQL) + 用阿里云 DTS 把 VM 的数据迁过去 - [ ] 创建阿里云 ElastiCache (Redis), 同步数据 (如果有) - [ ] **PG 端连通验证**: `psql -h ` 确认能连上, schemata 在 ### 2. CI 镜像仓库 - [ ] 阿里云 ACR 创建 namespace `topfans`, registry 是 `registry.cn-shanghai.aliyuncs.com` - [ ] CI (GitHub Actions / 阿里云云效) 配 ACR push 凭据, 跑通 `gateway:v1.0.0` 一个 image - [ ] (`Dockerfile.services` 多阶段构建已 OK, 无需改) ### 3. 真值 values-prod.yaml **推荐用交互脚本生成** (避免在 example 里写假值被误部署): ```bash ./k8s/scripts/fill-values-prod.sh # 交互式提示输入 DB / Redis / JWT / OSS / Dify / OpenAI / SMS 真值 # 写完自动 chmod 600 + 检查 .gitignore + 用 gitleaks/detect-secrets 扫描 (如已装) # CI 模式: 全用环境变量 ./k8s/scripts/fill-values-prod.sh --non-interactive # 写完用 sops 加密 (加密文件可入 git) ./k8s/scripts/fill-values-prod.sh --sops # 只看不写 ./k8s/scripts/fill-values-prod.sh --dry-run ``` 手写版 (不推荐, 易出拼错): ```bash cd k8s/helm/topfans cp values-prod.example.yaml values-prod.yaml chmod 600 values-prod.yaml $EDITOR values-prod.yaml # 重点字段: # global.dbExternalEndpoint: rm-xxxxxx.mysql.rds.aliyuncs.com # global.redisExternalEndpoint: r-xxxxxx.redis.rds.aliyuncs.com # services..image.tag: (CI 注入, 或先用 latest) # secrets.* : DB / JWT / OSS / AI / SMS 真值 ``` ⚠️ **`values-prod.yaml` 不进 git** (`.gitignore` 已加, 脚本会二次确认)。 ### 4. 首次部署 ```bash cd /path/to/repo ./k8s/deploy.sh install ``` 会自动按顺序: 1. `helm.sh/hook pre-install` 创建 namespace 2. `helm.sh/hook pre-install` 跑 PG sequence sync (如果 `pgSequenceSync.enabled=true`) 3. `helm.sh/hook pre-install` 跑 oss-cors-init (Job 跑完即退) 4. 创建所有 Service / Deployment / Secret / ConfigMap / HPA 5. `helm.sh/hook pre-install` (其实是 `Install` 阶段) 跑完等 Pod Ready ### 5. Ingress 域名与 TLS ```bash # 改 ingress 内的 host $EDITOR k8s/helm/topfans/values-prod.yaml # ingress.hosts[0].host: api.example.com # ingress.tls[0].hosts[0]: api.example.com # 解析到 nginx-ingress-controller 的 external IP kubectl get svc -n ingress-nginx # api.example.com A 记录 → ./k8s/deploy.sh upgrade --reuse-values ``` ## 升级流程 (日常) ```bash # 1. CI 已经把镜像推到 ACR: # registry.cn-shanghai.aliyuncs.com/topfans/gateway:v1.0.1 # registry.cn-shanghai.aliyuncs.com/topfans/userservice:v1.0.1 # ... (13 个 image 都标 v1.0.1) # 2. 把所有 service 的 image tag 改成新版本: ./k8s/deploy.sh upgrade v1.0.1 # 实质执行: # helm upgrade topfans ./helm/topfans \ # -f values-prod.yaml \ # --set global.image.tag=v1.0.1 \ # --wait --timeout 10m ``` `helm upgrade --wait` 会按 readinessProbe 等到所有 Pod Ready 才返回, 失败的话 Exit code 非 0, deploy.sh 提示回滚。 ## 回滚 ```bash # 看历史 ./k8s/deploy.sh history # (helm history 通过 deploy.sh status 子命令也看得到) # 回滚到上一版 ./k8s/deploy.sh rollback # 回滚到指定 revision ./k8s/deploy.sh rollback 3 ``` ## PostgreSQL 序列同步 (Hard Blocker) > **CLAUDE.md 强制规范 + 设计文档 §10.3 标记为 Hard Blocker** > 任何手动 INSERT id 都必须配套 setval; 切流量前必跑。 ```bash ./k8s/deploy.sh sync-pg # 同步 + 验证 ./k8s/deploy.sh sync-pg --status # 只验证 ``` 挂在 Helm 上的版本 (设计文档 §六 Step 4 提到的方案): - `helm install / upgrade` 自动跑 `templates/pg-sequence-sync.yaml` (helm hook, weight=-8) - 失败 abort deployment **何时必须手动跑** (用 `deploy.sh sync-pg`): 1. 首次切流量前 2. 任何 backfill SQL (含手动 INSERT) 后 3. 数据迁移测试期间, 反复切换期间 ## Secret 管理 (最低要求) 真值 **必须** 通过以下任一方式入 K8s,**严禁**把 values-prod.yaml 入 git: | 方式 | 说明 | 适用 | |---|---|---| | **kubectl create secret** | 手 kubectl create secret 加 Secret, helm 不管 | 1-2 人小团队 | | **CI/CD 注入** | CI 流水线 kubectl apply / helm install --set 注入 | 推荐 | | **SOPS + Git** | values-prod.yaml sops -e 加密后入 git, CI decrypt | 多环境共享 | | **External Secrets Operator** | 接阿里云 KMS, 动态拉真值 | Phase 2+ | 当前 **Phase 1 默认用 kubectl create secret** (最快上手), 后续切 SOPS。 ## 监控 / 日志 (设计文档 §六 Step 6, 可选) 不阻塞 Phase 1 上线, 上线后补: - Prometheus Operator (集群级) - Grafana dashboard (按 dubbo / DB / Redis 分类) - Loki + Promtail (日志聚合) - 阿里云 ARMS (一键接入, 推荐) ## 常见问题 ### Q: helm install 报 `duplicate key on secret` / `ServerTimeout` **A**: 上一次 helm install 没清干净。`helm uninstall topfans` 再重试。 ### Q: PG 序列同步失败, 报 `setval: sequence_name not found` **A**: 说明该 BIGSERIAL 表要么不存在, 要么 sequence 名拼错, 可能表没建好。 连 RDS 验证: `\d+ assets` 看最下方的 `Sequence: assets_id_seq` 是否对得上。 ### Q: 容器启动后卡在 Init 或 CrashLoopBackOff **A**: 看日志: `kubectl logs -n topfans --previous` 常见: - DB 连接不上: 检查 `secrets/db/db.password` 是否对, RDS 安全组是否放行 K8s 节点 CIDR - OSS 配置缺: `oss-credentials` Secret 没建, helm uninstall + 重装 ### Q: HPA 不工作 **A**: `kubectl get hpa -n topfans` 看是不是 `Unknown`, 通常是没有 metrics-server。 Phase 1 实施时安装 metrics-server (Helm, 一般 ingress-nginx chart 一起装)。 ### Q: 各服务的 healthcheck 通不过 **A**: 各服务的 healthcheck path 不一致, 见 `values.yaml.services..healthPath`: - 大多数用 `/health` - `statisticservice` / `notificationservice` 用 `/healthz` - `moderationservice` 用 `/` (历史原因, 不修, 见设计文档 §10.4) --- ## 参考 - 设计文档: `../docs/superpowers/specs/2026-06-08-docker-to-k8s-migration-design.md` - Helm 官方文档: https://helm.sh/docs/ - 阿里云 ACK: https://help.aliyun.com/product/85222.html - 阿里云 ACR: https://help.aliyun.com/product/60716.html 最后更新: 2026-07-06 (Phase 1 首版)