跳转到内容

Docker 分布式集群

分布式集群部署用于验证 RTC Agent 的多 Worker 能力 — 2 个 Server 容器 + Admin-server 管理服务 + Nginx 负载均衡 + 完整可观测性栈(Jaeger、Prometheus、Grafana、Loki 等)。

服务端口说明
Nginx28080负载均衡入口
Server 1 & 2内部 8888不直接暴露
Admin-server28081管理后台(:28081 → :8081)
PostgreSQL25432带 pgvector
Redis26379Worker 协调
Jaeger UI26686追踪可视化
Jaeger OTLP24317gRPC 接入
Prometheus29090指标采集
Grafana23001仪表盘(admin/admin)
Loki23100日志聚合
Pyroscope24040持续性能分析
Alertmanager29093告警路由
Mock OAuth220060开发用 OAuth2

端口设计:所有端口使用 2xxxx 段,避免与本地常用服务端口冲突。

Nginx 根据请求路径将流量分发到不同后端服务:

路径上游说明
/admin/admin-server管理后台 SPA 静态资源 + API
/api/auth/admin-server管理员认证 API(登录、刷新、登出)
/.well-known/jwks.jsonadmin-serverJWKS 公钥端点(供主服务器验证 JWT)
其余路径server 集群WebSocket + HTTP 反向代理(负载均衡到 Server-1 / Server-2)

💡 管理后台可通过 Nginx 统一入口访问:http://localhost:28080/admin/,也可直接访问 http://localhost:28081。

复制 .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 中的值。

编辑 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/running
docker compose ps
# Jaeger 追踪面板
open http://localhost:26686
# Grafana 可观测性仪表盘
open http://localhost:23001
# Prometheus 指标端点
curl http://localhost:28080/metrics

💡 分布式部署预配置了 8 个 Grafana 仪表盘和 40+ 条告警规则,覆盖数据库、队列、WebSocket、认证、熔断器、对象存储等全链路。详见 可观测性监控。

两个 Server 共享同一个 PostgreSQL 和 Redis。当用户请求通过 Nginx 分发到不同 Server 时:

  • Session Affinity:通过 Redis 分布式锁(SET NX)实现,同一时刻只有一个 Worker 处理某个 Session 的工作
  • RTC Checkpoint:Agent 执行远程工具调用时,检查点存在 Redis 中,任何 Worker 可恢复
  • Worker 心跳:各 Worker 独立向 Redis 注册、心跳、竞争任务
终端窗口
docker compose down # 停止容器
docker compose down -v # 同时删除数据卷

Server 在启动时会自动执行 stale turns 恢复,确保因崩溃或重启而中断的工作能够继续。

概念说明
Stale Turn处于非终态(running / pending / interrupted)的 Turn,由上次崩溃或重启遗留
Ghost Work处于 processing 状态的 work item,但 session 锁已过期(Worker 崩溃遗留)
recoverStaleTurnsServer 启动时的恢复入口,扫描并处理所有 stale turns
RequeueGhostWork将 ghost work item 重新放回队列,以便 Worker 重新领取
  1. 查找 stale turns:扫描数据库中所有 running、pending、interrupted 状态的 Turn
  2. 标记中断:将 running / pending 的 Turn 标记为 interrupted
  3. 重排队 ghost work:批量检查并重新排队因崩溃遗留的 work item
  4. 发布 resume:为每个 stale Turn 发布 resume work item,触发 Worker 恢复处理
  5. 释放 session 锁:清理过期的 session 分布式锁,使 Worker 可以重新竞争

💡 恢复过程对前端用户透明。被中断的 Turn 会通过 turn.updated 事件通知前端状态变为 interrupted,随后恢复处理时自动继续。RTC Checkpoint 也在此过程中发挥作用——等待前端工具结果的 Turn 可以从 Redis Checkpoint 恢复,无需用户重新操作。