Files
easyai-deploy/README.md
T

485 lines
14 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`,需支持至少 `16` 个逻辑 DB | 队列、缓存、WebSocket 集群状态 | 内网地址、端口、密码,需支持多个逻辑 DB |
| RabbitMQ | `4.3.x`,自建模板固定为 `4.3.2`,需支持 AMQP `0-9-1` | 消息队列 | 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 |
#### 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 托管或自建方案
使用托管 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 `3.13.x` 已停止社区支持,只能作为存量过渡版本;升级现有集群前必须在测试环境验证队列声明、发布消费、重连和故障切换,不能直接跨版本替换数据节点。
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
```