# 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 一致;标注“规划参考”的外部依赖需根据实际业务量和压测结果调整。本表用于资源准备和首次上线,不代表固定性能或容量承诺。 | 依赖 | 建议生产拓扑 | 单节点初始规格 | 初始存储容量 | 备注 | | --- | --- | --- | --- | --- | | MongoDB | 云服务高可用版,或 3 个数据节点的副本集 | `4 vCPU / 16Gi` | 每节点 `200Gi` SSD | 规划参考;数据盘不包含备份和快照空间 | | 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 | 云服务高可用版,或 1 主 1 备 | `4 vCPU / 16Gi` | 每节点 `200Gi` SSD | 规划参考;可在同一实例创建 `agent_governance` 和 `easyai_memory` 两个数据库 | | RWX 共享存储 | 支持高可用和在线扩容的 RWX 存储 | 由存储服务决定 | 初始总容量 `100Gi` | 当前生产 PVC 实际值;不包含独立备份空间 | | OSS/S3 对象存储 | 云厂商托管对象存储 | 由对象存储服务决定 | 按量使用,无需预分配固定容量 | 可选;建议配置生命周期和历史文件清理策略 | 最终容量应根据客户业务数据计算: ```text 初始可用容量 >=(现有数据量 + 日增量 × 在线保留天数)× 1.5 ``` 其中 `1.5` 用于预留索引、临时文件、数据增长和运维空间。数据盘使用率达到 `70%` 时告警,达到 `80%` 前完成扩容;备份、快照和跨区域副本应单独计算,不占用上表的数据盘容量。 上线前请客户补充以下信息,以便把初始参考规格调整为最终规格: - 峰值并发用户数和同时运行的任务数; - 每日任务量、峰值队列积压量及单条消息大小; - 现有数据库大小、每日数据增量和在线保留天数; - 每日上传文件量、平均文件大小和文件保留周期; - 备份周期、保留份数以及 RPO/RTO 要求。 本地验证环境中的依赖为单节点和临时 `emptyDir` 存储,只用于功能验证,不能作为生产规格。MongoDB、Redis 和 PostgreSQL 的资源规划可参考官方生产说明: - [MongoDB Production Notes](https://www.mongodb.com/docs/manual/administration/production-notes/) - [Redis Administration](https://redis.io/docs/latest/operate/oss_and_stack/management/admin/) - [PostgreSQL Resource Consumption](https://www.postgresql.org/docs/current/runtime-config-resource.html) - [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 生命周期和驱动兼容性参考: - - #### 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 版本生命周期参考: 本地验证环境中的 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 kubectl -n easyai logs --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 ```