部署
本文档同时覆盖两种部署方式:
- 本地/自建 VM 方式(Docker Compose)
- GitHub Actions CI/CD 方式(推送镜像 + 环境发布)
本地 Docker Compose(开发与联调)
项目包含两个 Docker Compose 文件,用于分离基础设施与应用服务。
首先启动基础设施服务:
just docker-infra
或手动执行:
docker network create chameleon-net
docker compose -f docker-compose.infra.yml up -d
然后启动应用服务:
docker compose up -d --build
默认端口映射:
- AI 服务:8000
- Demo 后端:3000
- Demo 前端:80
- Docs 站点:8001
- MinIO:9000
- MinIO Console:9001
- Qdrant:6333
- PostgreSQL:5432
- pgAdmin:5050
- RedisInsight:5540
中间件管理界面
各中间件提供 Web 管理界面,用于浏览和管理内部资源(数据库表、缓存键、向量集合、对象存储桶等)。
| 服务 | 地址 | 默认账号 |
|---|---|---|
| pgAdmin(PostgreSQL) | http://localhost:5050 |
邮箱:PGADMIN_DEFAULT_EMAIL(默认 admin@admin.com)密码: PGADMIN_DEFAULT_PASSWORD(默认 admin) |
| RedisInsight(Redis) | http://localhost:5540 |
无需登录 |
| Qdrant Dashboard | http://localhost:6333/dashboard |
无需登录 |
| MinIO Console | http://localhost:9001 |
用户:MINIO_ROOT_USER密码: MINIO_ROOT_PASSWORD |
pgAdmin 连接 PostgreSQL
首次登录 pgAdmin 后,需手动添加服务器连接:
- Host:
postgres - Port:
5432 - Username:
.env中的POSTGRES_USER - Password:
.env中的POSTGRES_PASSWORD
RedisInsight 连接 Redis
首次打开 RedisInsight 后,手动添加 Redis 连接:
- Host:
redis - Port:
6379
容器间通信
ai-service与demo-backend通过外部网络chameleon-net通信。- 本地
docker-compose.yml未包含 Admin 前端;但已包含docs-site,默认映射到宿主机8001端口。 - CI/CD 发布清单
docker-compose.deploy.yml包含admin-frontend与docs-site服务。 docker-compose.deploy.yml面向 Dokploy,使用内部网络 +expose,不对宿主机直接发布端口。docker-compose.deploy.yml中ai-service使用命名卷ai_service_data(而非./data/./config.toml/./resourcesbind),避免 Swarm 节点路径不存在导致任务被拒绝。docker-compose.deploy.yml中ai-service同时加入dokploy-public网络,便于在 Dokploy 直接为 API 配置域名路由。
Dokploy 单机部署(环境变量与 Domain)
以下变量用于 docker-compose.deploy.yml。在 Dokploy 中可配置在项目的 Environment Variables。
必填变量
| 变量名 | 用途 | 示例 |
|---|---|---|
AI_SERVICE_IMAGE |
ai-service 镜像地址 |
registry.zata.cafe/aibot/ai-service:<tag> |
DEMO_BACKEND_IMAGE |
demo-backend 镜像地址 |
registry.zata.cafe/aibot/demo-backend:<tag> |
DEMO_FRONTEND_IMAGE |
demo-frontend 镜像地址 |
registry.zata.cafe/aibot/demo-frontend:<tag> |
ADMIN_FRONTEND_IMAGE |
admin-frontend 镜像地址 |
registry.zata.cafe/aibot/admin-frontend:<tag> |
DOCS_SITE_IMAGE |
docs-site 镜像地址 |
registry.zata.cafe/aibot/docs-site:<tag> |
强烈建议显式配置(不要使用默认值)
| 变量名 | 用途 |
|---|---|
POSTGRES_USER |
PostgreSQL 用户名 |
POSTGRES_PASSWORD |
PostgreSQL 密码 |
POSTGRES_DB |
PostgreSQL 数据库名 |
DATABASE_URL |
ai-service 数据库连接串,建议与上面三项保持一致 |
MINIO_ROOT_USER |
MinIO 管理账号 |
MINIO_ROOT_PASSWORD |
MinIO 管理密码 |
MINIO_ACCESS_KEY |
ai-service 访问 MinIO 的 Access Key,建议与 MINIO_ROOT_USER 一致 |
MINIO_SECRET_KEY |
ai-service 访问 MinIO 的 Secret Key,建议与 MINIO_ROOT_PASSWORD 一致 |
DASHSCOPE_API_KEY |
DashScope 模型调用密钥(如使用) |
OPENROUTER_API_KEY |
OpenRouter 模型调用密钥(如使用) |
可选变量
| 变量名 | 默认值 | 说明 |
|---|---|---|
DOKPLOY_PUBLIC_NETWORK |
dokploy-network |
Dokploy 外部网络名称 |
MINIO_ENDPOINT |
minio:9000 |
MinIO 容器内访问地址 |
QDRANT_HOST |
qdrant |
Qdrant 容器名 |
QDRANT_PORT |
6333 |
Qdrant 端口 |
Dokploy Domain 推荐配置
| Service Name | Host(示例) | Path | Internal Path | Strip Path | Container Port |
|---|---|---|---|---|---|
demo-frontend |
aibot.zata.cafe |
/ |
/ |
关闭 | 80 |
demo-backend |
aibot.zata.cafe |
/api |
/ |
开启 | 3000 |
admin-frontend |
admin.aibot.zata.cafe |
/ |
/ |
关闭 | 80 |
ai-service(Admin API 必需) |
admin.aibot.zata.cafe |
/api |
/ |
开启 | 8000 |
ai-service(可选直连) |
ai-api.aibot.zata.cafe |
/ |
/ |
关闭 | 8000 |
docs-site |
docs.aibot.zata.cafe |
/ |
/ |
关闭 | 80 |
注意事项:
demo-frontend是 Nginx 静态站点,容器端口是80;若填3000会导致Bad Gateway。- 前端固定通过
/api与后端通信(含 Socket.IO 路径/api/socket.io),所以demo-backend规则需使用Path=/api且开启Strip Path。 admin-frontend也固定调用同域名/api/*(如/api/knowledge-sources),因此admin.aibot.zata.cafe需要同时配置两条规则:/ -> admin-frontend:80与/api -> ai-service:8000(Strip Path开启)。- 若
Strip Path关闭,请求会以/api/knowledge-sources转发到ai-service,而后端真实路由是/knowledge-sources,会返回404。 docs-site是 Nginx 静态站点,推荐使用独立域名(例如docs.aibot.zata.cafe)直连容器80端口。- 修改 Domain 后,需要在 Dokploy 里重新部署 compose 才会生效。
自定义建议
- 使用外部数据库时,请将
DATABASE_URL指向托管实例。 - 为模型 API Key 使用安全的密钥管理方案。
- 多实例扩展场景下需确保 WebSocket 会话的一致性策略。
ai_service生产镜像默认不安装local_embedding依赖组以减小体积;若需容器内本地 embedding,请在构建时设置ENABLE_LOCAL_EMBEDDING=true。
GitHub Actions CI/CD(主线发布)
工作流文件
- CI:
.github/workflows/ci.yml - CD:
.github/workflows/cd.yml
触发规则
- CI:对
main的 Pull Request 自动触发 - CD 发布:
main分支 push 自动触发 - CD 回滚:手动触发
workflow_dispatch并填写rollback_tag(即历史 Git SHA 镜像标签)
镜像仓库与标签策略
- Registry Host:
registry.zata.cafe - 默认命名空间:
aibot(可通过 GitHub Repository VariableIMAGE_NAMESPACE覆盖) - 每个服务发布两个标签:
- 不可变标签:
${GIT_SHA} - 滚动标签:
main-latest
服务列表:
ai-servicedemo-backenddemo-frontendadmin-frontenddocs-sitepostgresminioqdrantredis
必需 GitHub Secrets
| Secret | 用途 | 示例 |
|---|---|---|
REGISTRY_USERNAME |
登录 registry.zata.cafe |
|
REGISTRY_PASSWORD |
登录 registry.zata.cafe |
|
DOKPLOY_PROD_DEPLOY_HOOK |
生产环境发布 webhook(手动审批后触发) | http://zata.cafe:3000/api/deploy/compose/lFyKFKfELXOthpMRsNaea |
PROD_HEALTHCHECK_URL |
生产发布后健康检查地址 | https://admin.aibot.zata.cafe/api/healthz 或 https://ai-api.aibot.zata.cafe/healthz |
可选:
| Secret | 用途 | 示例 |
|---|---|---|
DOKPLOY_STAGING_DEPLOY_HOOK |
若配置则在 staging job 自动触发 |
环境门禁(Manual Approval)
- 在 GitHub 仓库创建 Environments:
stagingproduction- 为
production配置 Required reviewers,即可在 CD 中实现人工审批后发布。
发布流程(main push)
- 构建并推送 5 个服务镜像的不可变标签
${GIT_SHA}到registry.zata.cafe - 校验
${GIT_SHA}标签在 registry 可见后,提升为滚动标签main-latest - 自动执行 staging 阶段(可选触发 Dokploy staging hook)
- 进入
production环境审批 - 审批通过后触发
DOKPLOY_PROD_DEPLOY_HOOK - 轮询
PROD_HEALTHCHECK_URL直到通过或超时失败
回滚流程
方案 A:GitHub Actions 手动回滚(推荐)
- 打开
CDworkflow 的Run workflow - 填写
rollback_tag(目标历史 SHA) - 流程会将各服务
${rollback_tag}重新标记为main-latest - 自动触发生产 deploy hook 并执行健康检查
说明:若该历史 tag 尚未包含 docs-site 镜像,回滚流程会保留现有 docs-site:main-latest,不会阻塞其他核心服务回滚。
方案 B:VM 上执行 Compose 回滚脚本
仓库内提供脚本:
scripts/deploy/compose-deploy.shscripts/deploy/compose-rollback.sh
示例(部署指定 SHA):
IMAGE_TAG=<git_sha> ./scripts/deploy/compose-deploy.sh \
--registry-host registry.zata.cafe \
--image-namespace aibot
示例(回滚到上一个成功版本):
./scripts/deploy/compose-rollback.sh
脚本会在 .deploy-state/ 记录 current.env / previous.env,用于快速恢复。
若目标回滚元数据缺失 DOCS_SITE_IMAGE 或对应镜像不可用,脚本会优先保留当前 docs 镜像,不可用时再回退到 docs-site:main-latest。