面向企业微信 AI Bot 与飞书应用机器人的多租户 Agent 生产运行时。项目基于
tRPC-Agent-Python 1.1.19 的公开 Runner、Agent、Event 与 Tool Safety API,提供可靠 IM
接入、事务型 Session、无状态 Worker、租户隔离、运维治理和可观测性。原始需求归档在
docs/requirements.md。
本文既是项目入口,也是正式部署模板。默认 production overlay 在同一个 Kubernetes/ACK namespace 中 部署 Gateway、Admin、Worker、两个 IM 通道、后台任务、Ingress、PostgreSQL/pgvector、Redis、MinIO、 Prometheus、Prometheus Adapter 与 OpenTelemetry Collector。托管数据库、缓存、对象存储或观测平台仍可 替换这些内置组件,但必须使用受审查的 managed-services patch;不能一边删除内置依赖,一边继续声称默认 模板能够独立运行。仓库中的主机联调资产只用于历史兼容,不属于正式部署入口。
- 由已认证
channel_binding_id解析租户,服务端 HMAC 生成 Session ID,外部消息不能声明租户。 - PostgreSQL Inbox/Outbox、幂等键、Session lease 与 fencing token;Redis Streams 只作可重建传输。
- 同一 Session 串行提交、不同 Session 并行;一次 turn 的 event/state/outbound 原子可见。
- 企业微信 AI Bot WebSocket 长连接,以及飞书加密 HTTP 回调、URL challenge 和 OpenAPI 异步回复。
- 企业微信 fenced connection epoch/租约证据,以及独立签名 IM 探针。
- OIDC/JWKS、RBAC、ETag 乐观并发、Admin 幂等、审计、DLQ 查询和人工 outbound 重放。
- 工具白名单、预算预留、SDK Tool Safety、一次性确认令牌和非幂等工具歧义状态。
- PostgreSQL/RLS、Redis 单调投影、S3/MinIO staged artifact、pgvector 与外部 Memory 扩展口。
- 隐私优先 OpenTelemetry、Prometheus 指标、Docker Compose 和 Kubernetes/Kustomize。
prepare → backfill → shadow-read → dual-write → cutover → verify → cleanup/rollback迁移状态机。
项目不包含管理 UI、Telegram、微信公众号或微信客服;InMemory 后端仅用于单进程开发。
| 模式 | 用途 | 配置入口 | 是否为正式部署 |
|---|---|---|---|
| 本地 Docker Compose | 开发、功能联调、离线故障测试 | .env |
否 |
| Kubernetes/ACK production overlay | 完整应用、Ingress、数据依赖、观测、真实 IM、HPA、迁移与发布验收 | Kustomize + Kubernetes Secret | 是 |
正式部署只采用第二行。主机路径、systemd、面板数据库或临时测试域名都不得复制进正式集群配置。
本项目使用 Kustomize,不再引入另一套会产生配置漂移的 values.yaml。一个环境的正式输入由两份
非敏感文件和六类 Secret(五份 env Secret + 一份 IM 文件 Secret)组成:
deploy/kustomize/overlays/production/
├── kustomization.yaml # namespace、资源、镜像仓库和不可变 digest
├── production-config-patch.yaml # OIDC、S3、模型主机、调度器等非敏感设置
├── infrastructure-config.yaml # PostgreSQL bootstrap、Prometheus、OTel 配置
├── infrastructure-services.yaml # 集群内数据与观测 Service
├── infrastructure-statefulsets.yaml # PostgreSQL/Redis/MinIO/Prometheus + PVC
├── infrastructure-workloads.yaml # OTel Collector、MinIO bucket bootstrap
├── infrastructure-network-policy.yaml # 数据与观测最小网络边界
├── prometheus-adapter.yaml # external metrics API、RBAC、Adapter
├── ingress.yaml # Gateway HTTPS 入口
├── deployment-order-patch.yaml # Argo CD 依赖创建顺序
├── migration-order-patch.yaml # 首次部署迁移等待与顺序
├── managed-services-patch.example.yaml # 可选:删除内置依赖并改接托管服务
├── replicas-patch.yaml # 固定副本基线
├── wecom-ha-patch.yaml # 企业微信连接器跨节点约束
├── im-secret-mounts-patch.yaml # IM Secret 只挂载给需要的角色
└── namespace.yaml
受控 Secret 系统或仓库外目录:
├── service.env # runtime、Redis、S3、OIDC、HMAC
├── worker.env # 跨租户 worker 数据库身份
├── migration.env # schema owner/迁移身份
├── metrics.env # 只读 backlog 指标身份
├── infrastructure.env # 内置 PG/Redis/MinIO bootstrap 凭据
└── im/
├── feishu_app_secret
├── feishu_verification_token
├── feishu_encrypt_key
└── wecom_bot_secret
kustomization.yaml 与 production-config-patch.yaml 可以放在受审查的私有部署仓库;六类 Secret 只能
进入 Vault、KMS、ExternalSecret 或权限为 0600 的仓库外文件,不能提交到本项目。
- Python 3.11–3.13;生产镜像使用 Python 3.12 + Alpine 3.24。
- Git、Docker Engine 24+ 与 Docker Compose v2。
- 本地开发推荐 uv。
- Kubernetes 1.29+、
kubectl和内置 Kustomize;ACK 使用受支持版本。 - 首次使用裸
kubectl部署时建议安装yqv4,用于安全拆分迁移和工作负载。 - 默认 overlay 自带 PostgreSQL/pgvector、Redis、MinIO、Prometheus、OTel Collector 与 External Metrics
provider;存储类必须能动态供应
ReadWriteOncePVC。 - 集群仍需提供真实 OIDC issuer/audience、Ingress Controller、DNS 与 TLS Secret;应用调用的模型和 IM 平台是经出口策略批准的外部服务,不属于集群内组件。
初始化开发环境:
uv sync --extra dev --locked
uv run trpc-service --help
uv run trpc-service doctor --output runs/multitenant/sdk-upgrade.jsonPowerShell:
uv sync --extra dev --locked
uv run trpc-service --help
uv run trpc-service doctor --output runs\multitenant\sdk-upgrade.json- 不要提交
.env、Kubernetes Secret、kubeconfig、机器人 Secret、发布 nonce、签名私钥或测试账号。 - 不要把 Secret 放在命令行参数、聊天、截图、日志或报告中;使用文件、stdin 或 Secret 管理系统。
- 租户 binding 只保存
file://或经过白名单批准的env://引用,不保存明文。 - Session HMAC 至少 32 个随机字节;Emergency Queue key 解码后必须恰好 32 字节。
- PostgreSQL 至少拆分
trpc_migration、trpc_runtime、trpc_worker、trpc_metrics四个账号。 - Gateway/Admin 不得获得 owner、superuser 或 worker 身份;metrics 不得复用 worker DSN。
- 生产必须禁用 development token、关闭内容采集、关闭飞书陈旧 binding cache,并配置真实 OIDC。
- 应用镜像必须写成
repository@sha256:<64-hex>;tag 不能作为发布身份。
应用设置统一使用 TRPC_SERVICE_ 前缀。配置由进程环境读取;*_REF 再解析 Secret:
env://NAME:读取进程环境变量NAME。file:///absolute/path:读取绝对路径文件;租户 Secret 必须在TRPC_SERVICE_TENANT_SECRET_ROOT下。.env:只用于本地 Compose。- Kubernetes:非敏感项放 ConfigMap,敏感项放下述七类 Secret。
生产禁止 literal://。环境专用配置必须覆盖所有 example.*、samples.*、REPLACE_* 值。
cp .env.example .envPowerShell:
Copy-Item .env.example .env必须替换:
| 变量 | 说明 |
|---|---|
POSTGRES_PASSWORD |
Compose 初始化管理员,只用于建库/建角色 |
MIGRATION_DATABASE_PASSWORD |
trpc_migration 密码 |
RUNTIME_DATABASE_PASSWORD |
trpc_runtime 密码 |
WORKER_DATABASE_PASSWORD |
trpc_worker 密码 |
METRICS_DATABASE_PASSWORD |
trpc_metrics 密码 |
REDIS_PASSWORD |
Redis ACL 密码 |
MINIO_ROOT_PASSWORD |
本地 MinIO 密码 |
SESSION_HMAC_KEY |
至少 32 个随机字节 |
EMERGENCY_QUEUE_KEY |
恰好 32 个随机字节 |
DEVELOPMENT_TOKEN |
仅本地使用 |
MODEL_API_KEY |
真实模型提供方密钥;只挂载给 Agent Worker |
TRPC_SERVICE_MODEL_ENDPOINT_HOSTS |
JSON 数组,只列批准的模型 API 主机 |
TRPC_SERVICE_TENANT_SECRET_ENV_NAMES |
默认 [],只增加精确批准的名称 |
生成随机值:
openssl rand -base64 36 | tr -d '\r\n'
openssl rand -hex 32PowerShell:
$bytes = New-Object byte[] 36
[Security.Cryptography.RandomNumberGenerator]::Fill($bytes)
[Convert]::ToBase64String($bytes)
$key = New-Object byte[] 32
[Security.Cryptography.RandomNumberGenerator]::Fill($key)
[Convert]::ToHexString($key).ToLowerInvariant()不要随意更换 Emergency Queue key。轮换时先设置新
TRPC_SERVICE_EMERGENCY_QUEUE_KEY_VERSION,在
TRPC_SERVICE_EMERGENCY_QUEUE_PREVIOUS_KEY_REFS 暂时保留旧版本引用,排空后再删除。
docker compose --env-file .env config --quiet
docker compose --env-file .env up --build -d
docker compose --env-file .env psmigrate 必须先成功。失败时查看:
docker compose --env-file .env ps --all
docker compose --env-file .env logs --tail=200 migrate gateway worker默认地址:
| 服务 | 地址 |
|---|---|
| Gateway | http://127.0.0.1:8080 |
| Admin | http://127.0.0.1:8081 |
| PostgreSQL / Redis | 127.0.0.1:5432 / 127.0.0.1:6379 |
| MinIO API / Console | http://127.0.0.1:9000 / http://127.0.0.1:9001 |
| Prometheus / Jaeger | http://127.0.0.1:9090 / http://127.0.0.1:16686 |
curl -fsS http://127.0.0.1:8080/health/live
curl -fsS http://127.0.0.1:8080/health/ready
curl -fsS http://127.0.0.1:8081/health/ready
docker compose --env-file .env exec worker python -m trpc_service.probe --role worker停止并保留卷:
docker compose --env-file .env downdocker compose down --volumes 会永久删除本地 PostgreSQL、Redis、MinIO 和 Prometheus 数据;不要把它
当普通停止命令。
| 角色 | 职责 | 凭据 |
|---|---|---|
gateway |
外部 API、飞书加密回调 | runtime + Feishu Secret |
admin |
租户、binding、DLQ、重放与审计 | runtime + OIDC |
worker |
Agent turn、IM 媒体下载 | worker + IM Secret |
outbox-dispatcher |
PostgreSQL outbox 投递 | worker |
channel-dispatcher |
飞书 OpenAPI 发送 | worker + Feishu Secret |
post-turn-projector |
turn 后投影 | worker |
wecom-connector |
企业微信 WSS 收发 | worker + WeCom Secret |
session-recovery |
过期 lease 与 ready mailbox 恢复 | worker |
artifact-gc |
staged artifact 回收 | worker + S3 |
本地镜像:
docker build -t trpc-agent-service:dev .生产验收需要初始候选和升级候选两个不同 digest。推荐用仓库脚本统一 build/push、release context 和 candidate lock;Docker credential helper 负责登录:
$repository = "docker.io/<owner>/trpc-agent-service"
./runs/multitenant/run-current-candidate-session.ps1 -Repository $repository
.venv\Scripts\python.exe scripts\candidate_lock.py verify输出的 images.initial.reference 与 images.upgrade.reference 必须是完整
repository@sha256:...。publish 后源码发生任何变化都必须创建新候选;不能复用旧 lock。详见
镜像候选发布。
复制 deploy/kustomize/overlays/production 到私有部署仓库的环境目录,或在受审查分支维护环境 patch。
填写:
namespace: trpc-service
images:
- name: trpc-agent-service
newName: docker.io/<owner>/trpc-agent-service
digest: sha256:<CURRENT_INITIAL_DIGEST>保留 base、namespace、im-external-egress、全部 infrastructure-*、prometheus-adapter.yaml 与
ingress.yaml;保留 replicas、production config、WeCom HA、IM Secret mounts、deployment order 和
migration order patch。不要在这里写 registry token 或机器人 Secret。
默认渲染的正式拓扑是:
| 层 | 默认资源 | 网络暴露 |
|---|---|---|
| 入口 | trpc-gateway Ingress/Service |
仅 Gateway 公网 HTTPS;Admin 保持内网 |
| 权威数据 | pgvector/PostgreSQL StatefulSet + PVC | 仅 namespace 内 5432 |
| 通知/投影 | Redis StatefulSet + PVC | 仅 namespace 内 6379;不是权威 Session |
| 对象存储 | MinIO StatefulSet + PVC + bucket bootstrap Job | 仅 namespace 内 9000;Console 不暴露 |
| 遥测 | OTel Collector、Prometheus StatefulSet + PVC | 仅集群内 |
| 弹性 | backlog exporter、Prometheus Adapter、External Metrics APIService、HPA | 仅 Kubernetes API/集群内 |
这些镜像均在清单中固定为 registry/repository@sha256:<digest>。默认模板是单副本数据依赖,适合完整功能
验收和单集群部署;生产高可用需要把数据层替换为多可用区托管服务或有明确复制/备份策略的 operator,不能
把单副本 PVC 当成跨区灾备。
逐项填写或确认:
apiVersion: v1
kind: ConfigMap
metadata:
name: trpc-service-config
data:
TRPC_SERVICE_ENVIRONMENT: production
TRPC_SERVICE_ALLOW_DEVELOPMENT_TOKEN: "false"
TRPC_SERVICE_CAPTURE_CONTENT: "false"
TRPC_SERVICE_OIDC_ISSUER: https://<OIDC_HOST>/
TRPC_SERVICE_OIDC_AUDIENCE: <OIDC_AUDIENCE>
TRPC_SERVICE_S3_ENDPOINT: http://minio:9000
TRPC_SERVICE_S3_BUCKET: trpc-artifacts
TRPC_SERVICE_OTLP_ENDPOINT: http://otel-collector:4317
TRPC_SERVICE_MODEL_ENDPOINT_HOSTS: '["api.openai.com"]'
TRPC_SERVICE_TENANT_SECRET_ROOT: /run/secrets
TRPC_SERVICE_TENANT_SECRET_ENV_NAMES: "[]"
TRPC_SERVICE_FEISHU_ALLOW_STALE_BINDING_CACHE: "false"
TRPC_SERVICE_FEISHU_SEND_API_ROOT: https://open.feishu.cn
TRPC_SERVICE_ONLINE_TESTS_ENABLED: "false"
TRPC_SERVICE_SCHEDULER_VERSION: v2
TRPC_SERVICE_REDIS_STREAM: trpc:session-ready:v2
TRPC_SERVICE_REDIS_CONSUMER_GROUP: trpc-session-ready-v2
TRPC_SERVICE_WORKER_CONCURRENCY: "10"默认内置依赖时保留 minio 与 otel-collector 的集群内地址;只有使用
managed-services-patch.example.yaml 时才替换为托管 endpoint。无论哪种模式,都不要保留
samples.auth0.com、example.internal 或 REPLACE_*。模型主机列表是出口白名单,不是模型 Secret。
飞书正常运行必须保持官方 API root;只有独立在线验收 witness 才可在显式启用 online tests 时临时覆盖。
在 Secret 系统或仓库外创建:
TRPC_SERVICE_DATABASE_DSN=postgresql://trpc_runtime:<URL_ENCODED_PASSWORD>@<PG_HOST>:5432/trpc_service?sslmode=require
TRPC_SERVICE_REDIS_URL=redis://:<URL_ENCODED_PASSWORD>@<REDIS_HOST>:6379/0
TRPC_SERVICE_SESSION_HMAC_KEY=<AT_LEAST_32_RANDOM_BYTES>
TRPC_SERVICE_EMERGENCY_QUEUE_KEY=<EXACTLY_32_RANDOM_BYTES>
TRPC_SERVICE_S3_ACCESS_KEY=<S3_ACCESS_KEY>
TRPC_SERVICE_S3_SECRET_KEY=<S3_SECRET_KEY>
TRPC_SERVICE_OIDC_ISSUER=https://<OIDC_HOST>/
TRPC_SERVICE_OIDC_AUDIENCE=<OIDC_AUDIENCE>OIDC 可放 ConfigMap,但由 Secret 覆盖也受支持。不要在 DSN 中留下未 URL-encode 的 @、:、/。
TRPC_SERVICE_WORKER_DATABASE_DSN_REF=env://TRPC_SERVICE_WORKER_DATABASE_DSN
TRPC_SERVICE_WORKER_DATABASE_DSN=postgresql://trpc_worker:<URL_ENCODED_PASSWORD>@<PG_HOST>:5432/trpc_service?sslmode=require
TRPC_SERVICE_WORKER_DATABASE_PASSWORD_REF=env://TRPC_SERVICE_WORKER_DATABASE_PASSWORD
TRPC_SERVICE_WORKER_DATABASE_PASSWORD=<RAW_WORKER_PASSWORD>只有 Worker、dispatcher、projector、connector、recovery 与 artifact GC 可以挂载这份 Secret。
把真实模型 API key 写入仓库外文件 /secure/trpc-service/model_api_key,文件权限设为 0600,且不要添加
尾随空行。Kubernetes 将它作为 trpc-model-secrets/model_api_key 只挂载给 trpc-worker,容器内固定路径为:
file:///run/secrets/model_api_key
这个文件只提供凭据;模型提供方、模型 URL、模型 ID、推理强度、采样参数、预算和系统指令属于租户不可变
配置,必须按 11.3 节通过 Admin API 创建并激活。仅设置 TRPC_SERVICE_MODEL_ENDPOINT_HOSTS 不会启用
模型调用。Kubernetes subPath 不会热更新 Secret;轮换 model_api_key 后必须滚动重启
trpc-worker,确认新 Pod Ready 后再撤销旧 key。
TRPC_SERVICE_DATABASE_DSN=postgresql://trpc_migration:<URL_ENCODED_PASSWORD>@<PG_HOST>:5432/trpc_service?sslmode=requiretrpc_migration 是 schema owner,只进入 migration Job,不进入任何长期 Pod。
TRPC_SERVICE_METRICS_DATABASE_DSN=postgresql://trpc_metrics:<URL_ENCODED_PASSWORD>@<PG_HOST>:5432/trpc_service?sslmode=requiretrpc_metrics 必须是 NOSUPERUSER NOBYPASSRLS,只允许执行
public.count_session_ready_backlog()。
创建四个无尾随空行的文件,权限 0600:
/secure/trpc-service/im/feishu_app_secret
/secure/trpc-service/im/feishu_verification_token
/secure/trpc-service/im/feishu_encrypt_key
/secure/trpc-service/im/wecom_bot_secret
飞书 App ID 和企业微信 Bot ID 不是 Secret,放在 PostgreSQL channel binding 的 account_id;四个 Secret
文件挂载到 /run/secrets/im。正式 binding 使用:
file:///run/secrets/im/feishu_app_secret
file:///run/secrets/im/feishu_verification_token
file:///run/secrets/im/feishu_encrypt_key
file:///run/secrets/im/wecom_bot_secret
默认 full-stack overlay 还需要一份只给 PostgreSQL、Redis、MinIO 与 bootstrap Job 使用的 Secret:
postgres_superuser_password=<RANDOM_POSTGRES_SUPERUSER_PASSWORD>
runtime_database_password=<SAME_RAW_PASSWORD_AS_service.env_RUNTIME_DSN>
migration_database_password=<SAME_RAW_PASSWORD_AS_migration.env_DSN>
worker_database_password=<SAME_RAW_PASSWORD_AS_worker.env_DSN>
metrics_database_password=<SAME_RAW_PASSWORD_AS_metrics.env_DSN>
redis_password=<SAME_RAW_PASSWORD_AS_service.env_REDIS_URL>
minio_root_user=<RANDOM_MINIO_ROOT_USER>
minio_root_password=<RANDOM_MINIO_ROOT_PASSWORD>
minio_application_user=<RANDOM_NON_ROOT_MINIO_APPLICATION_USER>
minio_application_password=<RANDOM_NON_ROOT_MINIO_APPLICATION_PASSWORD>这里相同角色的值必须逐字一致;DSN 中仍使用 URL-encoded 版本。内置 MinIO bootstrap 会创建
trpc-artifacts bucket、受限 application user 和只覆盖该 bucket 的读写 policy。service.env 的
TRPC_SERVICE_S3_ACCESS_KEY/TRPC_SERVICE_S3_SECRET_KEY 必须分别等于
minio_application_user/minio_application_password;MinIO root 凭据只挂载给 MinIO 与 bootstrap,
应用 Pod 不得使用或挂载 root 身份。
若使用托管 PostgreSQL/Redis/S3/OTel/Prometheus,创建一个环境 overlay 引用 production,并把
managed-services-patch.example.yaml 加入 patches。该 patch 会删除内置 StatefulSet、PVC 模板对应
工作负载、Adapter/APIService 与 PostgreSQL 等待器;随后必须在 Secret/ConfigMap 中提供托管地址,并在
启用 Worker HPA 前安装能提供 trpc_session_ready_backlog 的 External Metrics provider。子 overlay 还
必须按托管 endpoint 的实际 CIDR/FQDN/端口补充 egress 与 metrics scrape/adapter policy;默认规则只允许
私网 CIDR 的 5432/6379/9000/4317/4318/443,不能假定公网托管服务或任意 namespace 自动可达。
先创建 namespace:
kubectl apply -f deploy/kustomize/overlays/production/namespace.yaml创建五份 env Secret:
kubectl -n trpc-service create secret generic trpc-service-secrets \
--from-env-file=/secure/trpc-service/service.env \
--dry-run=client -o yaml | kubectl apply --server-side -f -
kubectl -n trpc-service create secret generic trpc-worker-secrets \
--from-env-file=/secure/trpc-service/worker.env \
--dry-run=client -o yaml | kubectl apply --server-side -f -
kubectl -n trpc-service create secret generic trpc-migration-secrets \
--from-env-file=/secure/trpc-service/migration.env \
--dry-run=client -o yaml | kubectl apply --server-side -f -
kubectl -n trpc-service create secret generic trpc-metrics-secrets \
--from-env-file=/secure/trpc-service/metrics.env \
--dry-run=client -o yaml | kubectl apply --server-side -f -
kubectl -n trpc-service create secret generic trpc-infrastructure-secrets \
--from-env-file=/secure/trpc-service/infrastructure.env \
--dry-run=client -o yaml | kubectl apply --server-side -f -创建只给 Agent Worker 使用的模型文件 Secret:
kubectl -n trpc-service create secret generic trpc-model-secrets \
--from-file=model_api_key=/secure/trpc-service/model_api_key \
--dry-run=client -o yaml | kubectl apply --server-side -f -创建 IM 文件 Secret:
kubectl -n trpc-service create secret generic trpc-im-secrets \
--from-file=feishu_app_secret=/secure/trpc-service/im/feishu_app_secret \
--from-file=feishu_verification_token=/secure/trpc-service/im/feishu_verification_token \
--from-file=feishu_encrypt_key=/secure/trpc-service/im/feishu_encrypt_key \
--from-file=wecom_bot_secret=/secure/trpc-service/im/wecom_bot_secret \
--dry-run=client -o yaml | kubectl apply --server-side -f -生产更推荐 ExternalSecret/Vault/KMS;无论工具为何,Secret 名称和 key 必须完全一致。
ACK 节点使用透明 Docker Hub 镜像加速(例如轩辕)时,Kubernetes 清单和证据仍保留规范引用:
docker.io/<owner>/trpc-agent-service@sha256:<digest>
deploy/runtime-gate.yaml 保持:
kubernetes:
pull_registry: docker.io镜像加速在 ACK 节点池/containerd 侧配置,不把清单仓库改成镜像站域名。production overlay 的默认
应用与基础设施镜像均使用 docker.io/...@sha256;Prometheus Adapter 使用已同步到 Docker Hub 的固定
support digest。这样节点通过轩辕加速拉取,candidate lock、Pod imageID 和证据仍绑定 Docker Hub
原始 digest。创建或扩容节点池后,先在新节点用每个不同 digest 做小 Pod 拉取并核对 imageID,避免
只在旧节点有缓存。
私有仓库需创建 kubernetes.io/dockerconfigjson Secret,并把
image-pull-secret-patch.example.yaml 复制为环境 patch 后加入 kustomization.yaml。不要把解码后的凭据
写进报告。
mkdir -p /tmp/trpc-render
kubectl kustomize deploy/kustomize/overlays/production \
>/tmp/trpc-render/production.yaml
! grep -E 'REPLACE_|example\.internal|samples\.auth0\.com' \
/tmp/trpc-render/production.yaml
kubectl apply --dry-run=server -f /tmp/trpc-render/production.yaml确认渲染结果包含:
- 所有应用镜像均为同一个
repository@sha256。 - Ingress、PostgreSQL、Redis、MinIO、Prometheus、OTel Collector、Prometheus Adapter 与 APIService。
trpc-im-secrets只挂载到 Gateway、Worker、Channel Dispatcher、WeCom Connector。trpc-model-secrets只以/run/secrets/model_api_key挂载到 Agent Worker。- Gateway/Worker HPA、PDB、NetworkPolicy、backlog exporter 与 PVC 均存在。
- production namespace、真实 OIDC/S3/OTLP 值,无 placeholder。
production overlay 已把旧 migration PreSync 改成可重建的 Sync hook:内置
PostgreSQL/Redis/MinIO 及其 Service 使用 Argo CD sync wave -2,schema migration 与 MinIO bootstrap
使用带 BeforeHookCreation,HookSucceeded 清理策略的 wave -1 Sync hook,应用使用默认 wave 0。
migration 另有最多 300 秒的 pg_isready init wait;这样首次部署不会在 PostgreSQL 创建前抢跑,后续候选
改变 Job Pod template 时也不会尝试原地修改已完成的不可变 Job。
使用裸 kubectl 首次部署时仍应显式分阶段并等待 StatefulSet:
yq eval 'select(.kind != "Deployment" and .kind != "HorizontalPodAutoscaler" and .kind != "Job" and .kind != "Ingress")' \
/tmp/trpc-render/production.yaml >/tmp/trpc-render/prerequisites.yaml
yq eval 'select(.kind == "Job")' \
/tmp/trpc-render/production.yaml >/tmp/trpc-render/bootstrap.yaml
yq eval 'select(.kind == "Deployment" or .kind == "HorizontalPodAutoscaler" or .kind == "Ingress")' \
/tmp/trpc-render/production.yaml >/tmp/trpc-render/workloads.yaml
kubectl apply --server-side -f /tmp/trpc-render/prerequisites.yaml
kubectl -n trpc-service rollout status statefulset/postgres --timeout=10m
kubectl -n trpc-service rollout status statefulset/redis --timeout=10m
kubectl -n trpc-service rollout status statefulset/minio --timeout=10m
kubectl -n trpc-service delete job trpc-schema-migration minio-bootstrap --ignore-not-found
kubectl apply --server-side -f /tmp/trpc-render/bootstrap.yaml
kubectl -n trpc-service wait --for=condition=complete \
job/trpc-schema-migration --timeout=1800s
kubectl -n trpc-service wait --for=condition=complete \
job/minio-bootstrap --timeout=10m
kubectl -n trpc-service logs job/trpc-schema-migration
kubectl -n trpc-service logs job/minio-bootstrap
kubectl apply --server-side -f /tmp/trpc-render/workloads.yaml
kubectl apply --server-side -f /tmp/trpc-render/production.yaml迁移失败时不要启动新工作负载。保存日志,修复数据库权限、扩展或 schema 问题;不要手工修改
alembic_version,也不要用 runtime/worker 账号迁移。
kubectl -n trpc-service get pods -o wide
kubectl -n trpc-service get deploy,job,svc,endpointslice
kubectl -n trpc-service rollout status deploy/trpc-gateway --timeout=10m
kubectl -n trpc-service rollout status deploy/trpc-worker --timeout=10m
kubectl -n trpc-service rollout status deploy/trpc-wecom-connector --timeout=10m
kubectl -n trpc-service get hpa
kubectl get --raw \
'/apis/external.metrics.k8s.io/v1beta1/namespaces/trpc-service/trpc_session_ready_backlog'
kubectl -n trpc-service top pods必须确认:Pod Ready、restart 为 0 或有解释;Pod imageID 等于候选 digest;Gateway EndpointSlice 无
unready/terminating endpoint;HPA ScalingActive=True;external backlog metric 可读;WeCom 两副本位于
不同节点。
Pod 长时间 Pending 时检查 node label、affinity、taint/toleration、配额和可用区。性能验收常用
trpc-role=workload、trpc-role=load-driver 等标签;它们是验收调度约束,不应无审查写进普通生产池。
Gateway Service 为 trpc-gateway:8080,Admin 为 trpc-admin:8081。默认清单已包含
deploy/kustomize/overlays/production/ingress.yaml;部署前必须把其中的 trpc.example.com、
ingressClassName 与 trpc-gateway-tls 改成真实值。其等价结构如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: trpc-gateway
namespace: trpc-service
spec:
ingressClassName: nginx
tls:
- hosts: [agent.example.com]
secretName: trpc-gateway-tls
rules:
- host: agent.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: trpc-gateway
port:
number: 8080Admin 建议使用独立内网域名、VPN 或零信任访问。不要暴露 PostgreSQL、Redis、MinIO Console、debug 或 metrics 管理端口。
飞书回调必须公网 HTTPS 可达,证书链完整;企业微信只需要 connector 出站访问
wss://openws.work.weixin.qq.com:443。production overlay 有两条独立的角色级 HTTPS fallback:IM policy
只选择 Channel Dispatcher/WeCom Connector;OIDC/model/tool policy 只选择 Gateway/Admin/Worker。标准
NetworkPolicy 不能表达 FQDN,因此默认目标为 0.0.0.0/0:443;支持 FQDN policy 的 CNI 必须分别替换为
审核后的飞书/企业微信、OIDC、模型和工具域名,不能扩展到其他 Pod 或其他端口。
所有租户和 channel binding 存 PostgreSQL,通过 Admin API 管理;不要再为每个租户复制一份进程 .env。
先取得 platform admin OIDC token:
export ADMIN_URL=https://admin.internal.example.com
export TOKEN='<OIDC_BEARER_TOKEN>'
curl -i -X POST "$ADMIN_URL/v1/tenants" \
-H "Authorization: Bearer $TOKEN" \
-H 'Idempotency-Key: create-tenant-example-001' \
-H 'Content-Type: application/json' \
--data '{"tenant_id":"tenant-example","display_name":"Example Tenant"}'保存响应 ETag。后续写操作每次先 GET 当前 tenant,使用最新 ETag 作为 If-Match,并使用新的
Idempotency-Key。
复制并编辑 租户配置模板:
模型配置字段都属于当前租户 revision,而不是进程级硬编码:
| 字段 | 填写方式 | 运行时行为 |
|---|---|---|
provider |
openai、anthropic 或 litellm |
选择对应 tRPC-Agent 模型适配器 |
base_url |
完整 HTTPS API 根地址,例如 https://api.openai.com/v1 |
Worker 将其直接交给适配器;主机还必须列入 TRPC_SERVICE_MODEL_ENDPOINT_HOSTS |
model |
账户实际可用的精确模型 ID;LiteLLM 使用 provider/model |
每个租户 revision 可独立选择,不需要重建镜像 |
api_key_ref.uri |
默认 file:///run/secrets/model_api_key |
Worker 在运行时解析 Secret,数据库不保存明文 |
timeout_seconds |
0 < value <= 600 |
转换为 SDK 的单次模型 HTTP 请求超时,不再只是描述字段 |
reasoning_effort |
OpenAI 可填 none、minimal、low、medium、high、xhigh、max |
自动使用 OpenAI Responses API,并原样传递 reasoning.effort;具体取值仍须由目标模型支持 |
thinking_budget_tokens |
Anthropic 或支持 SDK thinking 参数的 OpenAI 兼容端填 -1(自动)、0(关闭)或至少 1024 |
通过 SDK 内置 planner 设置 token 思考预算;正数必须小于 budget.max_tokens_per_turn |
temperature |
null 或 0..2 |
非 null 时传给模型;推理模型不支持时保持 null |
top_p |
null 或 0..1 |
非 null 时传给模型;通常不要和 temperature 同时调节 |
stop_sequences |
最多 8 个、每个 1–256 字符 | 非空时作为停止序列传入模型 |
fallback_model |
可选的同 provider 备用模型 ID | 主模型在输出任何可用内容前失败时才切换;沿用同一 URL、密钥和生成参数 |
reasoning_effort 与 thinking_budget_tokens 是两套不同供应商协议,配置模型会拒绝同时设置,避免参数被
静默忽略。模板默认展示 OpenAI Responses API 用法:保留 reasoning_effort,让
thinking_budget_tokens 为 null。Anthropic 示例应反过来设置:
{
"provider": "anthropic",
"base_url": "https://api.anthropic.com",
"model": "REPLACE_WITH_CLAUDE_MODEL_ID",
"api_key_ref": {"uri": "file:///run/secrets/model_api_key"},
"timeout_seconds": 60,
"reasoning_effort": null,
"thinking_budget_tokens": 2048,
"temperature": null,
"top_p": null,
"stop_sequences": []
}若使用自建 OpenAI 兼容网关,先确认它实现 /responses 再填写 reasoning_effort;只实现
/chat/completions 的网关应将该字段设为 null。修改 base_url 后还必须同步更新 production
ConfigMap 的 TRPC_SERVICE_MODEL_ENDPOINT_HOSTS,否则 Worker 会按 SSRF 防护策略拒绝加载 revision。
storage 默认值对应仓库内置的 PostgreSQL/S3/pgvector 正式实现。
创建 revision;服务端会注入 tenant_id、app_id 和递增的 version:
export ETAG='"1"' # 替换为 GET tenant 返回的当前值
curl -i -X POST \
"$ADMIN_URL/v1/tenants/tenant-example/config-revisions" \
-H "Authorization: Bearer $TOKEN" \
-H 'Idempotency-Key: config-tenant-example-001' \
-H "If-Match: $ETAG" \
-H 'Content-Type: application/json' \
--data @deploy/tenant-config.example.json保存响应中的 version,再次 GET tenant 取得新的 ETag,然后 100% 激活:
export CONFIG_VERSION='<VERSION_FROM_CREATE_RESPONSE>'
export ETAG='"2"' # 替换为最新值
curl -i -X POST \
"$ADMIN_URL/v1/tenants/tenant-example/config-revisions/$CONFIG_VERSION:activate" \
-H "Authorization: Bearer $TOKEN" \
-H 'Idempotency-Key: activate-tenant-example-001' \
-H "If-Match: $ETAG" \
-H 'Content-Type: application/json' \
--data '{"app_id":"support","percentage":100}'不要把 scripts/performance_fixture.py、migration/fault bootstrap 中的 provider=offline 当成正式配置;它们
刻意不调用外部模型。真实验收必须从飞书和企业微信分别发送不可预置的问题,确认回复不等于
offline deterministic response,并在 Worker telemetry 中看到对应模型请求成功或明确失败。
在飞书开放平台创建企业自建应用,启用机器人、加密事件回调、im.message.receive_v1、消息发送和媒体
权限。App ID 放 account_id,Secret 只在 trpc-im-secrets:
export ETAG='"1"' # 替换为 GET tenant 返回的当前值
curl -i -X PUT \
"$ADMIN_URL/v1/tenants/tenant-example/channel-bindings/feishu-primary" \
-H "Authorization: Bearer $TOKEN" \
-H 'Idempotency-Key: bind-feishu-example-001' \
-H "If-Match: $ETAG" \
-H 'Content-Type: application/json' \
--data '{
"app_id":"support",
"channel":"feishu",
"account_id":"cli_REPLACE",
"secret_refs":{
"app_secret":{"uri":"file:///run/secrets/im/feishu_app_secret"},
"verification_token":{"uri":"file:///run/secrets/im/feishu_verification_token"},
"encrypt_key":{"uri":"file:///run/secrets/im/feishu_encrypt_key"}
},
"capabilities":["text","proactive"],
"enabled":true
}'飞书后台回调地址:
https://agent.example.com/v1/channels/feishu/feishu-primary/callback
完成 URL challenge、应用版本发布和可用范围审批,再用测试成员发送唯一 marker;必须只产生一条 Inbox 和一条最终回复。
企业微信使用“智能机器人 → API 模式 → 长连接”,不是群机器人 webhook,也不是普通自建应用
CorpID/AgentID。Bot ID 放 account_id:
export ETAG='"2"' # 替换为上一步后的当前值
curl -i -X PUT \
"$ADMIN_URL/v1/tenants/tenant-example/channel-bindings/wecom-primary" \
-H "Authorization: Bearer $TOKEN" \
-H 'Idempotency-Key: bind-wecom-example-001' \
-H "If-Match: $ETAG" \
-H 'Content-Type: application/json' \
--data '{
"app_id":"support",
"channel":"wecom_ai_bot",
"account_id":"REPLACE_WITH_BOT_ID",
"secret_refs":{
"bot_secret":{"uri":"file:///run/secrets/im/wecom_bot_secret"}
},
"capabilities":["text","proactive"],
"enabled":true
}'企业微信不需要入站公网 callback。确认两个 connector 副本中只有一个 binding owner,另一个可接管;发送 唯一 marker,必须只产生一条回复。企业微信协议没有断线期间的历史补投或 resume cursor:全部 WSS 同时断开期间未送达服务的消息无法由应用恢复,必须记录 provider delivery gap,不能把恢复后的新消息 冒充补投。
正式配置分层如下:
| 内容 | 存储位置 | 是否含明文 Secret |
|---|---|---|
| 集群级非敏感参数 | ConfigMap/Kustomize patch | 否 |
| 数据库、Redis、S3、OIDC 私密值 | Kubernetes Secret/外部 Secret 管理器 | 是 |
| 模型 API key | trpc-model-secrets,只挂载 Agent Worker |
是 |
| 飞书/企业微信私密值 | trpc-im-secrets |
是 |
| tenant、app、binding、account ID、能力、SecretRef | PostgreSQL 控制面表 | 否 |
| release ID、source、image digest | candidate lock 与审计报告 | 否;nonce 原值不公开 |
因此新增租户通常不创建新 Pod 或复制 .env:创建 tenant、配置 agent revision、创建 binding,并让
binding 引用已批准的 Secret key。需要每租户独立凭据时,使用独立 Secret key/CSI 挂载路径并更新
SecretRef;不要把所有租户合并成一个 JSON 明文表。
TenantConfig.storage.profile_id 是 immutable config revision 的一部分,Worker 每次按
(tenant_id, profile_id, 完整 StorageSelection) 路由;不同租户不需要 sticky session。内置正式镜像只
实现下列组合:
| 数据域 | 内置正式后端 | 说明 |
|---|---|---|
| Session / Memory / Summary / Audit | PostgreSQL | 权威状态、事务和 RLS/fencing |
| Artifact metadata / object | PostgreSQL / S3-compatible | 默认对象端为同集群 MinIO |
| Knowledge | PostgreSQL + pgvector | 内置维度固定 1536 |
| Redis | 仅 SessionReady 通知和可重建投影 | 不能声明为权威 Session/Memory |
| InMemory | 仅单进程开发/测试 | 不能进入内置 production fallback |
| external memory/vector | RegisteredTenantServiceBundle 扩展口 |
必须由部署代码预构造并显式注册 |
这意味着宽泛 StorageSelection 可以描述迁移源/目标和外部适配器,但未注册的组合不会静默退回
PostgreSQL:Worker 会失败关闭。TRPC_SERVICE_STORAGE_PROFILE_REGISTRY_FILE 是可选、严格且无 Secret
的 JSON,只能把 tenant/profile 绑定到当前进程已经配置好的内置 bundle;它不能携带 DSN,也不能把同一
物理 pool 冒充成独立后端:
{
"schema_version": 1,
"profiles": [
{
"tenant_id": "tenant-example",
"profile_id": "default",
"bundle": "default_postgresql_s3_pgvector"
}
]
}文件必须是绝对路径、非符号链接、最大 64 KiB。标准内置部署不设置它,因为 default fallback 已覆盖上述
组合。若高监管租户需要独立 PostgreSQL/S3/external-memory 资源,部署扩展必须用各自 SecretRef 构造不同
TenantDataServices bundle,再按 exact tenant/profile 注册;仅修改数据库里的 backend 字符串不算完成。
binding 的 capabilities 是配置声明/要求,当前不会单独执行发送授权,也不会扩大适配器已经实现的能力。
发送权限应由租户策略与业务入口在创建 Outbox 前校验。当前两通道都能接收入站媒体;出站
则是严格 text-only:
| 通道 | text/proactive | stream | card | outbound media | recall | 自动长度拆分 |
|---|---|---|---|---|---|---|
| 飞书 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 |
| 企业微信 AI Bot | 支持(markdown body) | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 |
recall() 对两通道都返回非重试的 FAILED/unsupported_capability,不会请求供应商。当前 delivery attempt
没有持久化分片游标;长文本若在适配器内部分片,部分成功后整条重试会制造重复消息,因此代码不做隐式
拆分,也不声称未知的供应商长度上限。企业微信 markdown 仍是文本,不作为 card。
更完整的通道权限、媒体、群聊、幂等和故障语义见 IM 通道文档。
| 变量 | 建议 | 约束/用途 |
|---|---|---|
TRPC_SERVICE_ENVIRONMENT |
production |
启用生产不变量 |
TRPC_SERVICE_ALLOW_DEVELOPMENT_TOKEN |
false |
生产必须关闭 |
TRPC_SERVICE_CAPTURE_CONTENT |
false |
防止正文进入 telemetry |
TRPC_SERVICE_OIDC_ISSUER |
真实 HTTPS issuer | 生产必填 |
TRPC_SERVICE_OIDC_AUDIENCE |
服务 audience | 生产必填 |
TRPC_SERVICE_DATABASE_POOL_MIN_SIZE |
按角色设置 | 不得大于 max |
TRPC_SERVICE_DATABASE_POOL_MAX_SIZE |
按 PG 预算设置 | 所有 Pod 总和不能超过连接预算 |
TRPC_SERVICE_WORKER_CONCURRENCY |
默认 10 |
HPA 20 副本时上限 200 turn |
TRPC_SERVICE_SCHEDULER_VERSION |
v2 |
与 stream/group 成套 |
TRPC_SERVICE_REDIS_STREAM |
trpc:session-ready:v2 |
不可在普通滚动中切版本 |
TRPC_SERVICE_REDIS_CONSUMER_GROUP |
trpc-session-ready-v2 |
不可在普通滚动中切版本 |
TRPC_SERVICE_REDIS_RECLAIM_AFTER_MS |
60000 |
与 lease/恢复策略一致 |
TRPC_SERVICE_TENANT_SECRET_ROOT |
/run/secrets |
file SecretRef 根目录 |
TRPC_SERVICE_TENANT_SECRET_ENV_NAMES |
[] |
使用文件 Secret 时保持 fail-closed |
TRPC_SERVICE_STORAGE_PROFILE_REGISTRY_FILE |
默认不设置 | 可选的绝对路径、无 Secret、内置 bundle 精确绑定文件 |
TRPC_SERVICE_MODEL_ENDPOINT_HOSTS |
审批后的 JSON 数组 | 阻止租户任意模型出口 |
TRPC_SERVICE_FEISHU_ALLOW_STALE_BINDING_CACHE |
false |
生产不得放宽 |
TRPC_SERVICE_FEISHU_SEND_API_ROOT |
https://open.feishu.cn |
正常运行固定官方地址 |
TRPC_SERVICE_ONLINE_TESTS_ENABLED |
false |
仅在线门禁显式开启 |
TRPC_SERVICE_S3_ENDPOINT |
私有 S3/OSS | 不包含 Secret |
TRPC_SERVICE_S3_BUCKET |
私有 bucket | 禁止匿名 |
TRPC_SERVICE_OTLP_ENDPOINT |
集群内 Collector | 不直发未知公网 |
TRPC_SERVICE_MEDIA_DOWNLOAD_MAX_BYTES |
20971520 |
媒体上限 |
TRPC_SERVICE_MEDIA_DOWNLOAD_TIMEOUT_SECONDS |
30 |
1–300 秒 |
TRPC_SERVICE_RECOVERY_BATCH_SIZE |
25 |
recovery 单批数量 |
TRPC_SERVICE_ARTIFACT_STAGING_TTL_SECONDS |
86400 |
staged artifact 清理阈值 |
调度器 v1↔v2 不是普通滚动升级。必须停入站、排空旧 PostgreSQL outbox 和 Redis group、缩容相关角色
到 0,再切换 stream/group,并按 recovery → dispatcher → worker → ingress 恢复。完整判据见
调度器切换手册。禁止用 DEL、XTRIM 或直接改状态伪造排空。
复制 deploy/runtime-gate.example.yaml 为被 Git 忽略的 deploy/runtime-gate.yaml,填写:
- 明确 kubeconfig/context 和当前 candidate lock。
- Secret manifest 与可选 image pull Secret。
pull_registry: docker.io,ACK 节点侧走轩辕透明加速。- workload、load-driver、data/control 节点标签与 taint。
- digest-pinned PostgreSQL、Redis、MinIO、Prometheus、Adapter、load Job 镜像。
trpc_session_ready_backlog外部指标与 HPA driver 身份。
正式验收入口不包含个人 kubeconfig 或 context。通过参数或环境变量显式传入:
$env:TRPC_ACK_KUBECONFIG = "C:\secure\ack-admin.kubeconfig"
$env:TRPC_ACK_CONTEXT = "your-explicit-ack-context"
./runs/multitenant/run-current-final-acceptance.ps1 -StartStage 1 -EndStage 8性能 Job 必须在专用 trpc-role=load-driver 节点,不在独立 IM 探针主机、开发机端口转发或业务 Pod 中执行。性能、
Kubernetes runtime、迁移和故障注入必须串行使用同一候选,不能并发改 namespace、HPA、节点 drain 或
固定报告文件。详见测试与发布门禁。
完整 online_im 还要求每个真实通道证明入站、发送 ACK、幂等、媒体、重连/接管、长故障、真实限流和
ambiguous response。独立签名探针的安装与信任配置见
在线 IM 探针。没有真实证据时必须保持 production_gate=not_run。
- 备份 PostgreSQL并验证可恢复,记录
alembic_version。 - 备份 Redis AOF/RDB 与对象存储 bucket/versioning 状态。
- 记录当前
repository@sha256、ConfigMap hash、Secret 版本、release ID 与 scheduler 版本。 - 生成新候选并验证 candidate lock,不复用旧 tag。
- 先跑 expand-compatible 迁移,再滚动应用;观察期内保留旧字段、旧 key 和旧 transport。
同 scheduler/schema 兼容范围内,把环境 overlay digest 恢复为上一个已验证 digest,并对所有角色使用同一 候选。示例只展示 Gateway:
kubectl -n trpc-service set image deploy/trpc-gateway \
gateway=docker.io/<owner>/trpc-agent-service@sha256:<previous-digest>
kubectl -n trpc-service rollout status deploy/trpc-gateway --timeout=10m正式操作应在 Kustomize/GitOps 中回滚,不长期保留命令式漂移。数据库迁移不做盲目 downgrade;按 迁移与回滚的 verify/rollback 判据执行。
- 先把新 Secret 版本写入 Secret 管理器,确认文件 key/路径不变或创建新路径。
- binding 使用新 SecretRef 时携带最新
If-Match与唯一Idempotency-Key。 - 先滚动/重连一小部分实例,验证供应商 ACK,再完成其余实例。
- Emergency Queue key 按版本双读窗口轮换;不能直接覆盖后立即删除旧 key。
- Ed25519 IM probe trust 轮换后旧在线报告失效,必须重跑真实门禁。
- 内置 PostgreSQL 的角色脚本只在空 PVC 初始化时执行。已有 PVC 轮换密码时,先由受控管理会话执行
ALTER ROLE ... PASSWORD ...,再原子更新对应 Secret/DSN 并滚动依赖 Pod;只改 Secret 不会修改数据库 中的角色密码。 - MinIO application password 会在重跑 bootstrap Job 时收敛;bucket policy 内容变化时必须同步升级
trpc-artifacts-rw-v1的版本化名称并重新附加,不能在原名称下静默修改后期待 Job 覆盖已有 policy。
本地离线门禁:
uv run ruff format --check .
uv run ruff check .
uv run mypy trpc_service scripts
uv run pytest --cov=trpc_service --cov-branch
uv run python scripts/mock_production_gate.py
kubectl kustomize deploy/kustomize/overlays/production >/dev/null默认测试不调用外部模型或 IM 平台。真实 IM、性能、故障注入和部署门禁需要显式凭据/基础设施。
“功能完成”至少要求:静态/单元/契约通过;Compose 与 Kubernetes 运行态通过;零成本功能灾备通过; 当前候选在真实飞书和企业微信上证明唯一入站/唯一出站/供应商回执;镜像、源码、release context 与报告 一致。
“生产发布完成”还要求完整 online_im 8-case、最终 release manifest,以及按政策显式启用的
破坏性生产灾备。唯一允许的灾备豁免是 --allow-functional-dr:它只能授权功能灾备替代未运行的
破坏性 DR,并保留
production_gate=not_run 与 authorized_not_run_gates=[disaster_recovery];它不豁免 online_im、
任何 fail 或其他门禁。
| 现象 | 首查 |
|---|---|
| Compose 服务全部等待 | migration 日志、PG 扩展和数据库密码 |
another connector owns this binding |
是否重复 owner、租约/epoch、主备接管 |
| 同一 IM 消息回复两次 | provider message ID、Inbox 唯一键、旧 connector 是否仍在线 |
| 企业微信停机仍立即回复 | 是否只停一个 owner,另一个 connector 是否接管 |
| 企业微信全断线消息无回复 | 协议无历史补投/resume,记录 delivery gap |
| 飞书 challenge 失败 | TLS、Ingress 路径、binding ID、token/encrypt key、body limit |
Pod Pending |
node label、affinity、taint/toleration、配额 |
HPA ScalingActive=False |
Metrics Server、exporter、Adapter、metrics DSN 权限 |
ImagePullBackOff |
digest、pull Secret、ACK 新节点轩辕/containerd 配置 |
| 报告 identity mismatch | publish 后改了源码、复用了旧 lock/report |
| P95 偶发超门槛 | CPU throttle、DB pool wait、active queries、placement、transport errors、p99/max |