系统设计面试:如何安全推广 Kubernetes Node Declared Features?
题干与适用场景
集群引入 Kubernetes 的 Node Declared Features:kubelet 在 Node 状态中报告受管理的节点能力,调度器据此过滤 Pod,准入控制器在 Pod 更新时再次校验。请设计混合版本集群的上线、观测、失败处理和回滚方案。假设该能力只用于受控的节点特性,不允许业务团队任意写入能力名称。
面试官考察点
- 是否理解能力声明是 Node 状态事实,不是用户可随意伪造的标签。
- 是否能把 kubelet、kube-apiserver、kube-scheduler 和 admission controller 的依赖顺序讲清楚。
- 是否覆盖旧节点、状态延迟、Pod 更新和 feature gate 回滚。
- 是否用调度拒绝率与节点报告完整度证明安全,而不是只看组件启动成功。
回答前需要澄清的问题
- 目标节点能力由哪个 kubelet 版本产生,旧节点是否允许继续承载普通 Pod?
- 需要保护的是调度时的放置,还是 Pod 绑定后更新也必须受保护?
- 集群是否有自定义 scheduler、多个 API server 或跨区域控制面?
- 发生误报时优先停止新 Pod,还是允许旧 Pod 继续运行?
30 秒回答框架
我会把能力声明当作一条跨组件的事实链:kubelet 报告 status.declaredFeatures,调度器插件在 PreFilter 和 Filter 阶段判断 Pod 需求,准入控制器保护后续更新。上线先在非关键节点和小比例工作负载启用,确认 kube-apiserver、scheduler、kubelet 的 feature gate 一致,再扩大范围。监控能力报告完整度、调度失败原因、更新拒绝率和版本分布;发现不一致就停止依赖新能力的工作负载并关闭 gate,保留普通 Pod 的调度路径。
分步骤深入解答
- 定义事实来源。 节点能力由 kubelet 在启动时检测并写入 Node 的
status.declaredFeatures;应用团队不能把任意标签当成等价事实。能力名称应来自受管理的 feature gate 或明确的组件契约。 - 明确组件依赖。 Kubernetes 文档要求 NodeDeclaredFeatures gate 同时在 kube-apiserver、kube-scheduler 和 kubelet 启用。先验证控制面版本和配置,再升级 kubelet,避免只开一端造成“字段存在但没人使用”或“调度器要求字段而节点不会报告”。
- 设计调度路径。 scheduler 插件在 PreFilter 从 PodSpec 推断所需能力,在 Filter 对照节点声明;没有声明所需能力的节点不可调度。自定义 scheduler 若复用该字段,也必须复制同样的缺省与失败语义。
- 保护更新路径。
NodeDeclaredFeatureValidatoradmission controller 在 Pod 更新时验证绑定节点能力,防止初次调度后节点能力变化或工作负载要求升级绕过过滤。将更新拒绝作为明确业务错误,避免静默降级。 - 处理混合版本。 旧 kubelet 可能没有该字段或不识别新能力。把“未声明”当作“不满足要求”,让依赖新能力的 Pod 留在队列中;普通 Pod 仍可调度到兼容节点。不要通过手工补 Node 状态来绕过版本差异。
- 分阶段发布。 先在可回滚的节点池启用 gate,放置一个只要求新能力的探针工作负载,再逐步扩展。每阶段设置停止条件:报告缺失率、调度拒绝率、Pod 更新拒绝率或 scheduler 延迟超过基线即暂停。
- 观测与审计。 采集 Node 声明版本、能力集合摘要、调度过滤原因、准入拒绝原因和 gate 配置指纹;按节点池和 Kubernetes 版本切片。避免把完整 Node 对象写入高基数日志。
- 回滚和升级。 回滚先停止创建依赖能力的 Pod,再恢复普通调度;确认没有 pending 工作负载后按组件顺序关闭 gate。若能力已被业务依赖,应先迁移工作负载或保留兼容节点,不能直接让声明消失。
高质量示范回答
我会先确认这条链路的事实源和保护目标。kubelet 负责报告受管理的 status.declaredFeatures,scheduler 的 NodeDeclaredFeatures 插件负责在调度前过滤,NodeDeclaredFeatureValidator 负责保护绑定后的更新。因为 Kubernetes 要求 kube-apiserver、scheduler 和 kubelet 同时启用 gate,我会先统一控制面和节点版本,再在一个可回滚节点池启用。探针 Pod 验证能力报告和调度结果,随后以报告缺失率、过滤拒绝率、更新拒绝率和调度延迟作为扩容门槛。旧节点不声明能力就视为不满足要求,普通 Pod 仍走原路径。回滚时停止新依赖、迁移现有工作负载、关闭 gate,并确认 pending 数量和普通 Pod 调度恢复。
常见错误
- 把 declaredFeatures 当普通标签 → 用户可伪造能力而破坏调度安全 → 只接受 kubelet 管理的能力集合。
- 只在 scheduler 开 gate → 节点不会报告字段 → 按 kube-apiserver、scheduler、kubelet 三端检查配置。
- 把未声明当成支持 → 混合版本节点可能接收不兼容 Pod → 未声明必须按不满足处理。
- 只验证首次调度 → Pod 更新可能绕过能力约束 → 同时启用并观测准入校验。
- 直接全量打开 → 失败时无法区分版本、节点池和工作负载影响 → 使用探针、分阶段和停止条件。
- 直接关闭 gate → 已依赖能力的 Pod 进入不可恢复状态 → 先停止创建并迁移依赖工作负载。
追问及应对
节点报告能力后状态长时间没有更新,调度器该怎么办?
把报告年龄纳入可观测性和运维门槛;对要求该能力的 Pod,宁可继续等待或转移到新鲜节点,也不要根据过期声明放行。达到超时后触发节点池隔离和人工确认。
自定义 scheduler 不使用官方插件,会有什么风险?
它必须实现同样的 PreFilter、Filter、缺省和版本语义,否则会出现默认 scheduler 拒绝而自定义 scheduler 放行的分裂。先用一致性测试验证两条路径,再允许工作负载切换调度器。
feature gate 需要跨三个组件同时变更,如何避免窗口不一致?
把配置指纹纳入发布检查,先让不依赖能力的工作负载保持可运行,再按控制面、scheduler、节点池顺序滚动。任何指纹不一致都停止扩展,不把“组件已启动”当作完成信号。
业务已经依赖新能力,但回滚发现旧节点不支持,怎么办?
先保留一组声明能力的新节点,迁移或缩小依赖该能力的工作负载,再关闭 gate;如果无法迁移,就暂停回滚并提高兼容节点容量,避免让调度约束突然失效。