Per user feedback: admin/review/ai-image-gen/ai-chat are completely new independent systems with their own codebases and DBs, not reusing existing services. They only have API-level calls between each other and to existing services. Section 1.3 table and 'key clarification' paragraph updated. Other 'shared' references in the document refer to the platform-architecture sense (shared services for all groups), not code reuse, so no other changes needed.
591 lines
24 KiB
Markdown
591 lines
24 KiB
Markdown
# Docker → Kubernetes 迁移 设计文档
|
||
|
||
- 日期: 2026-06-08
|
||
- 涉及模块: `docker/` 全部产物、新增 `k8s/` 目录、未来四个新服务
|
||
- 现状: `docker-compose.prod.yml` 在单台 VM (`101.132.250.62`) 上跑 10 个 Go 服务 + Postgres + Redis
|
||
- 目标: 迁移到 Kubernetes,支持按"明星组"分服务器扩展,为新服务(admin/review/ai-image-gen/ai-chat)预留接入位
|
||
|
||
---
|
||
|
||
## 一、背景与动机
|
||
|
||
### 1.1 业务背景
|
||
|
||
TopFans 是一个"明星粉丝平台"。不同明星的粉丝量差异极大:
|
||
|
||
- **头部明星**: 单明星可占整平台 50%+ 流量,需要独立扩展
|
||
- **腰部明星**: 几个明星可共享资源池
|
||
- **尾部明星**: 大量冷启动明星,合并部署降低成本
|
||
|
||
运营方希望:**针对不同明星组,可以独立分配服务器资源、互不影响。**
|
||
|
||
### 1.2 当前架构瓶颈
|
||
|
||
`docker-compose.prod.yml` 是单机部署,本质限制:
|
||
|
||
| 能力 | Docker Compose | Kubernetes |
|
||
|---|---|---|
|
||
| 多机部署 | ❌ | ✅ |
|
||
| 按业务线隔离资源 | ❌ | ✅ (namespace + ResourceQuota) |
|
||
| 自动扩缩容 | ❌ | ✅ (HPA/KEDA) |
|
||
| 滚动升级 | 手动 | ✅ |
|
||
| 故障自愈 | 手动 | ✅ |
|
||
| 新增业务线 | 改 compose | helm install |
|
||
|
||
### 1.3 即将到来的新服务
|
||
|
||
代码或 PRD 中已提及、未来需要独立部署的**全新系统**(非复用现有服务,各自独立代码库、独立 DB,只通过 API 互相调用):
|
||
|
||
| 服务 | 作用 | 关系 |
|
||
|---|---|---|
|
||
| `admin` | 后台管理平台(运营、客服) | **独立系统**,通过 API 调用 userservice / 其他服务 |
|
||
| `review` | 审核工作流(UGC 内容审核) | **独立系统**,通过 API 调用 assetservice 读取待审内容,审核结果回写自己的 DB |
|
||
| `ai-image-gen` | AI 图片生成(镭射卡) | **独立系统**,gateway 改为通过 API 调用它(原 MiniMax 调用逻辑迁过去) |
|
||
| `ai-chat` | AI 对话(粉丝互动) | **独立系统**,前端通过 API 调用它(从 aichatservice 拆出来) |
|
||
|
||
> **关键澄清**: 这四个服务与现有 `userservice` / `assetservice` / `aichatservice` 等**没有代码级复用关系**,也没有共享 DB schema。它们是完全独立的新服务,通过 HTTP/gRPC API 互相调用。K8s 迁移任务只负责**为它们预留 namespace 位置和部署模板**,不涉及实现。
|
||
|
||
---
|
||
|
||
## 二、候选方案 (三个架构 + 优缺点对比)
|
||
|
||
### 2.1 方案 A:单租户架构 (应用层多租户)
|
||
|
||
**结构**: 集群里只部署**一份**完整的微服务栈,所有明星组共享,通过 `group_id` 在应用层和数据层做隔离。
|
||
|
||
```
|
||
namespace: topfans
|
||
├── gateway, userservice, assetservice, galleryservice, ...
|
||
├── postgres (一份,所有组数据混在一起,用 group_id 区分)
|
||
└── redis (一份,key 加 group: 前缀)
|
||
```
|
||
|
||
**优点**:
|
||
|
||
1. **部署最简单**: 只有一套 deployment,运维心智负担最低
|
||
2. **资源利用率最高**: 没有"为低流量组预留资源"的浪费
|
||
3. **代码改动最小**: 完全沿用现有 docker-compose 的服务间调用方式
|
||
4. **配置最少**: 只需要一份 values.yaml
|
||
|
||
**缺点**:
|
||
|
||
1. ❌ **吵市占率问题严重**: 头部明星的爆款活动会拖慢所有其他明星
|
||
2. ❌ **无法"按明星分服务器"**: 这正是用户提的核心需求
|
||
3. ❌ **故障爆炸半径大**: gateway 单点故障影响所有组
|
||
4. ❌ **扩容粒度粗**: 只能整体扩,无法精准给某个组加机器
|
||
5. ❌ **合规/数据隔离弱**: 某些明星可能有合规要求(肖像、隐私),数据物理混在一起不好处理
|
||
6. ❌ **不满足用户的根本需求**: 用户明确说"分服务器使用",此方案做不到
|
||
|
||
**适用场景**: 业务初期、流量小、组少(<3)、无合规要求。
|
||
|
||
**结论**: **不推荐**。与用户需求正面冲突。
|
||
|
||
---
|
||
|
||
### 2.2 方案 B:共享基础服务 + 按组隔离数据服务 ⭐ 推荐
|
||
|
||
**结构**: 平台型服务全集群一份(放 `topfans-shared`),数据敏感型服务按组复制(放 `topfans-group-*`)。
|
||
|
||
```
|
||
namespace: topfans-shared (平台共享,1 份)
|
||
├── admin (未来)
|
||
├── review (未来)
|
||
├── ai-image-gen (未来)
|
||
├── ai-chat (未来)
|
||
└── (Postgres / Redis 走外部托管,K8s 内只放 ExternalName 占位)
|
||
|
||
namespace: topfans-group-<group-name> (每组 1 个,1+ 明星)
|
||
├── gateway ← 入口,组内独享
|
||
├── userservice, assetservice, galleryservice,
|
||
│ socialservice, activityservice, starbookservice,
|
||
│ taskservice, aichatservice, lasercompositor
|
||
├── ResourceQuota ← 防吵市占率
|
||
└── LimitRange ← 单 Pod 上限
|
||
|
||
Ingress (集群级)
|
||
├── *.api.example.com → 按 Host 路由
|
||
└── admin.api.example.com → topfans-shared/admin
|
||
```
|
||
|
||
**优点**:
|
||
|
||
1. ✅ **核心数据服务可按组独立扩缩容** (用户核心需求)
|
||
2. ✅ **Gateway 也按组分**,Dubbo tri:// 协议栈短 DNS 名就够用,应用代码零改动
|
||
3. ✅ **共享服务复用**: AI 模型权重不可能每组复制,放 shared 反而合理
|
||
4. ✅ **故障隔离**: 一个组的 gateway 挂了不影响其他组
|
||
5. ✅ **可加新组成本极低**: `helm install` 一行,无需改应用代码
|
||
6. ✅ **运维友好**: 每组 namespace 独立,`kubectl config set-context --namespace=...` 即可隔离操作
|
||
7. ✅ **ResourceQuota + LimitRange 双层防爆**: 既控总量又控单 Pod
|
||
8. ✅ **新服务天然接入**: `admin / review / ai-*` 放 shared,一次部署全集群可用
|
||
|
||
**缺点**:
|
||
|
||
1. ⚠️ **管理面多**: 每组要单独做一次 helm install(可由 CI/CD 自动化)
|
||
2. ⚠️ **Pod 数量较多**: 9 数据服务 × N 组 = 较多 Pod,但 K8s 调度能 handle
|
||
3. ⚠️ **DB 仍是中心化**: Postgres 走外部托管,流量大时需做读写分离或拆库(后续可加 K8s 内的只读副本 Service)
|
||
4. ⚠️ **AI 服务被多个组共享**: 需要做 rate limit / quota 防止某组把 AI 资源吃光(可在 gateway 层加限流)
|
||
5. ⚠️ **首次配置稍复杂**: 要给每组填一份 values.yaml,但模板化后还好
|
||
|
||
**适用场景**: 中型平台、有明显头部尾部差异、需要合规隔离、为未来扩展留空间。**完全匹配用户需求**。
|
||
|
||
**结论**: **强烈推荐**。
|
||
|
||
---
|
||
|
||
### 2.3 方案 C:完全独立每组(含 AI/审核/管理也复制)
|
||
|
||
**结构**: 每个明星组独立一个 namespace,里面有**完整**的服务栈,包括 admin / review / AI。
|
||
|
||
```
|
||
namespace: topfans-group-a
|
||
├── gateway, userservice, assetservice, ... (9 个数据服务)
|
||
├── admin, review, ai-image-gen, ai-chat (平台服务也复制)
|
||
└── (无外部 DB,每组有独立 PG/Redis)
|
||
```
|
||
|
||
**优点**:
|
||
|
||
1. ✅ **物理级隔离**: 任何资源共享都不存在
|
||
2. ✅ **故障爆炸半径最小**: 一组全挂不影响其他组
|
||
3. ✅ **合规最优**: 数据完全分开
|
||
4. ✅ **可独立选择技术栈**: 每组可用不同版本
|
||
|
||
**缺点**:
|
||
|
||
1. ❌ **AI 模型权重不可能每组复制**: 一个 LLaVA/SD 模型几十 GB,几个组就是几 TB,启动慢、内存贵
|
||
2. ❌ **运维噩梦**: N 个组要维护 N 套全栈,版本同步、配置漂移都是问题
|
||
3. ❌ **资源严重浪费**: 小流量组根本用不上那么多资源
|
||
4. ❌ **新服务接入要 N 次部署**: 加一个 ai-image-gen 要 N 个 namespace 改一遍
|
||
5. ❌ **与用户实际需求不匹配**: 用户没要求"AI 也每组独立"
|
||
|
||
**适用场景**: 金融、医疗、政企等强合规、且客户付费意愿足够高的场景。
|
||
|
||
**结论**: **不推荐**。对本业务过度设计。
|
||
|
||
---
|
||
|
||
## 三、方案对比总结表
|
||
|
||
| 维度 | 方案 A 单租户 | 方案 B 共享+按组隔离 ⭐ | 方案 C 完全隔离 |
|
||
|---|---|---|---|
|
||
| 部署复杂度 | ⭐ 最低 | ⭐⭐ 中等 | ⭐⭐⭐ 最高 |
|
||
| 资源利用率 | ⭐⭐⭐ 最高 | ⭐⭐ 中等 | ⭐ 最低 |
|
||
| 按组扩缩容 | ❌ 不支持 | ✅ 完美支持 | ✅ 完美支持 |
|
||
| 故障爆炸半径 | 大 | 中(按组) | 小(按组) |
|
||
| 吵市占率 | 严重 | 轻(ResourceQuota 控) | 几乎无 |
|
||
| AI 资源浪费 | 无 | 低(共享) | 严重(每组一份) |
|
||
| 新服务接入成本 | 1 次 | 1 次(放 shared) | N 次(每组) |
|
||
| 数据合规隔离 | 弱 | 中(逻辑隔离) | 强(物理隔离) |
|
||
| 与"分服务器"需求匹配 | ❌ | ✅ | ✅ |
|
||
| **推荐度** | ❌ | ✅✅✅ 强烈推荐 | ❌ |
|
||
|
||
---
|
||
|
||
## 四、推荐方案 (B) 详细设计
|
||
|
||
### 4.1 集群拓扑
|
||
|
||
```
|
||
K8s 集群
|
||
│
|
||
├── namespace: topfans-shared
|
||
│ ├── (未来) admin — Deployment + Service
|
||
│ ├── (未来) review — Deployment + Service
|
||
│ ├── (未来) ai-image-gen — Deployment + Service
|
||
│ ├── (未来) ai-chat — Deployment + Service
|
||
│ ├── postgres-ext — Service (ExternalName → RDS endpoint)
|
||
│ ├── redis-ext — Service (ExternalName → ElastiCache endpoint)
|
||
│ ├── db-credentials — Secret
|
||
│ └── oss-credentials — Secret
|
||
│
|
||
├── namespace: topfans-group-<group-name> (例: topfans-group-a)
|
||
│ ├── ResourceQuota (CPU/内存/Pod 总上限)
|
||
│ ├── LimitRange (单 Pod 默认值)
|
||
│ ├── gateway — Deployment + Service (ClusterIP) + ConfigMap + Secret
|
||
│ ├── userservice — Deployment + Service (ClusterIP) + ConfigMap
|
||
│ ├── assetservice — 同上
|
||
│ ├── galleryservice — 同上
|
||
│ ├── socialservice — 同上
|
||
│ ├── activityservice — 同上
|
||
│ ├── starbookservice — 同上
|
||
│ ├── taskservice — 同上
|
||
│ ├── aichatservice — 同上
|
||
│ └── lasercompositor — 同上
|
||
│
|
||
└── Ingress (集群级,Gateway API 或传统 Ingress)
|
||
├── group-a.api.example.com → topfans-group-a/gateway:8080
|
||
├── group-b.api.example.com → topfans-group-b/gateway:8080
|
||
├── admin.api.example.com → topfans-shared/admin:80
|
||
└── ... (按 Host 头或 path 路由)
|
||
```
|
||
|
||
### 4.2 关键设计点
|
||
|
||
#### 4.2.1 Gateway 放在每组 namespace 内 (而不是 shared)
|
||
|
||
**原因**: Dubbo `tri://` 是 TCP 二进制协议,K8s Ingress / Service 无法做基于 HTTP Host/Path 的智能路由。
|
||
|
||
把 gateway 放在组内,可以让组内服务间用短 DNS 名调用:
|
||
|
||
```yaml
|
||
# 组内 gateway 的环境变量 (相对原 compose 几乎无改动)
|
||
DUBBO_USER_SERVICE_URL: tri://userservice:20000 # 同 ns 短名
|
||
DUBBO_ASSET_SERVICE_URL: tri://assetservice:20003
|
||
DUBBO_SOCIAL_SERVICE_URL: tri://socialservice:20002
|
||
DUBBO_GALLERY_SERVICE_URL: tri://galleryservice:20001
|
||
DUBBO_ACTIVITY_SERVICE_URL: tri://activityservice:20004
|
||
DUBBO_TASK_SERVICE_URL: tri://taskservice:20006
|
||
DUBBO_STARBOOK_SERVICE_URL: tri://starbookservice:20005
|
||
DUBBO_AI_CHAT_SERVICE_URL: tri://aichatservice:20008
|
||
LASER_COMPOSITOR_URL: http://lasercompositor:7002
|
||
```
|
||
|
||
**应用代码零改动** — 相对原 `docker-compose.prod.yml` 只需把服务名换成 K8s 短 DNS 名。
|
||
|
||
#### 4.2.2 Postgres / Redis 走外部托管
|
||
|
||
K8s 内只创建 `ExternalName` Service 占位:
|
||
|
||
```yaml
|
||
# topfans-shared/postgres-external.yaml
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: postgres
|
||
namespace: topfans-shared
|
||
spec:
|
||
type: ExternalName
|
||
externalName: rm-xxxxxx.mysql.rds.aliyuncs.com # 阿里云 RDS endpoint
|
||
```
|
||
|
||
**好处**:
|
||
|
||
- K8s 不需要管 StatefulSet / PVC / 备份 / 主从切换(全部交给云服务)
|
||
- 所有组共享同一份数据库,通过 `group_id` 在 schema 层面区分
|
||
- 后续压力大了,云上一键升配即可,无需迁移数据
|
||
|
||
**所有组数据如何隔离**: 在现有表上加 `group_id` 字段,应用层做行级过滤。**这是应用层改动,不在本次 K8s 迁移范围**,但需要在设计文档里记录。
|
||
|
||
#### 4.2.3 ResourceQuota + LimitRange 双层防护
|
||
|
||
```yaml
|
||
# topfans-group-a/resource-quota.yaml
|
||
apiVersion: v1
|
||
kind: ResourceQuota
|
||
metadata:
|
||
name: group-a-quota
|
||
namespace: topfans-group-a
|
||
spec:
|
||
hard:
|
||
requests.cpu: "10" # 总 CPU 申请
|
||
requests.memory: 20Gi # 总内存申请
|
||
limits.cpu: "20"
|
||
limits.memory: 40Gi
|
||
pods: "50" # 最多 50 个 Pod
|
||
persistentvolumeclaims: "5"
|
||
---
|
||
apiVersion: v1
|
||
kind: LimitRange
|
||
metadata:
|
||
name: group-a-limits
|
||
namespace: topfans-group-a
|
||
spec:
|
||
limits:
|
||
- type: Container
|
||
default:
|
||
cpu: 500m
|
||
memory: 512Mi
|
||
defaultRequest:
|
||
cpu: 100m
|
||
memory: 128Mi
|
||
max:
|
||
cpu: 2
|
||
memory: 4Gi
|
||
```
|
||
|
||
#### 4.2.4 镜像构建与推送策略
|
||
|
||
**两种选择**:
|
||
|
||
- **方式 1 (推荐)**: CI 构建镜像推送阿里云 ACR,Helm 通过 `image.tag` 引用
|
||
- **方式 2**: 维持当前 `deploy.sh` 的"本地 build → SSH 推到服务器"流程,服务器装 containerd/nerdctl
|
||
|
||
**推荐方式 1**,原因:
|
||
|
||
- 镜像版本化管理 (`:v1.0.0`)
|
||
- 利用镜像分发,build 一次,所有 K8s 节点共享
|
||
- rollback 简单: `helm rollback topfans-group-a 1`
|
||
|
||
需要在 `Dockerfile.services` 增加 base 镜像 tag 参数(目前是 `FROM --platform=linux/amd64 alpine:3.19`,已 OK),在 CI 脚本里改 tag 即可。
|
||
|
||
#### 4.2.5 健康检查修正
|
||
|
||
原 `docker/Dockerfile.services` 中存在 **HEALTHCHECK 端口错配 bug**:
|
||
|
||
| 服务 | 应用监听 | Dockerfile HEALTHCHECK 用 | 状态 |
|
||
|---|---|---|---|
|
||
| galleryservice | 20001 | 21001 | ❌ 错的,会一直 fail |
|
||
| socialservice | 20002 | 21002 | ❌ 同上 |
|
||
| activityservice | 20004 | 21004 | ❌ 同上 |
|
||
| taskservice | 20006 | 21006 | ❌ 同上 |
|
||
| starbookservice | 20005 | 21005 | ❌ 同上 |
|
||
| aichatservice | 20008 | 21008 | ❌ 同上 |
|
||
|
||
其他服务端口配置正确: gateway 8080、userservice 20000、assetservice 20003、lasercompositor 7002。
|
||
|
||
K8s 迁移时,改用 `livenessProbe` / `readinessProbe` 显式配置,**顺便修复这个 bug**。
|
||
|
||
#### 4.2.6 Secrets 管理
|
||
|
||
```yaml
|
||
# topfans-group-a/gateway-secret.yaml
|
||
apiVersion: v1
|
||
kind: Secret
|
||
metadata:
|
||
name: gateway-secrets
|
||
namespace: topfans-group-a
|
||
type: Opaque
|
||
stringData:
|
||
DB_PASSWORD: <从 base64 或外部 secret store 注入>
|
||
REDIS_PASSWORD: ...
|
||
JWT_SECRET: ...
|
||
OSS_ACCESS_KEY_ID: ...
|
||
OSS_ACCESS_KEY_SECRET: ...
|
||
DIFY_API_KEY: ...
|
||
MINIMAX_API_KEY: ...
|
||
QWEN_API_KEY: ...
|
||
```
|
||
|
||
**生产建议**: 配合 [External Secrets Operator](https://external-secrets.io/) 或阿里云 KMS,不要把明文 secret 提交到 git。本期先用原生 Secret 加密,后续接 secret manager。
|
||
|
||
### 4.3 数据层多租户设计 (应用层改动,不在本次范围)
|
||
|
||
本次 K8s 迁移只解决编排层。多组数据隔离需要在应用层做配套改动,简要列出:
|
||
|
||
| 表 | 加 group_id 字段 | 中间件透传 group_id |
|
||
|---|---|---|
|
||
| users | ✅ | JWT 携带 group_id |
|
||
| galleries / assets / stars | ✅ | Dubbo attachment 透传 |
|
||
| 评论/点赞/收藏 | ✅ | 同上 |
|
||
|
||
建议在另一份专门的设计文档中详细设计,**本文档不展开**。
|
||
|
||
---
|
||
|
||
## 五、目录结构
|
||
|
||
```
|
||
k8s/ (新目录,根目录同级)
|
||
├── README.md 运维使用手册
|
||
├── helm/
|
||
│ ├── topfans-shared/ Chart 1: 共享服务
|
||
│ │ ├── Chart.yaml
|
||
│ │ ├── values.yaml 默认值
|
||
│ │ ├── values-prod.yaml 生产覆盖
|
||
│ │ ├── values-dev.yaml 开发覆盖
|
||
│ │ └── templates/
|
||
│ │ ├── _helpers.tpl
|
||
│ │ ├── external-db/
|
||
│ │ │ ├── postgres-external.yaml ExternalName → RDS
|
||
│ │ │ └── redis-external.yaml ExternalName → ElastiCache
|
||
│ │ ├── admin/ (未来,.gitkeep 占位)
|
||
│ │ ├── review/ (未来)
|
||
│ │ ├── ai-image-gen/ (未来)
|
||
│ │ ├── ai-chat/ (未来)
|
||
│ │ └── secrets/
|
||
│ │ ├── db-credentials.yaml
|
||
│ │ └── oss-credentials.yaml
|
||
│ │
|
||
│ └── topfans-group/ Chart 2: 每组一份
|
||
│ ├── Chart.yaml
|
||
│ ├── values.yaml 默认值 + 文档
|
||
│ ├── values-group-a.yaml 实际组 A 配置示例
|
||
│ ├── values-group-b.yaml 实际组 B 配置示例
|
||
│ └── templates/
|
||
│ ├── _helpers.tpl
|
||
│ ├── namespace.yaml 创建组 namespace
|
||
│ ├── resource-quota.yaml
|
||
│ ├── limit-range.yaml
|
||
│ ├── gateway/ deployment + service + configmap + secret
|
||
│ ├── userservice/
|
||
│ ├── assetservice/
|
||
│ ├── galleryservice/
|
||
│ ├── socialservice/
|
||
│ ├── activityservice/
|
||
│ ├── starbookservice/
|
||
│ ├── taskservice/
|
||
│ ├── aichatservice/
|
||
│ └── lasercompositor/
|
||
│
|
||
└── ingress/
|
||
└── ingress.yaml 集群级 Ingress(可放 helm 也可 kubectl apply)
|
||
```
|
||
|
||
**原则**:
|
||
|
||
- `docker/` 目录保留,继续支撑本地开发 (`docker-compose.local.yml`)
|
||
- `k8s/` 是新增的部署维度,与 `docker/` 并存
|
||
- 未来四个新服务**不在本次实现**,只留 `.gitkeep` 占位 + README 说明
|
||
- 镜像构建继续走 `docker/Dockerfile.services` (多阶段),不重复造轮子
|
||
|
||
---
|
||
|
||
## 六、迁移计划 (建议分 4 步走)
|
||
|
||
### Step 1: K8s 基础设施 (本期)
|
||
|
||
- [ ] 在阿里云 ACK 创建测试集群 (或自建 k3s)
|
||
- [ ] 部署 nginx-ingress / cert-manager (HTTPS)
|
||
- [ ] 创建 `topfans-shared` namespace + ExternalName 占位
|
||
- [ ] 编写 `topfans-shared` Helm chart (不含未来服务)
|
||
- [ ] 编写 `topfans-group` Helm chart (含全部 9 个数据服务 + gateway)
|
||
- [ ] 准备 `values-group-a.yaml` 模板 (用现有 .env.prod 内容填充)
|
||
- [ ] 修复 Dockerfile 健康检查端口错配 bug
|
||
- [ ] 编写 README: 加新组的步骤 (`helm install` 一行)
|
||
|
||
### Step 2: 灰度切换 (本期可一并做)
|
||
|
||
- [ ] 把现有 .env.prod 的所有密钥搬到 K8s Secret
|
||
- [ ] 准备 DNS 切换预案 (`group-a.api.example.com` 先解析到 K8s,旧 VM 保留回滚)
|
||
- [ ] 选 1 个非关键组(如内部测试组)切到 K8s,跑 1~2 周
|
||
- [ ] 验证: 业务功能 / 性能 / 故障恢复
|
||
|
||
### Step 3: 全量切换
|
||
|
||
- [ ] 切所有组到 K8s
|
||
- [ ] 停 VM 上的 `docker-compose`
|
||
- [ ] 释放 VM 资源
|
||
- [ ] 第一次: 取消注释 `init-db.sql` 中所有序列同步(从手工迁移数据开始时,见 CLAUDE.md 规范)
|
||
|
||
### Step 4: 后续优化 (本期不做)
|
||
|
||
- [ ] 接 External Secrets Operator
|
||
- [ ] 接 Prometheus + Grafana
|
||
- [ ] 接 Loki 日志收集
|
||
- [ ] 接 ArgoCD / Flux 做 GitOps
|
||
- [ ] 加 HPA (HPA + 自定义指标:KEDA)
|
||
- [ ] 实施应用层多租户改造(group_id 透传)
|
||
|
||
---
|
||
|
||
## 七、风险与待定项
|
||
|
||
| 风险/待定 | 影响 | 缓解 |
|
||
|---|---|---|
|
||
| 现有 docker-compose 在生产跑,切换期间需双轨 | 资源消耗 | 测试组先切,观察 1~2 周再切正式组 |
|
||
| Postgres 走外部 RDS,数据迁移 | 数据一致性 | 用阿里云 DTS 做实时同步,切换时切流量 |
|
||
| Gateway 在 K8s 内,Dubbo 跨 ns 调用 | 服务发现 | 短 DNS 名 + 同 ns 部署,无问题 |
|
||
| 镜像构建走 CI 还是保留 deploy.sh | 流程变更 | 推荐 CI,本期可先保留 deploy.sh 过渡 |
|
||
| 新服务具体技术栈未定 | 模板不完整 | `.gitkeep` 占位,后续按需填 |
|
||
| 集群选型:ACK / TKE / 自建 k3s | 成本/可控性 | 建议先 ACK 测试,稳定后定型 |
|
||
| HPA 是否启用 (按 CPU / 自定义指标) | 资源效率 | 本期不开,观察流量稳定后加 |
|
||
| 多集群 / 多 region 容灾 | 灾备 | 暂不考虑,后续规划 |
|
||
|
||
---
|
||
|
||
## 八、用户已确认的关键决策
|
||
|
||
1. ✅ **按"组"隔离资源**,每组 1 个或多个明星,可灵活组合
|
||
2. ✅ **配置格式: Helm Chart**
|
||
3. ✅ **数据库: 外部托管 (RDS/ElastiCache)**
|
||
4. ✅ **Gateway 放在每组 namespace 内** (而非 shared)
|
||
5. ✅ **新服务 (admin / review / ai-image-gen / ai-chat) 放在 `topfans-shared`**
|
||
6. ✅ **保留 `docker/` 目录,继续支撑本地开发**
|
||
|
||
---
|
||
|
||
## 九、不在本次范围
|
||
|
||
- 新服务 (admin / review / ai-image-gen / ai-chat) 的实现
|
||
- 应用层多租户改造 (group_id 字段添加与透传)
|
||
- CI/CD 流水线改造 (CI 自动构建镜像)
|
||
- 监控/日志/告警接入
|
||
- 灾备多集群
|
||
- K8s 内的 StatefulSet (Postgres/Redis 用云服务,不自己跑)
|
||
|
||
---
|
||
|
||
## 十、Spec Review Refinements
|
||
|
||
本文档经 spec-document-reviewer 审查通过 (Status: Approved)。以下为审查中识别的可执行细化项,留待 writing-plans 阶段处理:
|
||
|
||
### 10.1 前置条件:`group_id` 字段已就绪
|
||
|
||
> 来自 4.2.2 节的隐含假设
|
||
|
||
Helm chart 能成功 install 并不等于 K8s 上的多组数据隔离已生效。多组隔离依赖现有 schema 已含 `group_id` 列(或配套 migration 已先于 K8s 部署完成)。
|
||
|
||
**实施计划中需明确**: Step 1 启动前的 blocker — 验证所有数据表已有 `group_id`,或先发一份 DB migration 再做 K8s 部署。
|
||
|
||
### 10.2 镜像仓库路径决策
|
||
|
||
> 来自 4.2.4 的歧义
|
||
|
||
`values.yaml` 中 `image.repository` 必须明确指向一个 registry:
|
||
|
||
- **选项 A (推荐)**: 阿里云 ACR,`image.repository: registry.cn-shanghai.aliyuncs.com/topfans/<service>`,CI 构建推送
|
||
- **选项 B**: 自建 Harbor,`image.repository: harbor.example.com/topfans/<service>`
|
||
|
||
**实施计划中需选其一**,并写明 deploy.sh 的去留:
|
||
|
||
- 选 A: 改 deploy.sh 为 CI 触发器,服务器只拉不构建
|
||
- 选 B: 保留 deploy.sh 构建逻辑,但目标改为推 Harbor 而非本地
|
||
|
||
### 10.3 Secret 落盘策略
|
||
|
||
> 来自 4.2.6 的潜在泄漏
|
||
|
||
`values-prod.yaml` 含明文密钥会污染 git。**实施计划中需**:
|
||
- 把 `values-prod.yaml` 加入 `.gitignore`,只提交 `values-prod.example.yaml` (空值)
|
||
- 真值由 CI/CD 注入,或用 `kubeseal` / `sops` 加密后提交
|
||
- 本期最低要求: 真值不进 git
|
||
|
||
### 10.4 数据库迁移时序
|
||
|
||
> 来自 CLAUDE.md PostgreSQL 序列同步规则 + 第 6 节 Step 3
|
||
|
||
若选择"从 VM 迁数据到 RDS"路径,需明确:
|
||
|
||
- `init-db.sql` 的 `setval(...)` 同步操作放在流量切换**之前**还是**之后**
|
||
- 推荐: 切换**前**以 Job 形式跑完,验证 `pg_sequences` 全部 `is_healthy=true` 后再切流量
|
||
- 详见 CLAUDE.md 的强制规范
|
||
|
||
### 10.5 HEALTHCHECK 修复范围
|
||
|
||
> 来自 4.2.5 的歧义
|
||
|
||
K8s 用 Helm chart 里的 `livenessProbe` / `readinessProbe`,**不再依赖 Dockerfile HEALTHCHECK**。两种选择:
|
||
|
||
- **A. 只改 K8s 探针,不动 Dockerfile**: 保持向后兼容,本地 docker-compose 仍可用
|
||
- **B. 同时修 Dockerfile**: 顺手修 bug,让 compose 也能看到正确健康状态
|
||
|
||
**推荐 A** — 本次任务专注 K8s,Dockerfile 修复单独提一个 issue。
|
||
|
||
### 10.6 跨 namespace Dubbo 调用模式 (为新服务预留)
|
||
|
||
> 来自审查中识别 — 当前 spec 未明确
|
||
|
||
当未来 `admin` / `review` 部署在 `topfans-shared` 时,它们需要调用各组的数据服务(如 review 审核 group-a 的 gallery):
|
||
|
||
```yaml
|
||
# 未来 review 服务的环境变量 (在 topfans-shared namespace)
|
||
# 需要按 group 动态获取或路由
|
||
DUBBO_GALLERY_SERVICE_URL: tri://galleryservice.topfans-group-a.svc.cluster.local:20001
|
||
DUBBO_GALLERY_SERVICE_URL_GROUP_B: tri://galleryservice.topfans-group-b.svc.cluster.local:20001
|
||
```
|
||
|
||
**当前不实现**,但 `topfans-shared` 的 chart 结构需考虑: 共享服务将来需要某种方式(配置中心/服务发现)拿到各组的服务地址。本期不展开,记入"未来工作"。
|
||
|
||
### 10.7 评审通过的完整决策
|
||
|
||
| # | 决策点 | 选择 |
|
||
|---|---|---|
|
||
| 1 | K8s 隔离粒度 | 按"组" (1+ 明星/组) |
|
||
| 2 | 配置格式 | Helm Chart |
|
||
| 3 | 数据库部署 | 外部托管 (RDS/ElastiCache) |
|
||
| 4 | Gateway 位置 | 每组 namespace 内 |
|
||
| 5 | 新服务位置 | `topfans-shared` |
|
||
| 6 | 镜像仓库 | 待定 (10.2 中 A/B 选一) |
|
||
| 7 | Docker HEALTHCHECK 修复 | 本期不动,改 K8s 探针 |
|
||
| 8 | `docker/` 目录 | 保留,继续支撑本地开发 |
|