17 KiB
Kubernetes部署手册
1. 适用范围
本手册用于把数据采集终端—云端系统部署到预生产或生产Kubernetes集群。仓库提供Kustomize基线,不在集群内自建PostgreSQL、Redis、对象存储、OIDC、OpenTelemetry Collector或外部模型/语音服务;这些依赖应使用已备份、可监控且具备生产SLA的托管或平台服务。
清单只定义应用工作负载,不包含任何真实Secret。deploy/kubernetes/base/configmap.yaml中的.example.invalid、24位全零RTC App ID和replace-with-*是不可用占位值。生产服务的启动门禁会拒绝这些值,避免占位配置被误发布。
2. 目录与发布单元
| 目录 | 用途 | 是否可重复应用 |
|---|---|---|
deploy/kubernetes/base |
四个应用Deployment、Service、Ingress、PDB、HPA和NetworkPolicy | 是 |
deploy/kubernetes/overlays/staging |
预生产环境覆盖层,APP_ENV=stage |
是 |
deploy/kubernetes/overlays/production |
生产环境覆盖层,APP_ENV=prod |
是 |
deploy/kubernetes/overlays/production-csi |
生产环境覆盖层,并以Secrets Store CSI替代应用Kubernetes Secret卷 | 是 |
deploy/kubernetes/migration |
数据库向前迁移一次性Job | 每次发布前执行并等待完成 |
deploy/kubernetes/migration-csi |
从Secrets Store CSI文件读取数据库连接串的迁移Job | 每次发布前执行并等待完成 |
API、Callbacks和Worker共用一个后端镜像,通过容器命令分别启动/app/api、/app/callbacks和/app/worker。Web使用独立Nginx镜像。迁移镜像只包含固定版本的migrate程序和当前仓库migrations目录。
3. 集群前置条件
部署前应具备:
- Kubernetes 1.27或更高版本,并启用支持
autoscaling/v2的Metrics Server。 - Nginx Ingress Controller;基线假定控制器命名空间为
ingress-nginx。 - 证书控制器或人工创建的TLS Secret
voice-platform-tls。 - 监控系统;基线假定Prometheus位于
monitoring命名空间。 - 支持pgvector的PostgreSQL、启用认证的Redis、TLS对象存储和HTTPS OIDC。
- 火山RTC/豆包语音、火山方舟内容模型和1536维Embedding模型的真实账号与已开通资源。
- 推荐使用External Secrets Operator或云KMS Secrets Store CSI Driver。若平台采用不同的Ingress或监控命名空间,必须同步修改NetworkPolicy。
生产数据库连接必须启用TLS,例如sslmode=verify-full;对象存储必须启用TLS;OIDC Issuer和JWKS必须为HTTPS。数据库迁移账号可与运行账号分离,但迁移Job使用的账号必须具有执行当前迁移所需的DDL权限。
4. 构建和推送镜像
为同一次发布使用不可变版本号或Git提交摘要,不要复用latest:
$Version = "2026.08.23-<commit>"
$Registry = "registry.company.example/voice-platform"
docker build -f deploy/backend.Dockerfile -t "$Registry/backend:$Version" .
docker build -f deploy/web.Dockerfile -t "$Registry/web:$Version" .
docker build -f deploy/migrate.Dockerfile -t "$Registry/migrate:$Version" .
docker push "$Registry/backend:$Version"
docker push "$Registry/web:$Version"
docker push "$Registry/migrate:$Version"
在目标覆盖层的kustomization.yaml中把三个镜像名称和版本改成上述不可变地址。建议由流水线写入镜像摘要,并在发布记录中保存后端、Web和迁移镜像的对应关系。
5. 非敏感环境配置
不要直接修改base作为某个现场的长期配置。复制环境覆盖层或增加一个现场补丁,至少替换下列字段:
| 配置 | 说明 |
|---|---|
REDIS_ADDR |
Redis主机与端口,不含密码 |
AUTH_ISSUER_URL、AUTH_JWKS_URL |
HTTPS OIDC地址 |
AUTH_AUDIENCE |
Web/API共同使用的Audience |
OTEL_EXPORTER_OTLP_ENDPOINT |
OTLP gRPC地址 |
EXTERNAL_PROBE_INTERVAL |
OIDC、方舟和RTC外部探针周期,默认30秒 |
RTC_APP_ID |
真实24字符火山RTC App ID |
OBJECT_STORE_ENDPOINT |
应用访问对象存储的TLS端点 |
OBJECT_STORE_PUBLIC_ENDPOINT |
浏览器短期下载地址使用的公网TLS端点 |
OBJECT_STORE_EXPORT_BUCKET、OBJECT_STORE_REGION |
私有导出桶和区域 |
ARK_CONTENT_MODEL |
已开通的方舟内容模型Endpoint ID |
ARK_EMBEDDING_MODEL |
已开通且输出1536维向量的Endpoint ID |
CONTENT_SAFETY_PROVIDER、CONTENT_SAFETY_ENDPOINT |
managed_http和正式HTTPS分类端点 |
CONTENT_SAFETY_POLICY_REF、CONTENT_SAFETY_TIMEOUT |
已批准且不可变的策略版本和调用超时 |
WEB_OIDC_AUTHORITY、WEB_OIDC_CLIENT_ID |
浏览器可见的OIDC公开配置 |
Ingress host和TLS Secret |
正式域名与证书Secret |
APP_ENV=prod会启用严格生产门禁。不要通过改回stage绕过配置错误;应修正真实配置后再发布。
6. Secret清单
下列Secret必须在voice-platform命名空间预先存在。文件名就是Secret的key,Secret内容不得提交到Git或写入普通ConfigMap。
| Secret名称 | 必需key | 使用者 |
|---|---|---|
voice-platform-common-secrets |
database-url、redis-password |
API、Callbacks、Worker、迁移Job |
voice-platform-api-secrets |
rtc-app-key、cursor-signing-secret、share-token-signing-secret |
API |
voice-platform-callbacks-secrets |
provider-callback-secret、platform-health-callback-secret |
Callbacks |
voice-platform-worker-secrets |
volc-access-key-id、volc-secret-access-key、voice-chat-template.json |
Worker |
voice-platform-model-storage-secrets |
object-store-access-key、object-store-secret-key、ark-api-key、content-safety-api-key |
API、Worker;内容安全Key仅由Worker引用 |
voice-platform-device-secrets |
每台设备一个key,例如terminal-001 |
API |
voice-platform-tls |
tls.crt、tls.key |
Ingress |
游标签名密钥和分享签名密钥必须各不少于32字节且互不相同。供应商回调密钥不少于32字节。数据库连接串和Redis密码由应用通过*_FILE读取;应用错误日志不会输出Secret内容。
每台量产设备在数据库中的credential_ref应写为device-secret://terminal-001,对应voice-platform-device-secrets中的terminal-001文件。名称只允许安全的单层文件名。Kubernetes Secret或CSI卷原子更新后,API会在下一次设备验签时读取新值,无需重启。
voice-chat-template.json可从deploy/volcengine/voice-chat-template.example.json复制结构。生产文件必须使用voice-chat-template-bundle-v1并同时包含s2s_pure、s2s_hybrid和cascade三个模板;示例中的TemplateBodyMustBeReplaced表示整个Config对象都应按现场已开通的官方语音能力替换,不是一个可直接提交给供应商的字段。平台按通话冻结模式选中模板后覆盖AppId、RoomId、TaskId、设备用户、Agent用户和授权背景,模板中不要固定这些请求级字段。若现场模型或音色字段需要由已发布Agent组合动态提供,应在官方字段对应位置填写{{MODEL_RESOURCE_REF}}或{{VOICE_RESOURCE_REF}};还可用{{AGENT_BUNDLE_VERSION}}、{{PERSONA_VERSION}}、{{VOICE_VERSION}}、{{MODEL_VERSION}}和{{ROUTING_VERSION}}写入供应商允许的追踪字段。未使用的占位符无需添加。
如使用火山临时凭据,可在Worker Secret增加volc-session-token,并通过现场补丁增加VOLC_SESSION_TOKEN_FILE=/var/run/secrets/voice-platform/worker/volc-session-token。如启用告警Webhook,同样应以现场补丁配置HTTPS ALERT_WEBHOOK_URL,并通过Secret文件注入ALERT_WEBHOOK_SECRET_FILE。
首次创建命名空间后再由密钥平台同步Secret:
kubectl apply -f deploy/kubernetes/base/namespace.yaml
kubectl -n voice-platform get secret
不建议在命令行直接传入密钥明文。短期人工联调只能使用kubectl create secret generic --from-file=...从受控临时文件创建,并在完成后安全清理临时文件和终端历史。
6.1 Secrets Store CSI模式
生产环境推荐使用deploy/kubernetes/overlays/production-csi和deploy/kubernetes/migration-csi。这两个覆盖层保持原有容器内文件路径不变,只把卷来源从Kubernetes Secret替换为secrets-store.csi.k8s.io内联卷。
集群平台需先安装Secrets Store CSI Driver和对应云密钥提供器,并启用工作负载身份。SecretProviderClass必须创建在voice-platform命名空间;仓库提供参数化示例,但provider和parameters必须严格按现场云厂商或Vault提供器文档填写,不能直接应用示例占位值。
必须创建以下六个SecretProviderClass:
| SecretProviderClass | 必须挂载的文件名 |
|---|---|
voice-platform-common |
database-url、redis-password |
voice-platform-api |
rtc-app-key、cursor-signing-secret、share-token-signing-secret |
voice-platform-callbacks |
provider-callback-secret、platform-health-callback-secret |
voice-platform-worker |
volc-access-key-id、volc-secret-access-key、voice-chat-template.json |
voice-platform-model-storage |
object-store-access-key、object-store-secret-key、ark-api-key、content-safety-api-key |
voice-platform-devices |
每台设备一个文件,例如terminal-001 |
提供器对象应通过objectAlias或等价字段映射为上述准确文件名。Deployment挂载整个目录,不使用subPath,以便CSI原子轮换能够更新容器看到的符号链接。ServiceAccount已按API、Callbacks、Worker和Web拆分;现场应只给前三个需要密钥的ServiceAccount附加相应工作负载身份,并按最小权限授予密钥读取能力。
自动轮换必须在CSI Driver和所选提供器均支持时启用。轮换后:
voice-platform-devices中的逐设备密钥由API每次请求重新读取,原子更新后下一次验签即可使用新值;轮换协议仍应保留受控双密钥过渡或设备同步窗口。- 数据库、Redis、RTC、供应商、对象存储、方舟和签名密钥在进程启动时读取。CSI可以更新文件,但不会主动重启Pod;这些密钥轮换后必须由部署流水线执行受控滚动重启,并验证新Pod就绪后再终止旧Pod。
- 不应依赖
secretObjects同步为Kubernetes Secret。CSI迁移Job直接读取voice-platform-common/database-url文件,避免数据库连接串落入额外Secret副本。
检查CSI对象和已挂载版本:
kubectl get secretproviderclass -n voice-platform
kubectl get secretproviderclasspodstatus -n voice-platform
kubectl describe pod -n voice-platform -l app.kubernetes.io/name=voice-platform-api
不要通过kubectl exec ... cat打印Secret内容。验收只检查文件存在、权限、版本编号、Pod就绪和实际认证结果。
目标环境完成动态读取和滚动重启两类轮换后,按云KMS/HSM密钥轮换一致性证据导出不含密钥正文的版本、探针和审计引用,并使用cmd/kms-rotation-conformance生成候选报告。仅检查SecretProviderClass存在或本地文件更新不能满足KMS_ROTATION发布门禁。
7. 发布前静态检查
静态渲染不连接集群,适合本地和CI的轻量门禁:
kubectl kustomize deploy/kubernetes/overlays/production > $null
kubectl kustomize deploy/kubernetes/migration > $null
kubectl kustomize deploy/kubernetes/overlays/production-csi > $null
kubectl kustomize deploy/kubernetes/migration-csi > $null
连接目标集群后执行服务端预检和差异检查:
kubectl apply --server-side --dry-run=server -k deploy/kubernetes/overlays/production
kubectl diff -k deploy/kubernetes/overlays/production
重点确认镜像摘要、生产域名、OIDC、RTC App ID、方舟模型、对象存储、Secret齐备情况和NetworkPolicy命名空间。此处只做结构和部署配置检查,不替代真实供应商、真机和恢复演练。
七类生产基础设施完成现场核对后,按生产基础设施一致性证据保存脱敏探针、配置版本和审计引用,并使用cmd/infrastructure-conformance生成同候选报告。静态Kustomize渲染或本地Compose报告不能满足PRODUCTION_INFRASTRUCTURE发布门禁。
8. 数据库迁移
应用发布前先执行向前迁移,并等待Job成功:
kubectl delete job voice-platform-migrate -n voice-platform --ignore-not-found
kubectl apply -k deploy/kubernetes/migration
kubectl wait --for=condition=complete job/voice-platform-migrate -n voice-platform --timeout=10m
kubectl logs job/voice-platform-migrate -n voice-platform
使用CSI模式时,把迁移命令中的目录替换为deploy/kubernetes/migration-csi。该Job直接挂载voice-platform-common,不会读取voice-platform-common-secrets。
迁移失败时停止应用发布,检查Job日志、数据库TLS、权限和当前schema版本。不要自动执行down;若迁移包含不兼容变更,应按发布方案先完成备份和向前修复脚本评审。
9. 应用发布
迁移成功后应用覆盖层:
kubectl apply -k deploy/kubernetes/overlays/production
kubectl rollout status deployment/api -n voice-platform --timeout=10m
kubectl rollout status deployment/callbacks -n voice-platform --timeout=10m
kubectl rollout status deployment/worker -n voice-platform --timeout=10m
kubectl rollout status deployment/web -n voice-platform --timeout=10m
使用CSI模式时,应用目录替换为deploy/kubernetes/overlays/production-csi。如果Pod停留在ContainerCreating,优先检查CSI Driver、提供器DaemonSet、工作负载身份、SecretProviderClassPodStatus和对象别名,不要通过放宽应用权限绕过挂载错误。
Deployment使用maxUnavailable=0、maxSurge=1滚动更新;每类服务默认至少两个副本,并受PDB保护。HPA根据CPU在2—10个副本范围内扩缩,真实生产应在观察一段时间的CPU、内存、请求率、Outbox积压和供应商配额后调整阈值。
10. 发布后轻量验收
按照“功能可用优先、避免重复高强度测试”的原则,生产发布只执行下列关键检查:
- 四个Deployment全部Available,Pod无重启循环。
- API、Callbacks和Worker的
/health/ready在集群内返回200。 - Web的
/runtime-config.js包含当前OIDC公开配置,登录和家庭导航可用。 - 使用专用验收设备完成一次签名握手、配置读取、通话启动、入房确认、心跳和停止。
- 确认火山任务进入ACTIVE后正常完成,最终字幕可见,内容候选生成并可人工确认。
- 确认一条已确认记忆能在下一次通话中按授权召回。
- 检查最近错误日志、Prometheus目标、Outbox open/dead数量和告警接收器。
- 确认
oidc_jwks、ark_tls、volc_rtc_tls和content_safety_tls外部依赖指标为1;该检查只证明网络、证书及JWKS结构,不替代真实账号业务调用或内容安全六类质量评测。
不在每次小版本发布后重复全量压测、全库恢复或完整浏览器矩阵;这些演练按重大变更、基础设施变更或既定周期执行。若上述关键链路任一失败,停止放量并回滚应用镜像。
11. 网络与观测说明
API、Callbacks和Worker Pod均带有prometheus.io/scrape、path和port发现注解。若集群Prometheus启用了基于Pod注解的服务发现,可直接抓取;使用Prometheus Operator时应创建等价的PodMonitor/ServiceMonitor,并保留相同指标路径和端口。
基线NetworkPolicy默认拒绝命名空间内所有Pod的入口流量,仅允许:
ingress-nginx命名空间访问API、Callbacks和Web业务端口;monitoring命名空间访问API、Callbacks和Worker指标端口。
基线暂不限制出口,因为数据库、Redis、OIDC、对象存储、OTLP、方舟和火山RTC可能位于不同网络。正式环境应根据实际CNI、域名解析和固定网段逐步增加出口白名单。/metrics不通过Ingress暴露,只允许监控网络访问。
12. 回滚
优先回滚应用镜像,不回滚已经成功执行的数据库迁移:
kubectl rollout undo deployment/api -n voice-platform
kubectl rollout undo deployment/callbacks -n voice-platform
kubectl rollout undo deployment/worker -n voice-platform
kubectl rollout undo deployment/web -n voice-platform
回滚后再次执行第10节的关键链路检查。若新迁移与旧应用不兼容,应使用事先评审的向前兼容修复版本,而不是在生产自动降级schema。
13. 尚需现场完成的事项
仓库清单完成的是可部署结构,不代表已经通过目标集群验收。上线前仍需业务方或平台方提供并验证:真实域名和证书、镜像仓库、托管数据库/Redis/对象存储、OIDC客户端、KMS/CSI工作负载身份、火山RTC/豆包语音、方舟模型、量产设备密钥、告警接收器,以及真机通话、外部故障、备份恢复和灰度回滚结果。