Docker 分布式集群
分布式集群部署用于验证 RTC Agent 的多 Worker 能力 — 2 个 Server 容器 + Admin-server 管理服务 + Nginx 负载均衡 + 完整可观测性栈(Jaeger、Prometheus、Grafana、Loki 等)。
| 服务 | 端口 | 说明 |
|---|---|---|
| Nginx | 28080 | 负载均衡入口 |
| Server 1 & 2 | 内部 8888 | 不直接暴露 |
| Admin-server | 28081 | 管理后台(:28081 → :8081) |
| PostgreSQL | 25432 | 带 pgvector |
| Redis | 26379 | Worker 协调 |
| Jaeger UI | 26686 | 追踪可视化 |
| Jaeger OTLP | 24317 | gRPC 接入 |
| Prometheus | 29090 | 指标采集 |
| Grafana | 23001 | 仪表盘(admin/admin) |
| Loki | 23100 | 日志聚合 |
| Pyroscope | 24040 | 持续性能分析 |
| Alertmanager | 29093 | 告警路由 |
| Mock OAuth2 | 20060 | 开发用 OAuth2 |
端口设计:所有端口使用 2xxxx 段,避免与本地常用服务端口冲突。
Nginx 路由规则
Section titled “Nginx 路由规则”Nginx 根据请求路径将流量分发到不同后端服务:
| 路径 | 上游 | 说明 |
|---|---|---|
/admin/ | admin-server | 管理后台 SPA 静态资源 + API |
/api/auth/ | admin-server | 管理员认证 API(登录、刷新、登出) |
/.well-known/jwks.json | admin-server | JWKS 公钥端点(供主服务器验证 JWT) |
| 其余路径 | server 集群 | WebSocket + HTTP 反向代理(负载均衡到 Server-1 / Server-2) |
💡 管理后台可通过 Nginx 统一入口访问:
http://localhost:28080/admin/,也可直接访问http://localhost:28081。
1. 准备配置
Section titled “1. 准备配置”复制 .env.example 模板并填入实际值:
cp .env.example .env编辑 .env,填入你的 LLM API Key:
LLM__API_KEY=your-api-key-here⚠️ 生产环境必须设置
SERVER__ENV=production:Docker 配置默认env: "development"以方便本地调试。生产部署时必须通过环境变量SERVER__ENV=production覆盖,否则将跳过关键安全检查(OAuth2 redirect_uri 白名单、debug 端点强制认证、metrics 端点强制认证等)。💡 环境变量命名规则:大写字母 + 双下划线
__分隔层级,对应 YAML 配置的层级结构。例如llm.api_key→LLM__API_KEY,database.dsn→DATABASE__DSN。这种映射由 Viper 的SetEnvKeyReplacer(".", "__")实现。
配置优先级(从高到低):
| 优先级 | 来源 | 说明 |
|---|---|---|
| 1 | 环境变量 | 如 LLM__API_KEY,通过 Viper 的 AutomaticEnv 实现 |
| 2 | 配置文件 | etc/config.yaml 或 --config 指定的文件 |
| 3 | 默认值 | 代码中 SetDefault 设置 |
⚠️ 敏感字段处理:敏感字段(如
api_key、password)建议不在 YAML 中写明文,而是通过环境变量配置。环境变量优先级高于配置文件,可以安全地覆盖 YAML 中的值。
YAML 配置
Section titled “YAML 配置”编辑 etc/config.docker.yaml(docker-compose.yml 会自动挂载此文件):
database: dsn: "postgres://rtc_agent:rtc_agent@postgres:5432/rtc_agent?sslmode=disable"
redis: addr: "redis:6379"
tracing: enabled: true endpoint: "jaeger:4317" sample_rate: 1.0
# Token Exchange: 信任 admin-server 签发的 JWT(RFC 8693)token_exchange: external_issuers: - name: "admin-server" issuer: "http://admin-server:8081" jwks_uri: "http://admin-server:8081/.well-known/jwks.json" allowed_algorithms: ["RS256", "ES256"] cache_ttl: 3600 claims_mapping: sub: "sub" email: "email" name: "name" avatar_url: "picture"
providers: mock: enabled: true url: "http://mock-oauth2:10060"
llm: provider: "claude" # api_key 通过环境变量 LLM__API_KEY 配置,不在 YAML 中写明文 model: "claude-sonnet-4-20250514"⚠️ OAuth2 服务地址:
providers.mock.url指向 OAuth2 授权服务。示例中的192.168.31.60:20060是开发环境的公网 IP 示例。开发者需要部署自己的 OAuth2 服务(协议与 mock-oauth2 兼容),并将此地址替换为实际的服务地址。详见 认证与授权。💡 Token Exchange:配置
token_exchange后,主服务器可通过 JWKS 端点验证 admin-server 签发的 JWT,实现管理员统一认证。Admin-server 使用独立的etc/admin.docker.yaml配置文件。详见 HTTP API - Admin-server。
docker compose up -d启动顺序:PostgreSQL/Redis → migrate(一次性容器)→ Server-1 & Server-2 & Admin-server → Nginx
Admin-server 首次启动时会自动生成 JWT 密钥对(RS256),存储在 full-admin-server-keys Docker volume 中。如需手动创建管理员账号:
# 创建管理员用户docker compose exec admin-server ./rtc-agent admin account create \ --email admin@example.com \ --password your-password \ --name "Admin"访问管理后台:http://localhost:28081
# 健康检查(通过 Nginx 负载均衡)curl http://localhost:28080/healthz# {"status":"ok"}
# 查看容器状态 — 所有容器应为 healthy/runningdocker compose ps
# Jaeger 追踪面板open http://localhost:26686
# Grafana 可观测性仪表盘open http://localhost:23001
# Prometheus 指标端点curl http://localhost:28080/metrics💡 分布式部署预配置了 8 个 Grafana 仪表盘和 40+ 条告警规则,覆盖数据库、队列、WebSocket、认证、熔断器、对象存储等全链路。详见 可观测性监控。
4. 分布式行为验证
Section titled “4. 分布式行为验证”两个 Server 共享同一个 PostgreSQL 和 Redis。当用户请求通过 Nginx 分发到不同 Server 时:
- Session Affinity:通过 Redis 分布式锁(
SET NX)实现,同一时刻只有一个 Worker 处理某个 Session 的工作 - RTC Checkpoint:Agent 执行远程工具调用时,检查点存在 Redis 中,任何 Worker 可恢复
- Worker 心跳:各 Worker 独立向 Redis 注册、心跳、竞争任务
5. 停止 & 清理
Section titled “5. 停止 & 清理”docker compose down # 停止容器docker compose down -v # 同时删除数据卷6. 重启恢复机制
Section titled “6. 重启恢复机制”Server 在启动时会自动执行 stale turns 恢复,确保因崩溃或重启而中断的工作能够继续。
| 概念 | 说明 |
|---|---|
| Stale Turn | 处于非终态(running / pending / interrupted)的 Turn,由上次崩溃或重启遗留 |
| Ghost Work | 处于 processing 状态的 work item,但 session 锁已过期(Worker 崩溃遗留) |
| recoverStaleTurns | Server 启动时的恢复入口,扫描并处理所有 stale turns |
| RequeueGhostWork | 将 ghost work item 重新放回队列,以便 Worker 重新领取 |
- 查找 stale turns:扫描数据库中所有
running、pending、interrupted状态的 Turn - 标记中断:将
running/pending的 Turn 标记为interrupted - 重排队 ghost work:批量检查并重新排队因崩溃遗留的 work item
- 发布 resume:为每个 stale Turn 发布 resume work item,触发 Worker 恢复处理
- 释放 session 锁:清理过期的 session 分布式锁,使 Worker 可以重新竞争
💡 恢复过程对前端用户透明。被中断的 Turn 会通过
turn.updated事件通知前端状态变为interrupted,随后恢复处理时自动继续。RTC Checkpoint 也在此过程中发挥作用——等待前端工具结果的 Turn 可以从 Redis Checkpoint 恢复,无需用户重新操作。