VeyraOS 部署指南
仓库归属(2026-09-22 起):三仓拆分后,account 相关清单在
veyra-bss仓、landing/router 相关在veyra-router仓,本文涉及这些路径的命令请在对应仓根执行。
环境要求
- macOS (本机开发)
- Docker + Colima (k3s)
- kubectl
基础设施部署
# 创建命名空间
kubectl apply -f deploy/k8s/namespace.yaml
# 部署基础设施 (PostgreSQL(pgvector) + MinIO + Neo4j)
kubectl apply -n veyraos -f deploy/k8s/infra/
# 创建 Secret
kubectl apply -n veyraos -f deploy/k8s/infra/secret.yaml知识库(RAG)依赖
知识库能力依赖 PostgreSQL(pgvector 扩展)、Neo4j(知识图谱存储)与 MinIO(文档原文托管),均包含在 deploy/k8s/infra/ 中。启用知识库需为 manager 注入 UA_KNOWLEDGE_ENABLED=true 及 Neo4j 连接环境变量(见 deploy/ci/deployment.yaml 中 knowledge 配置段)。
智能体 AI 生成(人设 / 头像 / 对话引导)
智能体创建/编辑页支持 AI 生成人设(SOUL.md)、头像图片与对话引导(开场白 + 推荐问题),属开发态能力,默认关闭。
优先走产品设置
下表环境变量均为兜底配置——管理员在管理台 系统管理 → 产品设置 → AI 生成 中保存的值优先生效,无需改环境变量或重启(详见 产品设置使用指南)。环境变量适合首次部署时给定初始值。
相关配置(见 deploy/ci/deployment.yaml 与 .env.local.example):
| 环境变量 | 说明 |
|---|---|
UA_AI_PERSONA_ENABLED | 人设生成开关(默认 false)。默认走已部署的 LiteLLM 网关;配置 UA_AI_PERSONA_BASE_URL 后改为直连 OpenAI 兼容 chat API。对话引导生成与人设共用此开关与模型配置 |
UA_AI_PERSONA_MODEL | 人设生成使用的模型:配了 UA_AI_PERSONA_BASE_URL 时为供应商模型名(如 Qwen/Qwen3.5-9B),否则为 LiteLLM 模型名 |
UA_AI_PERSONA_BASE_URL | 人设生成直连 API 地址(OpenAI 兼容 /chat/completions,如 https://api.siliconflow.cn/v1);留空则走 LiteLLM 网关 |
UA_AI_PERSONA_API_KEY | 人设生成直连 API Key(仅经环境变量 / k8s Secret 注入,不入仓) |
UA_AI_PERSONA_ENABLE_THINKING | 人设生成请求是否开启思考模式(默认 false 关闭)。硅基流动的 DeepSeek/Qwen 系默认思考时正文首 token 前先完成长推理(首 token 可达 25-29s),且部分模型会把推理过程直接写进输出正文,表现为流式输出开头出现非人设内容的杂文、随后才出正文;关闭后首 token 显著下降(Qwen3.5-9B 实测 ~2-4s)。直连与 LiteLLM 两条路径均生效 |
UA_AI_AVATAR_ENABLED | 头像生成开关(默认 false) |
UA_AI_AVATAR_BASE_URL | 图像生成 API 地址(OpenAI 兼容 /images/generations) |
UA_AI_AVATAR_API_KEY | 图像生成 API Key(仅经环境变量 / k8s Secret 注入,不入仓) |
UA_AI_AVATAR_MODEL | 图像生成模型名 |
UA_AI_AVATAR_SIZE | 生成图片尺寸(默认 512x512) |
开关关闭时对应 API 返回 503,前端不显示「AI 生成」入口。生成的头像图片存入 MinIO public bucket(avatars/ai/),经 nginx /avatars/ 反代访问。
语音识别(ASR)
终端对话中的语音转文字(含企业微信渠道语音消息转录)使用外部云 ASR(火山引擎豆包 OpenSpeech),由 gateway 消费。
优先走产品设置
下表环境变量均为兜底配置——管理员在管理台 系统管理 → 产品设置 → 语音识别 中保存的值优先生效,保存后约一分钟内热生效,无需重启(详见 产品设置使用指南)。
| 环境变量 | 说明 |
|---|---|
UA_ASR_PROVIDER | 服务商:volcengine(默认,即火山引擎);留空关闭语音识别 |
UA_ASR_TIMEOUT | 单次识别超时秒数(默认 30) |
UA_ASR_VOLC_API_KEY | 火山引擎 API Key(经 k8s Secret 注入,不入仓) |
UA_ASR_VOLC_RESOURCE_ID | 资源 ID(默认 volc.seedasr.auc) |
UA_ASR_VOLC_ENDPOINT | API 接入点(留空用官方默认地址) |
命令沙箱(OpenSandbox)
智能体实例启用「命令沙箱」时,终端命令在独立的 OpenSandbox 沙箱中执行(与引擎运行环境隔离,每位用户独立沙箱、空闲自动回收)。沙箱服务已包含在一键部署链路中(deploy/ci/deploy.sh 自动部署并注入 API key),手动部署方式:
# 部署 OpenSandbox server + controller(含 CRD、数据面 ns opensandbox)
# 生产必须先把清单内 api-key 占位值替换为随机串(与 veyraos-secret 的 opensandbox-api-key 同值)
kubectl apply -f deploy/k8s/infra/opensandbox.yaml
# 验证
kubectl -n opensandbox-system get deploy,pod要点:
- API Key 两端同值:
opensandbox-system/opensandbox-api-key(server 校验)与veyraos/veyraos-secret的opensandbox-api-key(引擎 Pod 经 secretKeyRef 透传)必须一致。一键部署由deploy.sh用同一变量(.env.local的OPENSANDBOX_API_KEY,留空则复用集群已有值/首次自动生成)注入两端;换值后自动滚动重启引擎 Pod 与 opensandbox-server(两端都只在 Pod 启动时解析 secret,任一端不重启都会导致沙箱创建 401)。 - manager 通过
OPENSANDBOX_SERVER_URL(默认http://opensandbox-server.opensandbox-system.svc.cluster.local)注入引擎 Pod,无需额外配置。 - 沙箱镜像来自阿里云公开镜像仓(
sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/),无需拉取凭据。 - 不启用命令沙箱的实例不受此组件影响(不注入相关 env,terminal 命令仍走引擎本地执行)。
容量估算
沙箱是独立 K8s Pod,按「实例并发用户数 × 实例配置的沙箱内存」估算数据面节点容量;节点 CPU requests 紧张时沙箱会 Pending,表现为终端命令长时间无响应。
资源监控(metrics-server)
资源池详情与智能体实例详情的 CPU/内存趋势图由 manager 后台 metric_sampler 每 60 秒采样引擎 Pod 用量落库生成,数据源为 metrics.k8s.io API(metrics-server)。本地 k3s 自带 metrics-server;非 k3s 集群(如自建 k8s / 云集群)若未部署该组件,采样器每轮跳过、监控趋势图恒为空:
# 非 k3s 集群部署 metrics-server(官方 components.yaml v0.9.0,已 vendored)
kubectl apply -f deploy/k8s/infra/monitoring/metrics-server.yaml
# 验证
kubectl top nodes部署后采样器自动开始积累数据(约 1 分钟后趋势图出现首个点)。metrics-server 不可用时功能优雅降级(不阻塞,仅无历史时序),但历史数据不会自动回补。
服务部署
发布版本时不需要在此手工构建镜像:平台服务镜像由主仓流水线的手动 job
build-platform-images构建并推入容器镜像仓库(见deploy/offline/README.md)。 下面的本地构建 + 导入仅用于开发调试与手工部署。
CI 流水线:nightly 与一键发包
主仓 .gitlab-ci.yml 提供两条自动化链路(执行机 tag veyra-cloud):
- nightly 每日构建 + 测试环境自动部署(schedule 触发):
nightly-build-images(平台镜像打<VERSION>-nightly.<日期>tag,引擎镜像幂等跳过) →nightly-package(slim 精简 bundle,只做 registry 存在性校验) →nightly-deploy-test(ssh 到测试机跑veyra-keeper upgrade+ 冒烟)。 版本号自动派生,全程无需人工输入。 - release 一键发包(
v*tag push 触发):build-platform-images→build-engine-images→bundle-offline自动执行,deploy-test-release手动卡点部署测试环境。版本号唯一来源是 git tag /VERSION文件 (先本地scripts/bump-version.sh <版本号>提交再打 tag),流水线 UI 不接受版本输入。 - 单服务重建(修单个服务时避免全量重跑):
Run pipeline传变量PLATFORM_SERVICES=manager(空格分隔可多个,build-platform-images/nightly-build-images均支持),再按需配合FORCE=1(覆盖已存在的同名 tag, ⚠️ 仅限 nightly/未正式发布 tag)与VERSION_OVERRIDE=<tag>(web 手动跑 build-platform-images 时缺省 tag =VERSION文件值,刷 nightly tag 须显式传)。 三个变量已在.gitlab-ci.yml顶层variables:声明,Run pipeline 表单自动预填 并带描述:FORCE提供下拉选项;PLATFORM_SERVICES为文本输入框(多服务空格分隔, 如manager console-admin)。表单顶部另有platform_services多选下拉 (GitLab 19.0+ 的 spec:inputs),点选多个服务与文本输入等效,多选非空时优先。 - 子集增量部署(单服务更新后一键上测试环境):
Run pipeline只传PLATFORM_SERVICES=manager(不要传VERSION_OVERRIDE/FORCE),nightly 链 自动完成「子集构建 → slim 打包(放行未选服务缺镜像)→ 测试环境增量部署」: 对选中服务kubectl set image到本次 nightly tag 并滚动重启,未选服务保持现网 版本不动;部署后跑核心 Deployment 就绪检查 + HTTP 冒烟。测试环境版本漂移由 下次全量部署(keeper upgrade)收敛。
此外提供若干 web 手动 job(Run pipeline 后在界面上按需点运行):
sync-base-images:把构建期基础镜像(console-admin-deps/skill-engine-deps/manager-deps/gateway-deps/engine-deepseek-deps等,由仓内Dockerfile.deps重建)同步进本仓 registry。这些镜像不随 bundle 发布,但必须先于平台/引擎镜像构建存在——镜像表变更或新增服务后须补跑,否则build-*-images拉不到基础镜像即失败(manager-deps首次同步是冷构建,约 10–20 分钟)。 DeepSeek 的runtime/package-lock.json变化后,须先以FORCE=1重建engine-deepseek-deps,再构建正式引擎镜像;引擎构建会拒绝使用 lockfile 不匹配的依赖镜像。 变量SYNC_BASE_IMAGES可选填短名子集(空格分隔,如manager-deps),缺省全量。sync-thirdparty/sync-bss:第三方镜像 / 账号中心镜像同步进本仓 registry。sync-bss从registry.gitlab.infrouter.com/veyra/veyra-bss拉取bss/account-portal镜像,版本由deploy/offline/bss.version控制;上游veyra-bss发版后需先跑本 job 再打 bundle。build-docs/sync-landing-docs:资料中心独立构建与生产门户同步。build-docs在 web 手动流水线和 release tag 流水线自动生成同源 dist 及 tar.gz 工件;sync-landing-docs是独立手动卡点,只把该工件同步到生产门户的/var/www/veyraos-landing/docs/, 不重建、不覆盖 landing 主站。console-admin 镜像仍内嵌同一版本的资料中心, 供 console 域和离线部署直接访问;在线管理台帮助入口默认跳https://veyraos.cn/docs, 离线包构建时改为本地/docs。 执行同步前需在 CI/CD 变量中配置LANDING_DOCS_SSH(门户 ssh 目标,形如user@host) 和 File 类型的LANDING_DOCS_SSH_KEY(部署私钥),目标账号需具备 NOPASSWD sudo rsync 权限。 门户 nginx 还需包含apps/landing/nginx.conf中 OpenAPI spec 的精确代理规则, 否则门户的 Swagger UI 无法读取接口定义。
需要在 GitLab UI 一次性配置(yaml 无法定义,重建 GitLab 后须重做):
- Pipeline schedule:
Build → Pipeline schedules新建,分支main, 建议 UTC 20:37(北京 04:37,避开整点半点)。 - CI/CD 变量(Settings → CI/CD → Variables,均建议 masked,
*号必填):TEST_ENV_SSH_TARGET*:测试机 ssh 目标(user@host形态)TEST_ENV_DOMAIN:测试环境域名(配置后 nightly 部署末尾做 HTTP 冒烟)TEST_KEEPER_STATE_PATH:keeper state 文件路径(缺省自动探测)TEST_ENV_EXTRA_ENV:多行<deployment>:<KEY>=<VALUE>,部署后重补 手工环境变量(keeper 重渲染会冲掉)OSS_ACCESS_KEY_ID/OSS_ACCESS_KEY_SECRET:bundle-offline 与 keeper 二进制同步用(group 级已有则无需重复配置)
- Runner 部署密钥(一次性,替代 CI 变量传私钥):masked 变量不支持多行 私钥,部署 job 的 ssh 认证改用执行机宿主持有的专用密钥对——
ssh-keygen -t ed25519 -f /etc/gitlab-runner/keys/test-env-ed25519(空口令), config.tomlvolumes加"/etc/gitlab-runner/keys:/keys:ro"挂入 job 容器, 公钥登记到测试机veyra用户authorized_keys。重建执行机后须重做。 - Registry 清理策略(Settings → Packages and registries → Cleanup policy): 按 tag 正则
.*-nightly\..*保留最近 7 个,防止 nightly tag 堆积。
引擎镜像版本升级的存量实例滚动见系统管理 · 引擎版本升级。
# 构建 Manager 镜像(本地/任意架构用 Dockerfile.local;
# CI 链路用 services/manager/Dockerfile,基于 registry 内的依赖预构建镜像)
docker build -t veyra/veyra-os/manager:latest -f services/manager/Dockerfile.local .
# 载入 k3s
docker save veyra/veyra-os/manager:latest | colima ssh -- sudo ctr -n k8s.io images import -
# 部署所有服务
kubectl apply -n veyraos -f deploy/k8s/services/
# 初始化数据库种子数据
kubectl exec -n veyraos deployment/manager -- python /app/scripts/seed.py引擎部署
引擎实例 Pod 由 manager 按需创建:所用镜像取自 manager 自身的引擎版本配置,可被 UA_<引擎>_IMAGE(如 UA_HERMES_IMAGE)覆盖。使用一键部署脚本或离线安装包时,这些镜像地址由部署链路按镜像分发方式自动注入(在线/镜像仓库 → 带仓库前缀;离线本地导入 → 本地镜像名),无需手工设置;只有手工部署时才需要自行保证镜像地址可达。
发布版本时引擎镜像同样由主仓流水线的手动 job
build-engine-images构建并推送 (tag 取各engines/*/VERSION);下面的本地构建仅用于开发调试。
# 构建引擎镜像
docker build --no-cache -t veyra/veyra-os/engine-hermes:latest -f engines/hermes/Dockerfile .
docker save veyra/veyra-os/engine-hermes:latest | colima ssh -- sudo ctr -n k8s.io images import -
# 创建 DeepSeek API Key Secret
kubectl create secret generic -n veyraos deepseek-key \
--from-literal=deepseek-api-key=sk-your-key-here
# 部署引擎 (示例: engine-hermes-test)
kubectl apply -n veyraos -f deploy/k8s/engines/hermes-template.yaml
# (需替换模板中的 AGENT_ID 占位符)端用户门户部署
# 构建镜像(apps/enduser/Dockerfile)
docker build -t veyra/veyra-os/enduser-portal:latest -f apps/enduser/Dockerfile apps/enduser/
kubectl rollout restart -n veyraos deploy/enduser-portal产品主页(Landing)部署
Landing 已迁 veyra-router 仓(三仓拆分),下列命令在该仓根执行;本仓不再包含 landing 的构建与部署清单。
# 构建镜像(apps/landing/Dockerfile,在 veyra-router 仓根执行)
docker build -t veyraos/console-landing:latest -f apps/landing/Dockerfile .
docker save veyraos/console-landing:latest | colima ssh -- sudo ctr -n k8s.io images import -
# 部署到 k3s(NodePort 30082)
kubectl apply -n veyraos -f deploy/k8s/apps/landing.yaml云上裸域名 ingress + TLS 由 veyra-router 仓的部署链路负责(含 landing-secret TLS 证书的创建与 ingress 渲染),本仓 deploy/ci/deploy.sh 不再 apply landing 相关资源。
统一入口与子域分流
平台对外提供四个入口,按访问者身份区分:
| 入口 | 云上子域 | 本地 k3s NodePort | 面向人群 |
|---|---|---|---|
| 企业客户平台(account-portal) | account.<域名> | 30083 | 企业客户:注册企业、管理成员、API Key、钱包与订阅 |
| 管理后台(console-admin) | console.<域名> | 30080 | 平台运营人员 |
| 用户对话门户(enduser-portal) | chat.<域名> | 30081 | 终端用户:浏览器内与智能体对话 |
| 产品主页(console-landing) | 裸域名 <域名> | 30082 | 所有访客,含统一入口页 /entry |
云上部署
本仓 deploy/ci/deploy.sh 只 apply 本仓两个子域的 ingress:
chat-ingress.yaml:chat.<域名>终端门户admin-ingress.yaml:console.<域名>管理后台
账号中心(account.<域名> 的 account-ingress.yaml 与 account 服务清单)与运营门户(platform.<域名>)随 veyra-bss 仓部署;产品主页(裸域名)随 veyra-router 仓部署。四个入口同域协作,但部署清单按仓分离。
入口分流行为
- 各门户独立会话(Cookie 不跨子域,令牌各自经
Authorization头传递)。 - 令牌按签发方区分用途:管理后台与对话门户使用管理台签发的令牌,企业客户平台使用账号中心签发的门户令牌。
- 管理后台无独立登录页:未登录访问自动跳账号中心授权页完成统一登录,授权码回跳后由管理台建本地会话(与 Router 控制台同一 SSO 链路,见 SSO 单点登录)。
- 前端守卫自动纠偏:在管理后台持有门户令牌会被引导至企业客户平台,反之亦然;两端经独立子域(
console.<域名>/account.<域名>)直达。 - 无令牌访客可从产品主页「全部入口」按钮或
/entry统一入口页按进入意图选择工作台(Router 控制台 / 管理后台 / 用户对话门户;Router 控制台与管理后台入口未登录时自动跳账号中心授权页完成统一登录)。
入口地址配置
管理台内的账号中心跳转(右上角「账号中心」下拉项、账户设置「凭证自助」)与发布渠道的体验链接按下列地址渲染;账号中心地址为空串时,管理台内相关入口整体隐藏。SSO 已配置时这些入口走免登授权链直达(用户经管理台 SSO 登录后已在账号中心持有会话);SSO 未配置时降级为普通跳转。
| 环境变量 | 说明 |
|---|---|
UA_PORTAL_BASE_URL | 终端门户对外地址(如 https://chat.<域名>),用于发布渠道的「Web 网页」体验链接 |
UA_ACCOUNT_PORTAL_URL | 账号中心门户地址(如 https://account.<域名>);留空时管理台内的账号中心跳转入口全部隐藏 |
云上部署时由 deploy/ci/deploy.sh 按域名自动注入(可在 deploy/ci/.env.local 覆盖);离线包安装时由安装向导按访问模式(域名 / 节点 IP)自动填充。
端口转发 (本地开发)
kubectl port-forward -n veyraos svc/manager 8002:8002 # Manager API
kubectl port-forward -n veyraos svc/gateway 8010:8010 # Gateway
kubectl port-forward -n veyraos svc/enduser-portal 3000:80 # 终端门户验证端到端流程
# 1. 登录获取 Token(管理台入口,JWT aud=admin)
curl -s http://localhost:8000/api/manager/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"<管理员账号>","password":"<管理员密码>"}'
# 2. 创建并发布智能体(定义 + 发布)
TOKEN=<access_token>
curl -s -X POST http://localhost:8000/api/manager/agent-definitions \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"助手","engine_type":"HERMES"}'
curl -s -X POST http://localhost:8000/api/manager/agents/<definition_id>/publish \
-H "Authorization: Bearer $TOKEN"
# 3. 测试 Gateway 透传 (非流式)
curl -s -X POST http://localhost:8010/v1/chat/completions \
-H "Authorization: Bearer <engine_api_key>" \
-H "Content-Type: application/json" \
-d '{"model":"agent-test","messages":[{"role":"user","content":"你好"}]}'
# 4. 打开浏览器访问端用户门户
open http://localhost:3000镜像构建顺序 (依赖链)
各服务镜像独立构建;DeepSeek 正式引擎镜像基于预构建依赖镜像,其余构建期基础镜像统一经本仓 registry 分发:
veyra/veyra-os/manager:latest
veyra/veyra-os/gateway:latest
veyra/veyra-os/engine-hermes:latest (FROM python:3.11-slim)
veyra/veyra-os/engine-deepseek:latest (FROM engine-deepseek-deps:latest,仅打包 wrapper 与本地插件)
veyra/veyra-os/console-admin:latest
veyra/veyra-os/enduser-portal:latest
veyra/veyra-os/hub:latest
veyra/veyra-os/skill-engine:latest清理
# 删除命名空间下的所有资源
kubectl delete namespace veyraos