677 lines
30 KiB
Markdown
677 lines
30 KiB
Markdown
# EasyAI Kubernetes 部署指南
|
||
|
||
本仓库用于将 EasyAI 部署到客户自己的 Kubernetes 环境中。客户拿到仓库后,只需要按本文准备外部依赖、修改生产配置并执行 `kubectl apply`,即可完成部署。
|
||
|
||
生产部署只使用以下目录:
|
||
|
||
```text
|
||
k8s/overlays/production
|
||
```
|
||
|
||
本地部署验证可参考:
|
||
|
||
```text
|
||
k8s/overlays/local/README.md
|
||
```
|
||
|
||
镜像版本默认使用 `latest`。EasyAI 发布新版本后,客户拉取本仓库最新内容并按“更新到最新版本”执行即可升级。
|
||
|
||
## 部署内容
|
||
|
||
| 服务 | Kubernetes 资源 | 说明 |
|
||
| --- | --- | --- |
|
||
| 前端 | `easyai-web` | Web 页面入口 |
|
||
| 主服务 | `easyai-server` | API、核心业务服务 |
|
||
| WebSocket 网关 | `ws-gateway` | `/socket.io` 长连接入口 |
|
||
| 视频编辑 | `video-edit` | 视频编辑能力 |
|
||
| 沙箱 | `sandbox` | 代码执行/Notebook 沙箱 |
|
||
| Agent 服务治理 | `easyai-asg` | Agent 治理服务 |
|
||
| Agent 记忆服务 | `agent-memory` | Agent 记忆与检索服务 |
|
||
|
||
生产环境优先建议使用云厂商托管的 Redis、MongoDB、RabbitMQ 和 PostgreSQL。客户不能使用云服务时,可在客户 Kubernetes 或独立基础设施中自建;本仓库已提供 RabbitMQ 三节点集群模板,其他自建依赖需由客户按其基础设施标准提供高可用、备份和监控能力。
|
||
|
||
## 部署前准备
|
||
|
||
### Kubernetes 集群
|
||
|
||
请先确认集群满足以下条件:
|
||
|
||
| 项目 | 要求 |
|
||
| --- | --- |
|
||
| Kubernetes | 可正常使用 `kubectl` 连接 |
|
||
| Worker 节点 | 建议不少于 3 个节点,生产环境建议跨可用区 |
|
||
| Metrics Server | 已启用,用于 HPA 自动扩缩容 |
|
||
| Ingress Controller | 已安装,当前配置默认使用 NGINX Ingress |
|
||
| 共享存储 | 有支持 `ReadWriteMany` 的 StorageClass |
|
||
| 镜像拉取 | 节点可以访问 `registry.cn-shanghai.aliyuncs.com` |
|
||
|
||
检查命令:
|
||
|
||
```bash
|
||
kubectl config current-context
|
||
kubectl get nodes -o wide
|
||
kubectl top nodes
|
||
kubectl get ingressclass
|
||
kubectl get storageclass
|
||
```
|
||
|
||
如果 `kubectl top nodes` 不可用,请先启用 Metrics Server。
|
||
|
||
### 基础依赖
|
||
|
||
部署前需要准备以下基础依赖,并保证 EasyAI Pod 可以访问。依赖既可以使用云厂商托管服务,也可以由客户自行部署。
|
||
|
||
以下版本为新建生产环境的推荐基线;已有依赖满足各小节兼容条件时可以复用。实际部署时请固定主版本和补丁版本;大版本升级前必须在测试环境完成连接、功能、性能和备份恢复验证。
|
||
|
||
| 依赖 | 推荐版本 | 用途 | 需要准备的信息 |
|
||
| --- | --- | --- | --- |
|
||
| MongoDB | `7.x` | 主服务业务数据 | 内网地址、端口、用户名、密码、连接参数 |
|
||
| Redis | `7.x`,需支持多个逻辑 DB;默认使用 DB `0`、`6`、`8`、`11`、`12` | 队列、缓存、WebSocket 集群状态 | 内网地址、端口、用户名、密码、可分配的 DB 编号 |
|
||
| RabbitMQ | 需支持 AMQP `0-9-1`;新建环境建议使用官方当前仍受支持的版本,自建模板默认使用 `4.3.2` | 消息队列 | AMQP 地址、端口、用户名、密码、vhost |
|
||
| PostgreSQL + pgvector | PostgreSQL `18` + pgvector `0.8.2` | Agent 治理和记忆服务 | 地址、端口、用户名、密码、数据库、扩展 |
|
||
| RWX 共享存储 | 与 Kubernetes 集群版本兼容的 CSI/存储插件 | 上传、备份、恢复文件共享 | 支持 `ReadWriteMany` 的 StorageClass |
|
||
| OSS/S3 对象存储 | 兼容 AWS S3 Signature V4 或云厂商 OSS/S3 当前 API,可选 | 文件存储,可选 | Endpoint、Bucket、Access Key |
|
||
|
||
#### 生产初始规格与容量基线
|
||
|
||
客户尚未提供业务容量数据时,可先按下表准备生产环境。表中的 CPU、内存和磁盘均为**单个数据节点**的规格,标注“当前模板”的项目与仓库 YAML 一致;标注“官方容量参考”的项目引用官方规格指南;标注“项目初始值”的项目是用于首次部署和压测的起点,不是官方最低配置或吞吐量承诺。
|
||
|
||
数据库访问量应使用峰值数据库读写操作数、事务数和活跃数据库会话衡量,不能直接用日活、PV 或在线用户数代替。同一个 API 请求可能不访问数据库,也可能触发多次查询、写入或后台任务。
|
||
|
||
EasyAI 应用 Pod 当前资源规格如下,CPU 和内存均为单个 Pod 的配置:
|
||
|
||
| 服务 | 最小/固定副本 | HPA 上限 | CPU 请求/上限 | 内存请求/上限 |
|
||
| --- | ---: | ---: | --- | --- |
|
||
| `easyai-web` | 2 | 10 | `200m / 1 CPU` | `512Mi / 1500Mi` |
|
||
| `easyai-server` | 2 | 20 | `500m / 2 CPU` | `1Gi / 2500Mi` |
|
||
| `ws-gateway` | 2 | 10 | `200m / 1 CPU` | `256Mi / 512Mi` |
|
||
| `video-edit` | 1 | 5 | `1 CPU / 2 CPU` | `2Gi / 4Gi` |
|
||
| `sandbox` | 固定 1 | 无 HPA | `500m / 1 CPU` | `512Mi / 1Gi` |
|
||
| `easyai-asg` | 2 | 8 | `200m / 1 CPU` | `256Mi / 512Mi` |
|
||
| `agent-memory` | 2 | 8 | `200m / 1 CPU` | `256Mi / 512Mi` |
|
||
|
||
| 依赖 | 建议生产拓扑 | 单节点初始规格 | 初始存储容量 | 备注 |
|
||
| --- | --- | --- | --- | --- |
|
||
| MongoDB | 云服务高可用版,或 3 个数据节点的副本集 | Atlas `M30` 参考值为 `2 vCPU / 8GB`;自建环境以压测为准 | 无存量数据时每节点可从 `50Gi` SSD 开始压测;已有数据按下方公式计算 | `M30` 的 `3000/s` 和 `20–50GB` 是 Atlas 近似集群负载,不是自建单节点性能承诺 |
|
||
| Redis | 云服务高可用版,或主节点 + 2 个副本并配套 Sentinel | `2 vCPU / 4Gi` | 每节点 `20Gi` SSD,建议 `maxmemory` 初始设为 `2Gi` | 规划参考;必须支持多个逻辑 DB 和 `SELECT`,当前不支持 Redis Cluster 模式 |
|
||
| RabbitMQ | 3 节点集群,持久化业务队列使用 quorum queue | 请求 `1 vCPU / 2Gi`,上限 `2 vCPU / 2Gi` | 每节点 `50Gi` RWO SSD,总计 `150Gi` | 当前自建模板实际值;高吞吐或大消息场景需压测后增加内存和磁盘 |
|
||
| PostgreSQL + pgvector | 云服务高可用版,或主库 + 备库并配置经过验证的自动故障切换、隔离机制和统一访问端点 | 项目初始参考 `2 vCPU / 8Gi` | 无存量数据时每节点可从 `50Gi` SSD 开始压测;已有数据按下方公式计算 | 按实际 SQL、并发客户端、向量规模和检索压测调整;本地 `1 CPU / 1Gi` 仅为功能验证上限 |
|
||
| RWX 共享存储 | 支持高可用和在线扩容的 RWX 存储 | 由存储服务决定 | 初始总容量 `100Gi` | 当前生产 PVC 实际值;不包含独立备份空间 |
|
||
| OSS/S3 对象存储 | 云厂商托管对象存储 | 由对象存储服务决定 | 按量使用,无需预分配固定容量 | 可选;建议配置生命周期和历史文件清理策略 |
|
||
|
||
##### MongoDB 规格计算依据
|
||
|
||
[MongoDB Atlas Cluster Size Guide](https://www.mongodb.com/docs/atlas/architecture/current/hierarchy/#atlas-cluster-size-guide) 明确说明规格表仅用于近似起点,最终规格需要根据资源需求、性能目标、负载特征和增长持续迭代。官方给出的初步估算公式为:
|
||
|
||
```text
|
||
预计数据存储 = 原始数据量 × 50%
|
||
预计 RAM = 原始数据量 × 10%
|
||
预计 CPU 核数 = 峰值数据库读写操作数/秒 ÷ 4000
|
||
预计存储 IOPS = 峰值数据库读写操作数/秒
|
||
```
|
||
|
||
Atlas 官方档位如下。CPU、内存和 IOPS 是 Atlas 数据节点的规格,典型数据量和峰值读写操作数是近似集群负载;自建 MongoDB 的云盘、CPU 型号和文件系统不同,不能把 Atlas 数值当作自建环境的固定性能承诺。
|
||
|
||
| Atlas 参考档 | CPU | 内存 | 默认 IOPS | 典型数据量 | 峰值读写操作数 | 官方用途 |
|
||
| --- | ---: | ---: | ---: | ---: | ---: | --- |
|
||
| `M10` | `2` | `2GB` | `1000` | `1–10GB` | `200/s` | 开发/测试 |
|
||
| `M30` | `2` | `8GB` | `3000` | `20–50GB` | `3000/s` | 生产 |
|
||
| `M50` | `16` | `32GB` | `3000` | `360–420GB` | `11000/s` | 生产 |
|
||
| `M80` | `32` | `128GB` | `3000` | `1200–1750GB` | `39000/s` | 生产 |
|
||
|
||
使用 MongoDB Atlas 时,客户未提供容量和压测数据可先选择 `M30` 作为生产准备参考,而不是原来的 `4 vCPU / 16Gi` 自建节点规格。自建环境可以使用 `2 vCPU / 8Gi` 作为首轮压测候选,但不能直接继承 Atlas 的吞吐量结论。如果实测负载低于 `M10` 参考范围,可在客户接受性能验证结果的前提下降配;高于 `M30` 范围时,应按数据量和峰值操作数选择更高档位并重新压测。
|
||
|
||
MongoDB 的实际峰值操作数应通过 [`mongostat`](https://www.mongodb.com/docs/database-tools/mongostat/) 或 [`serverStatus.opcounters`](https://www.mongodb.com/docs/manual/reference/command/serverstatus/#mongodb-serverstatus-serverstatus.opcounters) 的时间差值测量,现有物理数据和索引大小通过 [`dbStats`](https://www.mongodb.com/docs/manual/reference/command/dbstats/) 测量。项目数据盘计算公式为:
|
||
|
||
```text
|
||
MongoDB 单节点数据盘
|
||
>=(压缩后数据 + 索引 + oplog + 在线保留期增长量)÷ 0.7
|
||
```
|
||
|
||
除以 `0.7` 是为了符合本项目“使用率达到 `70%` 告警”的运维策略,不是 MongoDB 官方固定系数。3 个数据节点用于副本集高可用,每个节点都需要容纳完整数据副本;[MongoDB 官方推荐的最小副本集配置](https://www.mongodb.com/docs/manual/core/replica-set-members/)是 3 个数据承载节点。
|
||
|
||
##### PostgreSQL 与 pgvector 规格计算依据
|
||
|
||
PostgreSQL 官方没有提供“多少 QPS/TPS 对应多少 CPU 和内存”的通用硬件表。查询复杂度、索引命中率、并发事务、向量维度、HNSW/IVFFlat 选择、召回率目标和存储延迟都会显著改变结果。为了给首次生产部署提供可执行的压测起点,本项目采用单节点 `2 vCPU / 8Gi`:按照 [PostgreSQL 18 Resource Consumption](https://www.postgresql.org/docs/18/runtime-config-resource.html) 的建议,将 `shared_buffers` 从总内存的 `25%` 起步时约为 `2Gi`,其余内存用于操作系统文件缓存、并发 `work_mem`、连接进程、维护任务和 pgvector。该数值是项目初始参考,不是 PostgreSQL 官方最低配置或吞吐量承诺,最终规格仍必须通过实际负载确定。
|
||
|
||
自建高可用不能只写成“1 主 1 备”。还必须使用经过验证的高可用管理方案完成故障检测、自动切换、主库隔离或 fencing、客户端访问端点切换以及故障域隔离;所选方案需要仲裁或 witness 时还必须部署对应组件,并完成故障演练。
|
||
|
||
内存规划应遵循 [PostgreSQL 18 Resource Consumption](https://www.postgresql.org/docs/18/runtime-config-resource.html):
|
||
|
||
- 专用数据库服务器的 `shared_buffers` 可从系统内存的 `25%` 起步;官方说明超过 `40%` 通常不会比更小的值更好,因为 PostgreSQL 同时依赖操作系统文件缓存。
|
||
- `work_mem` 是每个排序或哈希操作的基础上限,一个复杂查询可能同时使用多份 `work_mem`,多个会话还会并发叠加;哈希操作的内存上限还要乘以 `hash_mem_multiplier`,默认值为 `2.0`。
|
||
- `maintenance_work_mem` 可用于 `VACUUM` 和建索引,但 autovacuum 最多可能按 worker 数量重复分配相关内存。
|
||
- `max_connections` 默认通常为 `100`,提高它会增加共享内存等资源分配;连接上限不能当作数据库吞吐量目标。
|
||
|
||
规划并发内存时至少要检查以下上界,而不能只看 `shared_buffers`:
|
||
|
||
```text
|
||
排序瞬时内存
|
||
≈ 活跃排序操作实例数 × work_mem
|
||
|
||
哈希瞬时内存
|
||
≈ 活跃哈希操作实例数 × work_mem × hash_mem_multiplier
|
||
|
||
HNSW 迭代扫描内存
|
||
≈ 并发 HNSW 扫描执行实例数 × work_mem × hnsw.scan_mem_multiplier
|
||
|
||
数据库节点内存
|
||
> shared_buffers
|
||
+ 排序瞬时内存
|
||
+ 哈希瞬时内存
|
||
+ HNSW 迭代扫描内存
|
||
+ autovacuum/维护任务内存
|
||
+ 会话本地内存、连接进程、操作系统和文件缓存预留
|
||
```
|
||
|
||
[pgvector `0.8.2` 官方说明](https://github.com/pgvector/pgvector/blob/v0.8.2/README.md#index-build-time)指出,HNSW 的查询性能通常优于 IVFFlat,但建索引更慢且使用更多内存;当 HNSW 图可以放入 `maintenance_work_mem` 时建索引明显更快,同时明确警告不能把该参数设置到耗尽服务器内存。`hnsw.ef_search`、`hnsw.scan_mem_multiplier` 和 IVFFlat `probes` 也会在召回率、速度和内存之间产生取舍。上式中的执行实例数必须把 leader 和参与查询的并行 worker 分别计算。存在较大向量索引或在线建索引需求时,应根据实际 HNSW 图大小临时提高维护窗口资源并重新压测,不能预先写死 CPU 和内存规格。
|
||
|
||
PostgreSQL 单节点数据盘按实际数据库大小计算:
|
||
|
||
```text
|
||
PostgreSQL 单节点数据盘
|
||
>=(pg_database_size('agent_governance')
|
||
+ pg_database_size('easyai_memory')
|
||
+ 其他数据库和集群级空间
|
||
+ WAL 预留
|
||
+ 临时文件预留
|
||
+ 最大计划索引重建、REINDEX 或表重写工作空间
|
||
+ 在线保留期增长量)÷ 0.7
|
||
```
|
||
|
||
[`pg_database_size`](https://www.postgresql.org/docs/18/functions-admin.html#FUNCTIONS-ADMIN-DBSIZE) 包含数据库中的表、索引和 TOAST 数据;使用额外 tablespace 时还要分别确认其存储卷容量。WAL 位于集群级目录,需要单独预留。[PostgreSQL WAL 官方说明](https://www.postgresql.org/docs/18/wal-configuration.html)指出 `max_wal_size` 是软限制,在高负载、归档失败、较大的 `wal_keep_size` 或复制槽滞后时可能被超过,因此不能只按 `max_wal_size` 配置磁盘。主库和物理备库都需要容纳完整数据副本,备份和归档空间另行计算。
|
||
|
||
PostgreSQL 最终规格必须使用 [PostgreSQL `pgbench`](https://www.postgresql.org/docs/18/pgbench.html) 的自定义事务脚本模拟 EasyAI 实际 SQL:
|
||
|
||
1. 使用 `-f` 编写覆盖 Agent 治理写入、记忆写入、普通查询和向量检索的混合事务脚本;
|
||
2. `-c` 表示并发客户端连接数,不等于生产环境的活跃会话数或请求到达率;需要结合实际连接池、思考时间,并在模拟固定到达率时使用 `-R`,同时通过 `pg_stat_activity` 验证数据库内实际活跃会话;
|
||
3. 使用 `-T` 运行至少数分钟并重复多轮;
|
||
4. 记录 TPS、事务延迟、失败事务和超过延迟限制的事务,不能使用默认 TPC-B-like 脚本结果直接代表 EasyAI;
|
||
5. 同时检查 `pg_stat_database` 的连接数、事务提交/回滚、磁盘块读取、临时文件、临时字节数和死锁;
|
||
6. 启用 [`pg_stat_statements`](https://www.postgresql.org/docs/18/pgstatstatements.html) 后,检查实际 SQL 的调用次数、平均/最大执行时间、缓存命中、临时块、WAL 量和 I/O 时间;只有启用 `track_io_timing` 后 I/O 时间字段才有有效值,启用前应评估所在平台的计时开销;
|
||
7. 选择满足客户峰值负载和延迟目标的最小规格,并在向量数量、维度、索引类型或召回率目标改变后重新压测。
|
||
|
||
##### 容量信息与扩容规则
|
||
|
||
上线前请客户补充以下信息,以便把初始参考规格调整为最终规格:
|
||
|
||
- API 峰值 QPS、MongoDB 峰值读写操作数/秒和 PostgreSQL 峰值 TPS;
|
||
- PostgreSQL 峰值活跃数据库会话数、目标事务延迟和主要 SQL 类型;
|
||
- 每日任务量、峰值队列积压量及单条消息大小;
|
||
- MongoDB 原始/压缩数据、索引和 oplog 大小;
|
||
- PostgreSQL 两个数据库的 `pg_database_size`、WAL 峰值和临时文件峰值;
|
||
- 向量条数、向量维度、索引类型、目标召回率和是否需要在线建索引;
|
||
- 每日数据库增量和在线保留天数;
|
||
- 每日上传文件量、平均文件大小和文件保留周期;
|
||
- 备份周期、保留份数以及 RPO/RTO 要求。
|
||
|
||
所有数据盘在使用率达到 `70%` 时告警,达到 `80%` 前完成扩容。备份、快照、WAL 归档和跨区域副本空间单独计算。当前本地验证模板中 MongoDB 上限为 `1 CPU / 2500Mi`,PostgreSQL 上限为 `1 CPU / 1Gi`,且均使用单节点 `emptyDir`;这些数值只证明低负载功能验证可以运行,不能作为生产容量依据。
|
||
|
||
资源规划参考:
|
||
|
||
- [MongoDB Atlas Cluster Size Guide](https://www.mongodb.com/docs/atlas/architecture/current/hierarchy/#atlas-cluster-size-guide)
|
||
- [MongoDB Production Notes](https://www.mongodb.com/docs/manual/administration/production-notes/)
|
||
- [MongoDB Replica Set Members](https://www.mongodb.com/docs/manual/core/replica-set-members/)
|
||
- [MongoDB WiredTiger Memory Use](https://www.mongodb.com/docs/manual/core/wiredtiger/#memory-use)
|
||
- [Redis Administration](https://redis.io/docs/latest/operate/oss_and_stack/management/admin/)
|
||
- [PostgreSQL 18 Resource Consumption](https://www.postgresql.org/docs/18/runtime-config-resource.html)
|
||
- [PostgreSQL 18 Connections](https://www.postgresql.org/docs/18/runtime-config-connection.html)
|
||
- [PostgreSQL 18 pgbench](https://www.postgresql.org/docs/18/pgbench.html)
|
||
- [PostgreSQL 18 Monitoring Statistics](https://www.postgresql.org/docs/18/monitoring-stats.html)
|
||
- [PostgreSQL 18 Disk Usage](https://www.postgresql.org/docs/18/diskusage.html)
|
||
- [PostgreSQL 18 WAL Configuration](https://www.postgresql.org/docs/18/wal-configuration.html)
|
||
- [pgvector 0.8.2](https://github.com/pgvector/pgvector/blob/v0.8.2/README.md)
|
||
- [RabbitMQ Quorum Queues](https://www.rabbitmq.com/docs/quorum-queues)
|
||
|
||
#### Redis 逻辑 DB 配置
|
||
|
||
Redis 地址、端口和逻辑 DB 编号统一配置在:
|
||
|
||
```text
|
||
k8s/overlays/production/app-config.yaml
|
||
```
|
||
|
||
密码等敏感信息配置在:
|
||
|
||
```text
|
||
k8s/overlays/production/app-secret.yaml
|
||
```
|
||
|
||
当前默认映射如下:
|
||
|
||
| DB | 用途 | 配置项 |
|
||
| --- | --- | --- |
|
||
| `0` | WebSocket 网关集群状态 | `GATEWAY_CLUSTER_REDIS_DB` |
|
||
| `6` | 任务队列、画布运行状态和模型限流 | `CONFIG_COMFYUI_QUENE_REDIS_DB` |
|
||
| `8` | Agent 服务治理及其队列 | `ASG_REDIS_DB` |
|
||
| `11` | 业务缓存和 WebSocket 鉴权缓存 | `CONFIG_COMFYUI_CACHE_REDIS_DB` |
|
||
| `12` | 跨实例内部事件 | `CONFIG_EVENT_REDIS_DB` |
|
||
| `12` | 任务中止和超时控制 | `CONFIG_ABORT_REDIS_DB` |
|
||
|
||
系统实际使用 `0`、`6`、`8`、`11`、`12` 共 5 个不同的逻辑 DB。每个配置项填写的是一个确定的 DB 编号,不是起止范围。客户分配了其他连续或非连续 DB 时,可以逐项修改上述编号;若保持默认值,Redis 必须允许选择到 DB `12`,常见的 `databases 16` 配置可以满足要求。
|
||
|
||
该多 DB 方案要求 Redis 服务支持 `SELECT`。Redis Cluster 只支持 DB `0`,不能直接用于当前配置,详见 Redis 官方 [`SELECT` 文档](https://redis.io/docs/latest/commands/select/)。
|
||
|
||
#### MongoDB 数据库、集合和权限
|
||
|
||
EasyAI 默认使用以下业务数据库:
|
||
|
||
```text
|
||
aidraw
|
||
```
|
||
|
||
部署时应显式配置数据库名,不要依赖应用默认值:
|
||
|
||
```yaml
|
||
CONFIG_DB_MONGO_URI: mongodb://你的Mongo内网地址:27017/?authSource=admin
|
||
CONFIG_DB_MONGO_DBNAME: aidraw
|
||
CONFIG_DB_MONGO_USERNAME: 你的Mongo用户名
|
||
CONFIG_DB_MONGO_PASSWORD: 你的Mongo密码
|
||
```
|
||
|
||
如果 MongoDB 使用副本集,URI 需要包含所有可用节点和副本集名称,例如:
|
||
|
||
```text
|
||
mongodb://mongo-0:27017,mongo-1:27017,mongo-2:27017/?replicaSet=rs0&authSource=admin
|
||
```
|
||
|
||
`authSource` 必须填写用户实际创建所在的认证库;如果用户创建在 `aidraw`,应改为 `authSource=aidraw`。
|
||
|
||
无需提前创建或逐项提供集合名称。应用会根据业务模型在 `aidraw` 中创建所需集合和索引,集合也可能随产品版本或启用模块变化。建议为应用用户授予 `aidraw` 数据库级 `readWrite` 权限,不要采用固定集合白名单。若客户审计制度必须使用集合级授权,应以实际交付镜像在预发布环境启动后生成的集合和索引清单为准。
|
||
|
||
当前生产验证基线是 MongoDB `7.x`。应用驱动可以连接 MongoDB `4.x`,但 MongoDB `4.0`、`4.2` 和 `4.4` 均已停止官方维护。存量环境确实无法升级时,建议至少使用最终补丁版 `4.4.29`,并在上线前完成完整回归;不要把 MongoDB `4.x` 作为新的长期生产基线。
|
||
|
||
MongoDB 生命周期和驱动兼容性参考:
|
||
|
||
- <https://www.mongodb.com/legal/support-policy/lifecycles>
|
||
- <https://www.mongodb.com/docs/drivers/node/v6.12/compatibility/>
|
||
|
||
#### RabbitMQ 托管或自建方案
|
||
|
||
EasyAI 使用标准 AMQP `0-9-1` 能力,不依赖 RabbitMQ `4.3` 专属功能。自建模板中的 `4.3.2` 是默认部署版本,不是应用的硬性最低版本。
|
||
|
||
已有 RabbitMQ `3.13.7` 及以上环境时,可以直接复用,不需要再部署本仓库的 RabbitMQ 模板;上线前应验证队列声明、消息发布和消费、断线重连及故障切换。低于 `3.13.7` 的版本不作为当前交付兼容范围。RabbitMQ `3.13.x` 已停止社区支持,因此新建生产环境仍建议选择官方当前处于支持期的版本。
|
||
|
||
使用托管或客户已有的 RabbitMQ 时,向 EasyAI 提供内网 AMQP Service 地址、`5672`/`5671` 端口、用户名、密码和 vhost 即可。
|
||
|
||
不能使用云服务时,使用以下目录中的 RabbitMQ Cluster Operator 三节点模板:
|
||
|
||
```text
|
||
k8s/addons/rabbitmq-cluster
|
||
```
|
||
|
||
详细的 Operator 安装、StorageClass 配置、部署、凭据读取和验证步骤见:
|
||
|
||
```text
|
||
k8s/addons/rabbitmq-cluster/README.md
|
||
```
|
||
|
||
自建模板默认使用 RabbitMQ `4.3.2` 和 quorum queue。升级现有集群前必须在测试环境验证队列声明、发布消费、重连和故障切换,不能直接跨版本替换数据节点。
|
||
|
||
RabbitMQ 配置分为三部分:
|
||
|
||
- AMQP 协议、地址、端口和 vhost 等非敏感连接参数位于 `k8s/overlays/production/app-config.yaml`,该文件会生成 EasyAI 应用的 ConfigMap;
|
||
- 用户名和密码位于 `k8s/overlays/production/app-secret.yaml`;
|
||
- 使用自建模板时,RabbitMQ 服务端参数写在 `RabbitmqCluster` 资源的 `spec.rabbitmq.additionalConfig` 中,由 Cluster Operator 管理,不需要额外提供 RabbitMQ ConfigMap。
|
||
|
||
RabbitMQ 版本生命周期参考:
|
||
|
||
<https://www.rabbitmq.com/release-information>
|
||
|
||
本地验证环境中的 PostgreSQL/pgvector 镜像为:
|
||
|
||
```text
|
||
registry.cn-shanghai.aliyuncs.com/easyaigc/pgvector:0.8.2-pg18-trixie
|
||
```
|
||
|
||
外部依赖版本核对示例:
|
||
|
||
```bash
|
||
mongosh --eval 'db.version()'
|
||
redis-cli INFO server | grep '^redis_version:'
|
||
rabbitmqctl status | grep '{rabbit,'
|
||
psql "$ASG_DATABASE_URL" -c 'SHOW server_version;'
|
||
psql "$ASG_DATABASE_URL" -c "SELECT extversion FROM pg_extension WHERE extname = 'vector';"
|
||
kubectl get storageclass
|
||
```
|
||
|
||
PostgreSQL 需要创建两个数据库,并启用扩展:
|
||
|
||
```sql
|
||
CREATE DATABASE agent_governance;
|
||
\c agent_governance
|
||
CREATE EXTENSION IF NOT EXISTS vector;
|
||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||
|
||
CREATE DATABASE easyai_memory;
|
||
\c easyai_memory
|
||
CREATE EXTENSION IF NOT EXISTS vector;
|
||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||
```
|
||
|
||
最终需要准备两个连接串:
|
||
|
||
```text
|
||
postgresql://USER:PASSWORD@HOST:5432/agent_governance?schema=public
|
||
postgresql://USER:PASSWORD@HOST:5432/easyai_memory?schema=public
|
||
```
|
||
|
||
## 修改生产配置
|
||
|
||
所有生产配置都在:
|
||
|
||
```text
|
||
k8s/overlays/production
|
||
```
|
||
|
||
### 1. 修改非敏感配置
|
||
|
||
编辑:
|
||
|
||
```text
|
||
k8s/overlays/production/app-config.yaml
|
||
```
|
||
|
||
至少替换以下内容:
|
||
|
||
```yaml
|
||
NUXT_PUBLIC_BASE_SOCKETURL: wss://你的域名/socket.io
|
||
CONFIG_SECURITY_ORIGIN: https://你的域名
|
||
CONFIG_COMFYUI_QUENE_REDIS_HOST: 你的Redis内网地址
|
||
GATEWAY_CLUSTER_REDIS_HOST: 你的Redis内网地址
|
||
ASG_REDIS_HOST: 你的Redis内网地址
|
||
CONFIG_MQ_HOST: 你的RabbitMQ内网地址
|
||
```
|
||
|
||
如果使用统一域名访问,以下配置通常保持默认:
|
||
|
||
```yaml
|
||
NUXT_PUBLIC_BASE_APIURL: /api
|
||
NUXT_PUBLIC_SG_APIURL: /asg-api
|
||
```
|
||
|
||
### 2. 修改敏感配置
|
||
|
||
编辑:
|
||
|
||
```text
|
||
k8s/overlays/production/app-secret.yaml
|
||
```
|
||
|
||
至少替换以下内容:
|
||
|
||
```yaml
|
||
CONFIG_DB_MONGO_URI: mongodb://你的Mongo内网地址:27017/?authSource=admin
|
||
CONFIG_DB_MONGO_DBNAME: aidraw
|
||
CONFIG_DB_MONGO_USERNAME: 你的Mongo用户名
|
||
CONFIG_DB_MONGO_PASSWORD: 你的Mongo密码
|
||
|
||
CONFIG_COMFYUI_QUENE_REDIS_PASSWORD: 你的Redis密码
|
||
GATEWAY_CLUSTER_REDIS_PASSWORD: 你的Redis密码
|
||
ASG_REDIS_PASSWORD: 你的Redis密码
|
||
|
||
CONFIG_MQ_USER: 你的RabbitMQ用户名
|
||
CONFIG_MQ_PASSWORD: 你的RabbitMQ密码
|
||
|
||
CONFIG_JWT_SECRET: 一段足够长的随机字符串
|
||
CONFIG_TOKEN_SIGN_SK: 一段足够长的随机字符串
|
||
CONFIG_INITIAL_ADMIN_PASSWORD: 至少12位的EasyAI初始管理员密码
|
||
|
||
ASG_DATABASE_URL: postgresql://USER:PASSWORD@HOST:5432/agent_governance?schema=public
|
||
MEMORY_DATABASE_URL: postgresql://USER:PASSWORD@HOST:5432/easyai_memory?schema=public
|
||
|
||
ASG_POSTGRES_USER: 你的PostgreSQL用户名
|
||
ASG_POSTGRES_PASSWORD: 你的PostgreSQL密码
|
||
ASG_ADMIN_PASSWORD: 与CONFIG_INITIAL_ADMIN_PASSWORD相同
|
||
|
||
SANDBOX_JUPYTER_TOKEN: 一段足够长的随机字符串
|
||
```
|
||
|
||
生成随机密钥示例:
|
||
|
||
```bash
|
||
openssl rand -base64 48
|
||
```
|
||
|
||
如果使用 OSS/S3,请同时替换:
|
||
|
||
```yaml
|
||
OSS_ENDPOINT: ""
|
||
OSS_ACCESS_KEY_ID: ""
|
||
OSS_ACCESS_KEY_SECRET: ""
|
||
OSS_BUCKET: ""
|
||
```
|
||
|
||
生产密钥不要提交到公共 Git 仓库。正式环境建议接入 External Secrets、Sealed Secrets 或云厂商 Secret Manager。
|
||
|
||
### 3. 修改域名和证书
|
||
|
||
编辑:
|
||
|
||
```text
|
||
k8s/overlays/production/ingress.yaml
|
||
```
|
||
|
||
将所有 `easyai.example.com` 替换为客户真实域名。
|
||
|
||
如果集群的 IngressClass 不是 `nginx`,同步修改:
|
||
|
||
```yaml
|
||
ingressClassName: nginx
|
||
```
|
||
|
||
创建 TLS Secret:
|
||
|
||
```bash
|
||
kubectl create namespace easyai --dry-run=client -o yaml | kubectl apply -f -
|
||
|
||
kubectl -n easyai create secret tls easyai-tls \
|
||
--cert=/path/to/tls.crt \
|
||
--key=/path/to/tls.key
|
||
```
|
||
|
||
如果使用 cert-manager,请按客户集群规范在 `ingress.yaml` 中添加证书签发 annotation。
|
||
|
||
### 4. 修改共享存储
|
||
|
||
编辑:
|
||
|
||
```text
|
||
k8s/overlays/production/shared-pvc.yaml
|
||
```
|
||
|
||
将占位符替换为真实的 RWX StorageClass:
|
||
|
||
```yaml
|
||
storageClassName: 你的RWX_StorageClass
|
||
```
|
||
|
||
默认 PVC 容量为 `100Gi`,可按客户实际文件量调整:
|
||
|
||
```yaml
|
||
storage: 100Gi
|
||
```
|
||
|
||
## 部署前检查
|
||
|
||
确认没有未替换的占位符:
|
||
|
||
```bash
|
||
grep -R -nE 'CHANGE_ME|easyai.example.com|你的' k8s/overlays/production
|
||
```
|
||
|
||
使用自建 RabbitMQ 时,还需要检查其模板:
|
||
|
||
```bash
|
||
grep -R -n 'CHANGE_ME' k8s/addons/rabbitmq-cluster
|
||
```
|
||
|
||
如果还有输出,请先完成配置替换。
|
||
|
||
渲染生产 YAML:
|
||
|
||
```bash
|
||
kubectl kustomize k8s/overlays/production > /tmp/easyai-production.yaml
|
||
```
|
||
|
||
检查资源类型:
|
||
|
||
```bash
|
||
grep '^kind:' /tmp/easyai-production.yaml
|
||
```
|
||
|
||
执行服务端 dry-run:
|
||
|
||
```bash
|
||
kubectl create namespace easyai --dry-run=client -o yaml | kubectl apply -f -
|
||
kubectl apply --dry-run=server -f /tmp/easyai-production.yaml
|
||
```
|
||
|
||
如果 dry-run 报 IngressClass、Ingress annotation 或权限相关错误,请先按客户集群规范调整 `ingress.yaml`。
|
||
|
||
## 部署
|
||
|
||
执行部署:
|
||
|
||
```bash
|
||
kubectl apply -k k8s/overlays/production
|
||
```
|
||
|
||
查看资源:
|
||
|
||
```bash
|
||
kubectl -n easyai get deploy,svc,pvc,ingress,hpa,pdb
|
||
kubectl -n easyai get pods -o wide
|
||
```
|
||
|
||
等待服务发布完成:
|
||
|
||
```bash
|
||
for d in easyai-web easyai-server ws-gateway video-edit sandbox easyai-asg agent-memory; do
|
||
kubectl -n easyai rollout status deploy/$d --timeout=15m
|
||
done
|
||
```
|
||
|
||
如果某个 Deployment 超时,查看 Pod 状态和日志:
|
||
|
||
```bash
|
||
kubectl -n easyai get pods -o wide
|
||
kubectl -n easyai describe pod <PodName>
|
||
kubectl -n easyai logs <PodName> --all-containers --tail=200
|
||
```
|
||
|
||
## DNS 和访问验证
|
||
|
||
查看 Ingress 地址:
|
||
|
||
```bash
|
||
kubectl -n easyai get ingress
|
||
```
|
||
|
||
将客户域名解析到 Ingress 暴露的公网 IP 或 CNAME。
|
||
|
||
DNS 生效前,可以先用 `curl --resolve` 验证:
|
||
|
||
```bash
|
||
curl -i --resolve 你的域名:443:Ingress公网IP https://你的域名/api/health
|
||
```
|
||
|
||
DNS 生效后验证:
|
||
|
||
```bash
|
||
curl -i https://你的域名/api/health
|
||
curl -i https://你的域名/asg-api/health
|
||
curl -i https://你的域名/ams-api/health
|
||
```
|
||
|
||
浏览器访问:
|
||
|
||
```text
|
||
https://你的域名
|
||
```
|
||
|
||
重点确认:
|
||
|
||
| 检查项 | 预期结果 |
|
||
| --- | --- |
|
||
| Web 页面 | 可以正常打开 |
|
||
| `/api/health` | 返回健康状态,不是 404/502 |
|
||
| `/asg-api/health` | 返回健康状态 |
|
||
| `/ams-api/health` | 返回健康状态 |
|
||
| `/socket.io` | WebSocket 可以正常连接 |
|
||
|
||
## 更新到最新版本
|
||
|
||
本仓库默认使用 `latest` 镜像标签,并且工作负载已配置 `imagePullPolicy: Always`。
|
||
|
||
当 EasyAI 发布新版本后,客户在本仓库目录执行以下命令。即使 `git pull` 没有拉到新的 YAML 变更,只要 EasyAI 已发布新的 `latest` 镜像,也需要执行后面的 `rollout restart`:
|
||
|
||
```bash
|
||
git pull
|
||
kubectl apply -k k8s/overlays/production
|
||
|
||
kubectl -n easyai rollout restart \
|
||
deploy/easyai-web \
|
||
deploy/easyai-server \
|
||
deploy/ws-gateway \
|
||
deploy/video-edit \
|
||
deploy/sandbox \
|
||
deploy/easyai-asg \
|
||
deploy/agent-memory
|
||
|
||
for d in easyai-web easyai-server ws-gateway video-edit sandbox easyai-asg agent-memory; do
|
||
kubectl -n easyai rollout status deploy/$d --timeout=15m
|
||
done
|
||
```
|
||
|
||
说明:`latest` 标签更新后,Kubernetes 不会仅因为远端镜像变化就自动重建 Pod,所以更新时必须执行 `rollout restart`。
|
||
|
||
## 回滚
|
||
|
||
如果是配置变更导致问题,可回到上一份配置后重新部署:
|
||
|
||
```bash
|
||
git checkout <上一个可用提交>
|
||
kubectl apply -k k8s/overlays/production
|
||
```
|
||
|
||
如果是镜像版本问题,请使用 EasyAI 提供的回滚版本或回滚仓库版本后重新执行部署。
|
||
|
||
查看发布历史:
|
||
|
||
```bash
|
||
kubectl -n easyai rollout history deploy/easyai-server
|
||
```
|
||
|
||
回滚单个服务:
|
||
|
||
```bash
|
||
kubectl -n easyai rollout undo deploy/easyai-server
|
||
kubectl -n easyai rollout status deploy/easyai-server --timeout=10m
|
||
```
|
||
|
||
## 常见问题
|
||
|
||
| 现象 | 优先检查 |
|
||
| --- | --- |
|
||
| `ImagePullBackOff` | 节点是否能访问镜像仓库,镜像仓库是否需要额外拉取凭证 |
|
||
| Pod 一直 `Pending` | 节点资源、PVC 是否 Bound、StorageClass 是否支持 RWX |
|
||
| HPA 显示 `unknown` | Metrics Server 是否可用,`kubectl top pods` 是否正常 |
|
||
| `/api/health` 返回 404/502 | IngressClass、rewrite annotation、后端服务是否 Ready |
|
||
| WebSocket 频繁断开 | `/socket.io` 是否路由到 `ws-gateway:3002`,Ingress 超时时间是否足够 |
|
||
| 文件上传后多副本不可见 | `easyai-shared-files` PVC 是否正确挂载到 `easyai-server` |
|
||
| 连接数据库或中间件失败 | VPC、安全组、白名单、端口、用户名密码、TLS 要求 |
|
||
| MongoDB 认证成功但业务库没有数据 | `CONFIG_DB_MONGO_DBNAME` 是否为 `aidraw`,`authSource` 是否指向用户实际所在的认证库 |
|
||
| RabbitMQ 集群 Pod 一直 Pending | RWO StorageClass、PVC、3 个 Worker 节点以及主机级 Pod 反亲和规则 |
|
||
| `video-edit` 无法创建 | 集群 PodSecurity/PSA 是否禁止 `SYS_ADMIN` capability |
|
||
|
||
查看事件和日志:
|
||
|
||
```bash
|
||
kubectl -n easyai get events --sort-by=.lastTimestamp | tail -80
|
||
kubectl -n easyai logs deploy/easyai-server --tail=200
|
||
kubectl -n easyai logs deploy/ws-gateway --tail=200
|
||
kubectl -n easyai logs deploy/easyai-asg --tail=200
|
||
kubectl -n easyai logs deploy/agent-memory --tail=200
|
||
```
|