id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week
| id |
title |
type |
domain |
stack |
tags |
level |
prerequisites |
est_hours |
related |
week |
| devops.k8s.scenario.agent-rollout |
AI Agent 服务上 K8s:发布时流式回答不中断、慢启动、密钥管理和按负载扩容 |
scenario |
devops |
|
| 滚动更新 |
| 优雅退出 |
| SSE |
| 探针 |
| HPA |
| Secret |
| 回滚 |
|
intermediate |
| devops.k8s.core-objects |
| devops.docker.image-dockerfile |
|
2.5 |
| devops.k8s.interview |
| devops.cicd.release-rollback |
|
|
AI Agent 服务上 K8s:发布时流式回答不中断、慢启动、密钥管理和按负载扩容
业务背景与问题
Agent API 从虚拟机迁移到公司的 K8s 集群后:
- 每次发布,正在进行中的流式回答被切断,用户看到“网络错误”;
- 新版本启动需要预热(加载提示词模板、建立连接池),偶尔被重启循环;
- 有人把模型 API Key 直接写在 Deployment 的环境变量里提交到了仓库;
- 高峰期响应变慢,但 CPU 使用率并不高,HPA 没有扩容。
约束
- 集群由平台团队维护,应用团队只能修改自己的清单。
- 回答可能持续 60 秒以上。
方案设计
- 优雅退出:
- 应用收到 SIGTERM 后:就绪检查立即返回失败、不再接受新请求、等待进行中的流结束(最长 80 秒)后退出;
preStop 短暂等待,给 Ingress / Service 摘除端点的时间;
terminationGracePeriodSeconds: 90 大于最长回答时间;
- 滚动更新
maxUnavailable: 0。
- 慢启动:startupProbe 给足启动时间;就绪探针在预热完成后才返回成功。
- 密钥:轮换已泄露的 Key;清单中只引用 Secret;Secret 由密钥管理系统同步(或平台提供的方案);CI 中加密钥扫描。
- 扩容指标:AI 服务主要在等待模型返回,CPU 低但并发连接数高。改用“每个 Pod 的进行中请求数”作为自定义指标(需要平台支持指标适配器),或者先按经验提高副本下限。
- 发布与回滚:镜像固定版本;CI 中先
kubeconform + 规范测试;发布后观察错误率和首 token 延迟,异常时 kubectl rollout undo。
关键代码
FastAPI 应用的优雅退出(示意):
(Uvicorn 自身也会在收到 SIGTERM 后停止接收新连接并等待请求完成,具体参数如 --timeout-graceful-shutdown 以官方文档为准。)
完整清单:examples/agent-api。SSE 在 Nginx 层的配置见 AI 网关场景。
取舍
| 选择 |
优点 |
缺点 |
| 优雅退出 + 长宽限期(本方案) |
用户无感知 |
发布时间变长 |
| 前端断线自动续传(从断点继续) |
对任何中断都有效 |
后端要保存生成进度,复杂 |
| 发布时间放在低峰期 |
简单 |
治标不治本 |
易错点
- 宽限期比最长回答时间短,SIGKILL 依然切断。
- 应用作为 shell 脚本的子进程启动,收不到 SIGTERM(使用 exec 形式的启动命令)。
- 就绪探针在退出阶段仍然返回成功,新请求继续进来。
- 以为 Secret 是加密的。
面试怎么讲
“迁移到 K8s 后发布会切断流式回答。我做了优雅退出:收到 SIGTERM 后就绪探针立即失败,停止接新请求,等进行中的流结束;preStop 留出摘除端点的时间,宽限期设为 90 秒,大于最长回答;滚动更新不减少可用副本。慢启动用 startupProbe。泄露的 Key 立即轮换,清单只引用 Secret,CI 加密钥扫描。扩容方面,AI 服务 CPU 不高但并发高,改用进行中请求数作为指标。”