“进程还在”与“系统可用”不是同一件事
一个容器进程存在,只能说明它还没有退出。它可能仍在加载数据、已经死锁、依赖的网关不可用,甚至根本无法处理请求。
本项目用了两层健康表达:
- Pod probes:kubelet 判断单个容器是否启动、存活、能否接流量;
- SubPool Conditions:Operator 判断整套空号池平台的依赖是否满足。
两层都叫“健康”,但观察范围完全不同。
三种 Probe 分别问什么
startupProbe:你启动完了吗
慢启动应用可能需要初始化文件、打开数据库或加载大量配置。startupProbe 在成功前,会保护应用不被 livenessProbe 过早判死。
本项目 CPA 和 cpa-manager 都允许最多约 150 秒启动:
| |
粗略上限是 30 × 5 = 150 秒,实际还会受到 timeout 和执行时间影响。
readinessProbe:现在可以接流量吗
readinessProbe 失败时,容器不一定被重启,但 Pod 会变成 NotReady,通常也不会作为 Service 的 Ready Endpoint 接收流量。
它适合表达暂时不可服务的状态,例如:
- 应用还没完成初始化;
- 本地依赖暂时不可用;
- 应用正在优雅排空请求。
livenessProbe:你是不是已经坏到需要重启
livenessProbe 持续失败时,kubelet 会重启容器。它应检测无法自行恢复的故障,而不是把所有外部依赖都塞进去。
如果 livenessProbe 强依赖互联网或共享网关,一个短暂外部故障可能让整个集群中的 Pod 同时重启,造成故障放大。
本项目的探针设计
CPA 使用 HTTP GET /,端口 8317;cpa-manager 使用 HTTP GET /health,端口 18317。
Mihomo Gateway 使用 TCP socket 探测 18000 端口。TCP 探针只证明进程正在监听端口,不能证明每个代理节点可用或访问外部网站一定成功。
Operator 自己暴露:
/healthz:进程健康;/readyz:controller manager 准备状态。
探针越靠近应用语义,结论越强,但也越可能被外部依赖干扰。设计时要明确“这个探针失败后,Kubernetes 会采取什么动作”。
Probe 失败后谁做什么
| |
在多容器 Pod 中,一个容器重启不一定重建整个 Pod;但任何一个普通容器不 Ready,Pod 整体通常不会 Ready。
SubPool Conditions 是系统级状态
本项目固定维护这些 Conditions:
| Condition | True 表示什么 |
|---|---|
InfrastructureReady | StatefulSet 有 Ready replica,两个内部 Service 存在 |
ProxyGatewayReady | Shared Mihomo Service 至少有一个 Ready Endpoint |
ExposureReady | Internal 边界成立,或 Gateway Route/Gateway 已就绪 |
PlatformReady | 上面三类依赖同时满足 |
Ready | 当前 generation 的空号池平台已就绪 |
DeletionBlocked | 删除正被 Namespace 或 finalizer 阻塞 |
依赖关系可以画成:
| |
这样比只有一个模糊的 Ready=False 更容易排查。
Condition 的四个核心字段
一个标准 Condition 常包含:
| |
阅读顺序:
type:在检查哪个维度;status:True、False 或 Unknown;reason:机器可读、相对稳定的原因码;message:给人看的上下文说明。
自动化应优先依赖 type/status/reason,不要用字符串包含关系解析 message。
observedGeneration 防止读到过期的好消息
每次修改 SubPool spec,metadata.generation 都会递增。Operator 完成本轮状态计算后,把这代数写入:
| |
如果出现:
| |
说明 status 仍对应旧 spec。即使 Ready 还是 True,也不能直接当作新配置已生效。
这是异步控制系统的重要常识:状态有时间差,必须知道控制器观察的是哪一代期望。
Internal 模式为什么 ExposureReady 可以为 True
Internal 模式不要求外部 Gateway。它的 ExposureReady 表示设计中的访问边界已经成立:CPA 是 ClusterIP,管理员可通过受控 port-forward 访问。
这不是说 CPA 已经公网可达。Condition 的含义必须结合产品契约,而不能凭名字猜。
Gateway 模式则要求:
- HTTPRoute 存在;
- Route 被指定 Gateway listener Accepted;
- Route 的引用已成功解析;
- Shared Gateway 的
Programmed=True。
所以同一个 Condition type 在两种模式下有不同的检查路径,但都回答“所选择的暴露方式是否准备好”。
Ready=True 明确不检查什么
本项目把 Ready 限定为“空号池平台 Ready”,不承诺:
- 账号已经导入;
- OAuth token 有效;
- 真实模型请求成功;
- 所有上游代理节点健康;
- 每个 HTTP 请求切换一次 IP。
这是负责任的状态设计。若控制器没有证据验证某件事,就不应让 Ready 暗示它已经验证。
未来可以新增业务级健康对象或指标,但不能悄悄改变现有 Ready 的语义,否则旧自动化会被误导。
kubectl wait 在等什么
| |
它等待名为 Ready 的 Condition 变为 True。超时不代表 kubectl 出错,只表示在指定时间内条件没有满足。
超时后不要立刻重复 wait,应读取 Conditions:
| |
然后沿失败维度继续检查。
从 Condition 到对象的排查路径
InfrastructureReady=False
| |
ProxyGatewayReady=False
| |
ExposureReady=False 且为 Gateway 模式
| |
DeletionBlocked=True
| |
常见探针误区
livenessProbe 做得越深越好
错误。它失败会触发重启,检查外部依赖过深容易制造重启风暴。
readinessProbe 失败就一定要重启
不一定。暂时不能接流量与进程不可恢复是两个问题。
TCP probe 成功等于业务正常
不等于。它只证明端口可建立 TCP 连接。
Pod Ready 等于整个平台 Ready
不等于。Pod 可能 Ready,但 Shared Mihomo 或 Gateway 尚未就绪。
Ready=False 都是故障
不一定。新建中的资源、显式 suspend 或等待外部基础设施时,False 可能是诚实的过渡状态。
健康检查的价值不在于把所有东西染成绿色,而在于让每一盏灯都有准确、稳定、可行动的含义。