部署指南¶
HermesX v2.4.0-dev SaaS API 的 SaaS-only 部署方式:Docker Compose、Kubernetes 和 Helm。
HermesX v2.0.0 部署说明¶
HermesX v2.0.0 相比 v1.x 版本有以下关键变化:
| 变化项 | v1.x | v2.0.0 |
|---|---|---|
| 二进制名称 | hermes |
hermesx |
| Helm Chart 路径 | deploy/helm/hermes-agent/ |
deploy/helm/hermesx/ |
| 默认副本数 | 1 | 2 |
| PodDisruptionBudget | 未配置 | 默认启用(minAvailable: 1) |
| HPA | 默认禁用 | 默认启用(2-10 副本) |
| OTel 配置 | 手动挂载 | 内置环境变量注入 |
| LLM Model | 单一模型 | 支持模型目录热重载 |
部署前置检查¶
- [ ] Go 1.23+ 用于从源码构建
- [ ] PostgreSQL 16+(需要 RLS 支持)
- [ ] Redis 7+(用于限流 Lua 脚本)
- [ ] Kubernetes 1.28+(若使用 Helm 部署)
- [ ] Docker 24+(若使用 Docker Compose 部署)
SaaS 镜像¶
Dockerfile.saas 是唯一受支持的发布镜像。它会构建 Go SaaS API 二进制、构建 React WebUI、将 WebUI 产物复制到 /static、打包默认 Skills 用于租户初始化,并默认执行 CMD ["saas-api"]。
Dockerfile.saas 特性¶
# 多阶段构建
# Stage 1: 构建 WebUI
# Stage 2: 编译 Go 二进制
# Stage 3: 复制二进制 + WebUI 静态文件到运行时镜像
# 包含 /static 供 SAAS_STATIC_DIR 使用
# 默认 CMD: ["saas-api"]
Docker Compose 配置对比¶
| 配置 | 用途 | 包含服务 | API 端口 | 健康检查 |
|---|---|---|---|---|
docker-compose.prod.yml |
生产部署 | hermesx-saas + postgres + redis + minio + OTel + Jaeger + Nginx LB | 8080/8081 | wget health/live |
docker-compose.saas.yml |
SaaS 预发或本地 SaaS 验证 | hermesx-saas + postgres + redis + minio | 18080/18081 | curl health/ready |
docker-compose.test.yml |
集成测试 | postgres-test + redis-test + minio-test(tmpfs 无持久化) | 测试端口隔离 | pg_isready |
生产级配置(docker-compose.prod.yml)¶
docker-compose.prod.yml 是生产推荐的 Docker Compose 配置,包含以下特性:
- OTel Collector:接收 gRPC/HTTP OTLP,导出到 Jaeger + Prometheus
- Jaeger:分布式追踪后端(UI: http://localhost:16686)
- Nginx:3 副本负载均衡(ip_hash 会话亲和)
- 资源限制:每个服务均配置 CPU/memory limits
- 健康检查:所有关键服务均有 healthcheck
- 备份脚本:postgres 容器挂载
./scripts/backup目录
# 启动完整生产栈
docker compose -f docker-compose.prod.yml up -d
# 查看所有服务状态
docker compose -f docker-compose.prod.yml ps
# 查看 OTel collector 日志
docker compose -f docker-compose.prod.yml logs -f otel-collector
# 访问 Jaeger UI(追踪)
open http://localhost:16686
# 访问 Prometheus metrics
curl http://localhost:8889/metrics | grep hermesx
方式一:Docker Compose SaaS¶
docker-compose.prod.yml 用于生产化部署,docker-compose.saas.yml 用于预发或本地 SaaS 验证。两者都运行 hermesx saas-api,API 服务从 /static 提供内嵌 WebUI。
docker compose -f docker-compose.saas.yml up -d --build
curl http://localhost:18080/health/ready
open http://localhost:18080/admin.html
方式二:Kubernetes / Kind 验证¶
使用 Kind 在本地运行 Kubernetes 集群。
1. 创建集群¶
kind create cluster --name hermes
2. 部署 PostgreSQL¶
kubectl apply -f deploy/kind/postgres.yaml
postgres.yaml 包含:
- PersistentVolumeClaim(1Gi)
- Deployment(PostgreSQL 16 单实例)
- Service(ClusterIP, port 5432)
- ConfigMap(初始化用户和数据库)
3. 构建并加载镜像¶
# 构建 SaaS 镜像
docker build -t hermes-agent-saas:local -f Dockerfile.saas .
# 加载到 Kind 集群
kind load docker-image hermes-agent-saas:local --name hermes
4. 安装 Helm Chart¶
# v2.0.0: Chart 路径变更为 hermesx/
helm install hermesx deploy/helm/hermesx/ \
-f deploy/kind/values.local.yaml
values.local.yaml 覆盖:
- image.pullPolicy: Never(使用本地镜像)
- DATABASE_URL 指向 Kind 内 PostgreSQL Service
5. 验证¶
kubectl get pods
kubectl port-forward svc/hermesx 8080:8080
curl http://localhost:8080/health/ready
OTel Collector 接入说明¶
deploy/otel-collector.yaml 是 HermesX v2.0.0 内置的可观测性收集器配置。
| 协议 | 端口 | 说明 |
|---|---|---|
| OTLP gRPC | 4317 | 接收 HermesX OTel 导出(推荐) |
| OTLP HTTP | 4318 | HTTP 方式接收 OTel 数据 |
处理器:memory_limiter(512MiB limit)+ batch(1024 batch, 5s timeout)
导出器:Jaeger(traces)+ Prometheus:8889(metrics)+ Logging(warn 级别)
# 在 Helm 中启用 OTel
helm install hermesx deploy/helm/hermesx/ \
--set env.OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4317" \
--set env.OTEL_SERVICE_NAME="hermesx"
# 独立部署 OTel Collector
kubectl apply -f deploy/otel-collector.yaml
方式三:Helm Chart 生产部署¶
Chart 结构¶
deploy/helm/hermesx/
├── Chart.yaml # Chart 元数据
├── values.yaml # 默认值
└── templates/ # K8s 资源模板
安装¶
kubectl create secret generic hermesx-runtime \
--namespace hermesx \
--from-literal=DATABASE_URL="postgres://user:pass@pg-host:5432/hermes?sslmode=require" \
--from-literal=HERMES_ACP_TOKEN="$(openssl rand -hex 32)" \
--from-literal=HERMES_API_KEY="$(openssl rand -hex 32)" \
--from-literal=REDIS_URL="redis://redis:6379" \
--from-literal=LLM_API_KEY="replace-me" \
--from-literal=MINIO_ACCESS_KEY="replace-me" \
--from-literal=MINIO_SECRET_KEY="replace-me"
helm install hermesx deploy/helm/hermesx/ \
--namespace hermesx \
--create-namespace \
--set image.tag="v2.4.0-dev" \
--set secretEnv.existingSecret="hermesx-runtime" \
--set env.SAAS_ALLOWED_ORIGINS="https://your-domain.example.com"
values.yaml 关键配置¶
replicaCount: 2
image:
repository: hermesx/hermesx-saas
# 空值默认使用 Chart.appVersion;生产环境应固定 release tag 或 digest。
tag: ""
pullPolicy: IfNotPresent
secretEnv:
# 生产环境优先引用预创建的 Kubernetes Secret。
existingSecret: "hermesx-runtime"
keys:
DATABASE_URL: DATABASE_URL
HERMES_ACP_TOKEN: HERMES_ACP_TOKEN
HERMES_API_KEY: HERMES_API_KEY
REDIS_URL: REDIS_URL
LLM_API_KEY: LLM_API_KEY
MINIO_ACCESS_KEY: MINIO_ACCESS_KEY
MINIO_SECRET_KEY: MINIO_SECRET_KEY
serviceAccount:
create: true
automountServiceAccountToken: false
service:
type: ClusterIP
port: 8080
args:
- saas-api
env:
SAAS_API_PORT: "8080"
SAAS_ALLOWED_ORIGINS: "https://your-domain.example.com" # 生产必须设置具体域名
SAAS_STATIC_DIR: "/static"
HERMES_API_PORT: "8081"
LLM_API_URL: ""
LLM_MODEL: ""
podSecurityContext:
seccompProfile:
type: RuntimeDefault
containerSecurityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
networkPolicy:
enabled: false # 生产命名空间应启用并收紧 ingressFrom/egressTo。
resources:
limits:
cpu: "1000m"
memory: "512Mi"
requests:
cpu: "200m"
memory: "128Mi"
probes:
liveness:
path: /health/live
initialDelaySeconds: 5
periodSeconds: 10
readiness:
path: /health/ready
initialDelaySeconds: 5
periodSeconds: 10
# PodDisruptionBudget — v2.0.0 默认启用
pdb:
enabled: true
minAvailable: 1
# 自动扩缩容 — v2.0.0 默认启用
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
scaleDownStabilizationSeconds: 300
# TLS
tls:
enabled: false
certFile: ""
keyFile: ""
# PostgreSQL 子 Chart(开发用)
postgresql:
enabled: true
auth:
database: hermesx
username: hermes
password: hermes-dev-password
使用外部 PostgreSQL¶
生产环境应使用外部管理的 PostgreSQL:
helm install hermesx deploy/helm/hermesx/ \
--set postgresql.enabled=false \
--set env.DATABASE_URL="postgres://hermes:pass@rds-endpoint:5432/hermes?sslmode=require"
生产环境检查清单(Pre-flight Checklist)¶
安全性检查¶
- [ ]
HERMES_ACP_TOKEN使用高强度随机字符串(32+ 字符) - [ ]
SAAS_ALLOWED_ORIGINS设置为具体域名,禁止* - [ ]
DATABASE_URL通过 Kubernetes Secret 注入(不使用明文 values) - [ ] 启用 TLS(通过 Ingress 或
tls.enabled) - [ ] API Key 定期轮换机制已建立
- [ ] Helm values.yaml 中所有
changeme占位符已替换
高可用性检查¶
- [ ]
replicaCount >= 2(v2.0.0 默认 2) - [ ]
autoscaling.enabled: true(v2.0.0 默认启用) - [ ]
pdb.enabled: true(v2.0.0 默认启用,minAvailable: 1) - [ ] 健康探针
liveness和readiness已配置 - [ ] PostgreSQL 配置主从复制或使用云托管服务(RDS/Cloud SQL)
- [ ] Redis 启用 AOF 持久化用于分布式速率限制
可观测性检查¶
- [ ]
/metrics端点已接入 Prometheus(指标见下表) - [ ]
OTEL_EXPORTER_OTLP_ENDPOINT配置 OpenTelemetry Collector - [ ]
OTEL_SERVICE_NAME设置为hermesx - [ ] 日志采集到集中式日志平台(EFK/Loki)
- [ ] 配置审计日志保留策略(建议 365 天)
- [ ] OTel Collector 已部署并验证可接收数据
资源规划检查¶
- [ ] CPU/Memory requests 和 limits 已设置(参考下方扩缩容表格)
- [ ] PostgreSQL 配置连接池(推荐 PgBouncer,>5 实例时必需)
- [ ] MinIO 使用持久化存储卷(不使用 hostPath)
- [ ]
audit_logs/execution_receipts> 10M 行时考虑分区
v2.0.0 特有检查¶
- [ ] Helm Chart 路径已更新为
deploy/helm/hermesx/(不再是hermes-agent/) - [ ] 镜像仓库地址已更新为
hermesx/hermesx-saas(不再是hermes-agent-saas) - [ ]
HERMES_API_PORT: "8081"已加入 values(v2.0.0 双端口架构) - [ ]
REDIS_URL环境变量已配置(v2.0.0 限流依赖) - [ ]
MINIO_BUCKET设置为hermesx-skills(区分多环境)
方式四:多副本 HA (Docker Compose)¶
3 实例 + Nginx LB,适用于小规模生产或验证水平扩展能力。
cd deploy/
docker compose -f docker-compose.multi-replica.yml up -d --build
架构:Nginx (ip_hash) → 3× hermes instances → 共享 PG + Redis + MinIO
生产环境变量完整参考¶
必须¶
| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
PostgreSQL 连接串 | postgres://user:pass@host:5432/hermes?sslmode=require |
HERMES_API_KEY |
API 认证 Bearer token | sk-prod-xxxxx |
HERMES_API_KEY_LLM |
LLM Provider API key | sk-... |
HERMES_PROVIDER |
LLM Provider | openai, anthropic, gemini |
HERMES_MODEL |
默认模型 | gpt-4o, claude-sonnet-4-20250514 |
基础设施(推荐)¶
| Variable | Default | Description |
|---|---|---|
REDIS_URL |
— | Redis 连接,启用分布式限流(v2.0.0 新增) |
MINIO_ENDPOINT |
— | MinIO/S3 endpoint |
MINIO_ACCESS_KEY |
— | MinIO access key |
MINIO_SECRET_KEY |
— | MinIO secret key |
MINIO_BUCKET |
hermes-skills |
Skills bucket |
企业多副本部署必须配置 REDIS_URL。Redis 不可用时,运行时会降级到进程内 LocalDualLimiter,这是可用性优先的故障策略;每个副本独立计数,因此故障窗口内有效限流约为 limit × replica_count。强监管环境需要在发布证据中记录 Redis HA/故障演练,或在入口层选择 fail-closed/限流降载策略。
SaaS API(v2.0.0)¶
| Variable | Default | Description |
|---|---|---|
HERMES_ACP_TOKEN |
— | 静态管理员 Token(必填) |
SAAS_API_PORT |
8080 |
SaaS API 端口 |
SAAS_ALLOWED_ORIGINS |
—(不启用 CORS) | CORS 允许的源(生产必须设置具体域名) |
SAAS_STATIC_DIR |
— | 静态文件目录 |
HERMES_API_PORT |
8081 |
HTTP API 端口(v2.0.0 新增) |
HERMES_API_KEY |
— | API 认证 Token(v2.0.0 新增) |
Agent 运行时¶
| Variable | Default | Description |
|---|---|---|
HERMES_INSTANCE_ID |
hostname | HA 实例标识 |
HERMES_MAX_ITERATIONS |
20 |
Agent 最大迭代次数 |
HERMES_MAX_TOKENS |
4096 |
最大响应 token |
HERMES_BASE_URL |
provider default | 自定义 LLM endpoint |
HERMES_DEBUG |
false |
Debug 日志 |
HERMES_ENV |
development |
设为 production 时 egress 默认改为 deny-all |
HERMES_EGRESS_DEFAULT |
环境推导 | 显式覆盖 egress 默认策略:allow-all、deny-all、log-only |
可观测性(v2.0.0 增强)¶
| Variable | Default | Description |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT |
— | OTel Collector gRPC/HTTP |
OTEL_EXPORTER_OTLP_INSECURE |
false |
禁用 OTel TLS |
OTEL_SERVICE_NAME |
hermesx |
服务名(v2.0.0 默认值变更) |
Prometheus 指标¶
Scrape endpoint: GET /v1/metrics
| Metric | Type | Labels |
|---|---|---|
hermes_http_requests_total |
Counter | method, path, status, tenant_id |
hermes_http_request_duration_seconds |
Histogram | method, path, tenant_id |
hermes_http_requests_in_flight |
Gauge | — |
hermes_llm_request_duration_seconds |
Histogram | provider, model, status, tenant_id |
hermes_llm_tokens_total |
Counter | provider, model, direction, tenant_id |
hermes_rate_limit_rejected_total |
Counter | tenant_id |
hermes_tool_executions_total |
Counter | tool_name, status, tenant_id |
hermes_tool_execution_duration_seconds |
Histogram | tool_name, status, tenant_id |
hermes_active_sessions |
Gauge | tenant_id |
hermes_chat_completions_total |
Counter | tenant_id, status |
hermes_store_operation_duration_seconds |
Histogram | operation, entity |
告警建议¶
- alert: HermesHighErrorRate
expr: rate(hermes_http_requests_total{status=~"5.."}[5m]) / rate(hermes_http_requests_total[5m]) > 0.05
for: 2m
- alert: HermesLLMSlow
expr: histogram_quantile(0.95, rate(hermes_llm_request_duration_seconds_bucket[5m])) > 30
for: 5m
- alert: HermesRateLimitSurge
expr: rate(hermes_rate_limit_rejected_total[5m]) > 100
for: 1m
备份恢复¶
RPO/RTO 目标¶
| 组件 | RPO(最大数据丢失) | RTO(最大恢复时间) | 策略 |
|---|---|---|---|
| PostgreSQL | < 5 min | < 1 h | WAL archiving + pg_dump |
| Redis | < 15 min | < 5 min | BGSAVE + RDB 复制 |
| MinIO | < 1 h | < 30 min | mc mirror 全量镜像 |
PostgreSQL 备份¶
# 自动备份(在 postgres 容器内或有 pg_dump 的主机上执行)
./scripts/backup/backup.sh /backup
# 输出: /backup/hermes_YYYYMMDD_HHMMSS.sql.gz
# BACKUP_RETENTION_DAYS=7 (默认保留 7 天)
PostgreSQL 恢复¶
./scripts/backup/restore.sh /backup/hermes_20260507_120000.sql.gz
# 单事务恢复 + 自动运行 pending migrations
PITR¶
生产环境建议启用 WAL archiving 实现 < 5 min RPO。配置模板见 deploy/pitr/。
Redis 备份¶
# 触发 BGSAVE 并复制 RDB 到备份目录
./scripts/redis-backup.sh
# 环境变量:
# REDIS_HOST=localhost Redis 地址
# REDIS_PORT=6379 Redis 端口
# REDIS_PASSWORD= Redis 密码
# BACKUP_DIR=/backup/redis 本地备份目录
# S3_BUCKET= 可选 S3 存储桶(设置后自动上传)
# REDIS_DATA_DIR=/data Redis 数据目录
# RETENTION_DAYS=7 本地备份保留天数
Redis 恢复¶
# 1. 停止 Redis 服务
docker compose stop redis
# 2. 复制备份 RDB 到 Redis 数据目录
cp /backup/redis/redis-20260515_120000.rdb /data/dump.rdb
# 3. 启动 Redis(自动加载 dump.rdb)
docker compose start redis
# 4. 验证
redis-cli DBSIZE
MinIO 备份¶
# 镜像 bucket 到本地目录或远程 bucket
./scripts/minio-backup.sh
# 环境变量:
# MINIO_ENDPOINT=http://localhost:9000 MinIO 地址
# MINIO_ACCESS_KEY= Access Key(必填)
# MINIO_SECRET_KEY= Secret Key(必填)
# SOURCE_BUCKET=hermes-skills 源 bucket
# TARGET=/backup/minio 目标:本地路径或 s3://bucket-name
# RETENTION_DAYS=7 本地备份保留天数
MinIO 恢复¶
# 从本地备份恢复到 MinIO
mc alias set hermesx http://localhost:9000 $MINIO_ACCESS_KEY $MINIO_SECRET_KEY
mc mirror /backup/minio/hermes-skills-20260515_120000 hermesx/hermes-skills
# 验证
mc ls --recursive hermesx/hermes-skills | wc -l
灾难恢复验证¶
# 运行 DR 测试脚本,验证备份可恢复
./scripts/dr-test.sh
# 该脚本会:
# 1. 检查 Redis 备份文件存在性和完整性
# 2. 检查 MinIO 备份目录和文件数量
# 3. 验证 Redis 和 MinIO 在线数据一致性
# 4. 输出 PASS/FAIL 报告
Cron 调度建议¶
# PostgreSQL — 每 4 小时备份一次
0 */4 * * * /opt/hermesx/scripts/backup/backup.sh /backup/postgres >> /var/log/hermesx-backup-pg.log 2>&1
# Redis — 每 15 分钟备份一次
*/15 * * * * /opt/hermesx/scripts/redis-backup.sh >> /var/log/hermesx-backup-redis.log 2>&1
# MinIO — 每天凌晨 2 点全量镜像
0 2 * * * /opt/hermesx/scripts/minio-backup.sh >> /var/log/hermesx-backup-minio.log 2>&1
# DR 验证 — 每周日凌晨 4 点
0 4 * * 0 /opt/hermesx/scripts/dr-test.sh >> /var/log/hermesx-dr-test.log 2>&1
水平扩展¶
HermesX 实例无状态,所有持久化状态在 PG + Redis 中。
| 负载 | CPU/实例 | 内存/实例 | 实例数 |
|---|---|---|---|
| < 100 req/s | 1 core | 512MB | 1-2 |
| 100-500 req/s | 2 cores | 1GB | 3-5 |
| 500+ req/s | 4 cores | 2GB | 5+ |
数据库扩展建议:
- > 5 实例时使用 PgBouncer 连接池
- audit_logs / execution_receipts > 10M 行时考虑分区
安全加固¶
认证体系¶
- API Key: SHA-256 hash 存储,支持 scopes + expiry + rotation
- JWT: 签名验证 + claims 提取 tenant_id
- Static Token: 单租户部署的简单 Bearer token
行级安全 (RLS)¶
所有租户数据表启用 PostgreSQL RLS。每个事务通过 SET LOCAL app.current_tenant 设置上下文——即使应用层有 bug,数据库层面也阻止跨租户访问。
网络安全¶
- API 仅绑定内部网络,通过 reverse proxy + TLS 暴露
- PG/Redis/MinIO 禁止公网暴露
- 生产环境 MinIO 启用 TLS
回滚策略¶
应用回滚¶
docker compose -f docker-compose.prod.yml up -d --no-build # 使用上一个镜像
# 或
docker service update --image ghcr.io/org/hermes:previous-tag hermes
数据库回滚¶
Migrations 仅前向。回滚步骤: 1. 从最近备份恢复 2. 部署上一个应用版本 3. 验证数据完整性
回滚触发条件¶
- Error rate > 5% 持续 5 分钟
- P95 latency > 30s 持续 5 分钟
- 数据完整性告警(跨租户数据泄漏)
- 发布后发现 Critical 安全漏洞