Files
easyai-deploy/README.md
T

524 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 |
#### 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_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: 一段足够长的随机字符串
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: EasyAI管理员密码
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
```