给事故分类的顺序
一句话总结
Pod 无法启动时,首先要数的不是剩余资源,而是候选节点的数量。如果候选节点为 0,剩余资源就毫无意义。
为什么顺序是固定的
首先要分清 Pod 对象是否存在。ResourceQuota 官方文档所描述的配额违规,可能会拒绝创建请求。这时要找的不是 Pending 的 Pod,而是 Deployment 和 ReplicaSet 事件中的 FailedCreate 以及 API 错误。LimitRange 违规也可能是准入阶段的问题。
如果 Pod 存在,就按照 Pod 生命周期检查条件和事件。Pending 不仅包括调度之前的等待,也包括镜像准备之类的等待。请同时查看 PodScheduled 条件、nodeName 和容器的等待原因。不要把所有的 Pending 都按同样的顺序解读为资源不足。
本实验的虚构事故,是没有与 nodeSelector 匹配的候选节点(为 0)的情形。先通过事件确认该条件,再统计候选节点的数量。即使有候选节点,也可能因为污点、affinity、卷或实际请求量而无法调度。请区分节点分配文档中的必需选择条件和偏好条件。
工作原理
分类的结果必须是数字
“好像资源不足”不是分类。分类就是写下以下四个值。
| 项目 | 来自哪里 |
|---|---|
| 选择器的键和值 | 工作负载的 nodeSelector |
| 副本数 | Deployment 的 spec.replicas |
| 所需的 CPU 总量 | 容器请求 × 副本数 |
| 候选节点数 | 用该选择器统计节点得到的值 |
写下这四个值,下一个人就会从同一个地方开始。如果没有写下来,下一个人就要从头重做。事故记录的价值不在于句子,而在于这些数字。
恢复与删除需求是两回事
让 Pod 启动起来的最快方法,是删除 nodeSelector。只要没有其他约束,它就可以被调度。然而,那个选择器是有人出于某种理由写下的。可能是需要 GPU,可能是必须挂接到特定存储,也可能是因为合规要求只能部署到特定节点。
如果不确认需求的依据和变更审批就删除约束,就可能变成删除需求。而且这种差别不会显示在界面上。Pod 是 Running,告警关闭,仪表板是绿灯。问题会在几周之后以出人意料的形式回来。
恢复,是让约束得到满足。给节点加上池标签,或者把节点加入那个池,如果做不到,就写下为什么做不到,由人来做出修改工作负载一侧需求的决定。
right-sizing 的方向是确定的
收到降低成本的要求时,人会很想先缩减节点。应该先收集有代表性的时间段内的使用量、峰值、失败和延迟,并审查请求量的余量和恢复所需的容量。只看平均使用量就往下调,会错过负载的突增。调整请求和缩减节点,要先定好回退条件,再在小范围内试验。scale-to-zero 也是要根据启动延迟和工作负载的需求才可能采用的选择,不能断言它总是会造成中断,或者总是能节省成本。
在现场相遇的样子
下面是为实验设计的虚构案例。节点增加了三台,Pod 却仍然是 Pending。新节点没有加上池标签,而工作负载要求那个标签。容量图上升了,候选节点却依旧是 0 台。这是只看仪表板就永远看不到的一类事故。
另一种情形是,加上标签之后立刻像评分一样去确认,就得出了“不行”的结论。调度器会周期性地重试,所以要等几秒钟。如果立即确认并下判断,就会把正确的处理撤销。
下一项实验要做什么
创建三个租户,用配额和 LimitRange 进行划分,亲自计算超额分配(overcommit)的比例,复现 Pending 事故并对其分类,在不删除约束的前提下恢复,然后编写并部署平台自身的记录规则和告警。