
Karpenter Node Disruption 完全指南Consolidation、Drift 与 Expiration 的优雅与强制驱逐机制【免费下载链接】karpenter-provider-awsKarpenter is a Kubernetes Node Autoscaler built for flexibility, performance, and simplicity.项目地址: https://gitcode.com/GitHub_Trending/ka/karpenter-provider-awsKarpenter 作为 Kubernetes 节点自动扩缩容组件其核心价值不仅在于按需创建节点更在于以受控、优雅的方式主动重组节点以降低成本与保持集群健康。本文基于 karpenter-provider-aws 仓库 v1.14 版本文档系统梳理 Karpenter 的 Disruption节点扰动体系从 Disruption Controller 与 Termination Controller 的双层控制流到 Consolidation整合、Drift漂移等自动化优雅方法再到 Expiration过期、Interruption中断与 Node Auto Repair节点自动修复等强制方法最后覆盖terminationGracePeriod、Disruption Budgets扰动预算以及 Pod/Node 级别的do-not-disrupt防护注解。读完本文你将掌握如何通过 NodePool 配置精确控制 Karpenter 在何时、以多快速度、以何种方式重组你的节点。控制流总览Finalizer 与两个核心 ControllerKarpenter 会对它创建的每一个 Node 和 NodeClaim 设置 Kubernetes finalizer。finalizer 会阻塞 Node 对象的删除直到 Termination Controller 完成对节点的污点标记taint和排空drain随后才移除底层的 NodeClaim。节点的扰动可以由三条路径触发Disruption ControllerKarpenter 自动发现可扰动节点并在需要时拉起替换节点用户手动扰动通过kubectl delete等命令手动删除外部系统向 Node 对象发送删除请求。Disruption Controller 的标准流程Karpenter 会一次只执行一种自动化方法优先级顺序为先 Drift后 Consolidation。每种方法的细节略有差异但都遵循标准扰动流程并通过 Disruption Budgets 控制扰动启动速度为当前扰动方法识别一批按优先级排序的候选节点。如果节点上有无法驱逐的 PodKarpenter 会忽略该节点稍后再尝试如果没有可扰动节点则继续下一种扰动方法。对每个可扰动节点检查扰动它是否会违反其 NodePool 的 disruption budget对该节点上的 Pod 执行调度模拟判断是否需要替换节点。给节点打上karpenter.sh/disrupted:NoSchedule污点阻止新的 Pod 调度到该节点。预启动步骤2中计算出的替换节点并等待它们变为 Ready。如果替换节点初始化失败则移除污点并从步骤1重新开始回到第一种扰动方法。删除节点并等待 Termination Controller 优雅关闭节点。Termination Controller 终止节点后回到步骤1再次从第一种扰动方法开始。Termination Controller 的优雅关闭五步当 Karpenter 节点被删除时finalizer 会阻塞删除APIServer 会在 Node 上设置DeletionTimestamp让 Karpenter 得以模拟 Kubernetes Graceful Node Shutdown 完成优雅关闭。其流程为给节点添加karpenter.sh/disrupted:NoSchedule污点阻止 Pod 调度上来使用 Kubernetes Eviction API 驱逐节点上的 Pod以尊重 PDBPodDisruptionBudget同时忽略所有 static pod、容忍karpenter.sh/disrupted:NoSchedule污点的 Pod 以及已完成/失败Succeeded/Failed的 Pod等待节点完全排空后再进入步骤3。等待期间如果底层 NodeClaim 已不存在则移除 finalizer 让 APIServer 删除 Node完成终止。校验所有可排空 Pod 对应的 VolumeAttachment 资源均已删除。在云提供商侧终止 NodeClaim。从 Node 上移除 finalizer让 APIServer 删除 Node完成终止。从仓库结构看Termination Controller 与 Disruption Controller 属于 Karpenter 核心控制器体系上游sigs.k8s.io/karpenter模块的一部分AWS 提供方在 pkg/cloudprovider/cloudprovider.go 中实现Create、Delete、IsDrifted等云提供商接口承接节点创建与终止的实际 EC2 操作。手动扰动方法删除 Node每个 Karpenter Node 都由一个 NodeClaim 拥有因此删除其中任何一个都会级联删除另一个# 删除指定的 nodeclaim kubectl delete nodeclaim $NODECLAIM_NAME # 删除指定的 node kubectl delete node $NODE_NAME # 删除所有 nodeclaims kubectl delete nodeclaims --all # 删除所有由任意 nodepool 拥有的 nodes kubectl delete nodes -l karpenter.sh/nodepool # 删除指定 nodepool 拥有的所有 nodeclaims kubectl delete nodeclaims -l karpenter.sh/nodepool$NODEPOOL_NAME删除 NodePoolNodeClaim 通过 owner reference 归属于启动它的 NodePool。当所属 NodePool 被删除时Karpenter 会通过级联删除优雅地终止节点。注意通过添加 finalizerKarpenter 改进了 Kubernetes 默认的节点删除流程。如果对一个没有 finalizer 的 Node 执行kubectl delete node节点对象会被直接删除而不触发终结逻辑——EC2 上的实例仍会继续运行但已没有对应的 Node 对象kubelet 不会监听自身的存亡因此不会自我终止所有 Pod 对象稍后会被垃圾回收进程删除因为它们的节点已经不存在了。自动化优雅方法自动化优雅方法可以通过 NodePool Disruption Budgets 进行限速Consolidation整合Karpenter 主动降低集群成本识别以下场景节点为空可以直接删除节点上的工作负载可以运行到集群中其他节点上从而删除该节点由于工作负载变化节点可以被更便宜的实例类型替换。Drift漂移Karpenter 将偏离期望规格的节点标记为 drifted 并扰动它们。默认值Disruption 通过 NodePool 的 disruption 块中的consolidationPolicy与consolidateAfter字段配置。如果未设置Karpenter 会使用以下默认值spec: disruption: consolidationPolicy: WhenEmptyOrUnderutilized consolidateAfter: 0sConsolidation整合Consolidation 由consolidationPolicy与consolidateAfter配置。consolidationPolicy决定 Karpenter 考虑哪些节点进行整合在成本节省与扰动运行中 Pod 的程度之间做权衡策略考虑的节点适用场景WhenEmpty仅空节点空节点指只运行无扰动成本的 Pod如 daemonset、用户覆盖的 Pod以及用户标注为低成本可驱逐的临时 Pod想要最保守的行为只有节点上无任何运行时才删除节点整合只驱逐零扰动成本的 PodBalanced成本节省大于扰动运行 Pod 代价的节点想要WhenEmptyOrUnderutilized的大部分收益但不想承受边际整合带来的扰动Karpenter 仍会删除空节点和明显低利用率的节点但会跳过节省不足以抵消扰动的动作参见 Balanced consolidationWhenEmptyOrUnderutilized任何可通过删除或替换来降低成本的节点想要最低成本并愿意接受为此付出的 Pod 扰动consolidateAfter决定 Karpenter 在考虑整合某节点前等待新工作落到该节点上的时长。每当节点上有 Pod 加入或移除Karpenter 都会重置该计时器因此一个节点只有在完整稳定了consolidateAfter时长后才会成为整合候选。设置更长的值可以让频繁变化的负载有时间沉淀降低 Karpenter 的整合激进程度设置为Never则完全禁用该 NodePool 的整合。Karpenter 有两种集群整合机制Deletion删除——节点上所有 Pod 都能运行到集群中其他节点的空闲容量上则该节点可被删除Replace替换——节点上所有 Pod 可以运行到集群其他节点空闲容量与单个更低价格替换节点的组合上则该节点可被替换。Consolidation 按顺序执行三种机制以尝试识别整合动作Empty Node Consolidation空节点整合——并行删除所有完全为空的节点Multi Node Consolidation多节点整合——尝试并行删除两个或更多节点可能启动单个替换节点其价格低于被删除节点的总价格Single Node Consolidation单节点整合——尝试删除任意单个节点可能启动单个价格更低的替换节点。逐一检查多节点整合的所有组合是不现实的因此 Karpenter 使用启发式方法来识别可能被整合的节点集合对于单节点整合Karpenter 会逐一考虑集群中的每个节点。当存在多个可删除或可替换的节点时Karpenter 倾向于终止对工作负载扰动最小的节点优先选择运行 Pod 更少的节点即将过期的节点运行低优先级 Pod 的节点。如果启用了整合Karpenter 会定期针对节点发布事件说明该节点为何无法被整合。这些事件可用于排查那些你预期已被整合、但仍留在集群中的节点Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Unconsolidatable 66s karpenter pdb default/inflate-pdb prevents pod evictions Normal Unconsolidatable 33s (x3 over 30m) karpenter cant replace with a lower-priced node警告使用 preferred anti-affinity 与 topology spread 会降低整合的有效性。在节点启动时Karpenter 会尝试满足亲和性与拓扑分布偏好为了减少节点频繁更换整合也必须尝试满足这些约束避免节点启动后立刻被整合。这意味着即使 kube-scheduler 能把宿主的 Pod 安排到别处整合也可能为了不违反偏好而不扰动节点。Karpenter 会通过日志报告这些 Pod 以提醒可能引发的问题例如pod default/inflate-anti-self-55894c5d8b-522jd has a preferred Anti-Affinity which can prevent consolidation。Balanced 整合Balanced策略对每个整合动作打分衡量该动作为 NodePool 节省的成本相对于其对 NodePool 全部 Pod 造成的扰动只有当节省相对扰动足够大时才执行该动作。spec: disruption: consolidationPolicy: Balanced默认情况下每个 Pod 对扰动贡献相同权重因此动作的扰动实际上等于其驱逐的 Pod 数量评分简化为节省 vs Pod 数量的比较。迁移成本更高的 Pod 可以承担更大权重——例如高优先级 Pod 被视为扰动更大——这会降低其所在节点被整合的可能性。Karpenter 会记录每次评分决策方便你查看某个动作为何被批准或拒绝。被批准的动作会发出ConsolidationApproved事件单节点动作在 Node 与 NodeClaim 上、多节点动作在 NodePool 上包含分数以及节省与扰动百分比。评分决策也会以karpenter_consolidation_score和karpenter_consolidation_moves_total指标 导出带 decision、NodePool 与 policy 标签并在--log-level debug时记录日志。这两项指标在该仓库的指标文档中标注为 ALPHA 稳定性级别可通过 Karpenter 默认的:8080/metrics端点METRICS_PORT环境变量可配置以 Prometheus 格式获取。Spot 整合对于 Spot 节点Karpenter默认启用删除型整合。如果要为 Spot 整合启用替换功能需要开启SpotToSpotConsolidationfeature flag当前仓库中该 gate 默认值为falseAlpha 阶段自 v0.34.x 引入。更低价格的 Spot 实例类型通过price-capacity-optimized策略 选择。有时最低价的 Spot 实例类型因中断概率较高而不会被启动。因此Karpenter 用价格低于当前 Spot 实例的可用实例类型数量作为启发式评估是否为当前 Spot 节点启动替换。Karpenter 将启动决策中可用的实例数量称为启动的实例类型灵活性。当考虑执行 spot-to-spot 整合替换时Karpenter 会检查替换实例类型是否能在随后的启动请求中保留足够的实例类型灵活性。由此得到两个特性不应持续整合到可能中断率极高的最低价 Spot 实例应以足够多的实例类型启动使替换实例的可用性与当前实例相当。Karpenter 在执行**单节点 spot-to-spot 整合1 节点替换 1 节点**时要求最少15 个实例类型的灵活性。多节点 spot-to-spot 整合多节点替换 1 节点没有同样的灵活性要求因为不要求灵活性也不会导致竞相触底race to the bottom的场景。Drift漂移Drift 处理 NodePool/EC2NodeClass 的变化。对于 DriftNodePool/EC2NodeClass 中的值会以与设置相同的方式反映在 NodeClaimTemplateSpec/EC2NodeClassSpec 中。如果其所属 NodePool/EC2NodeClass 中的值与 NodeClaim 中的值不匹配该 NodeClaim 就会被检测为 drifted。与上游deployment.spec.template与 Pod 的关系类似Karpenter 会给所属 NodePool 和 EC2NodeClass 打上 NodeClaimTemplateSpec 的哈希注解以检查漂移。某些特殊情况会由 Karpenter 或通过 CloudProvider 接口发现由 NodeClaim/Instance/NodePool/EC2NodeClass 变更触发。在 AWS 提供方实现中漂移检测逻辑位于 pkg/cloudprovider/drift.go。isNodeClassDrifted会先检查静态字段漂移基于 EC2NodeClass 哈希注解再依次检查 AMI 漂移、安全组漂移、子网漂移、容量预留漂移与放置组漂移可返回的漂移原因包括AMIDrift、SubnetDrift、SecurityGroupDrift、CapacityReservationDrift、PlacementGroupDrift与NodeClassDrift。例如isAMIDrifted会把当前实例类型可用的 AMI 列表与 NodeClaim 状态中的ImageID比对若不再包含则判定为 AMI 漂移areSecurityGroupsDrifted会对比 NodeClass 状态中的安全组集合与 EC2 实例实际挂载的安全组。AWS 云提供商通过 IsDrifted 接口 暴露这些检测能力给核心控制器。Drift 的特殊情况在特殊情况下漂移可能对应多个值需要区别处理。已解析字段上的漂移可能在没有 CRD 变更时发生或者 CRD 变更却不产生漂移。例如若 NodeClaim 是node.kubernetes.io/instance-type: m5.large而需求从node.kubernetes.io/instance-type In [m5.large]变为node.kubernetes.io/instance-type In [m5.large, m5.2xlarge]NodeClaim不会漂移因为它的值仍然兼容新的需求反之若 NodeClaim 使用镜像ami: ami-abc但发布了新镜像Karpenter 的EC2NodeClass.spec.amiSelectorTerms会发现新的正确值是ami: ami-xyz从而检测该 NodeClaim 漂移。NodePool 中触发漂移的字段Fieldsspec.template.spec.requirementsEC2NodeClass 中触发漂移的字段Fieldsspec.subnetSelectorTermsspec.securityGroupSelectorTermsspec.amiSelectorTerms行为字段Behavioral Fields行为字段是 NodePool 上控制 Karpenter 行为的总体设置。这些字段不对应 NodeClaim 或实例上的设置而是由用户设置以控制 Karpenter 的 Provisioning 与扰动逻辑。由于它们不映射到 NodeClaim 的期望状态行为字段不参与 Drift 判定。NodePoolFieldsspec.weightspec.limitsspec.disruption.*Karpenter 会在 NodeClaim 偏离其所属 NodePool 时添加Drifted状态条件并在以下任一情况下移除Drifted状态条件NodeClaim 已漂移但Driftfeature gate 未启用——Karpenter 移除状态条件注意v1 版本中 Drift 已晋升为 stablefeature gate 被移除可通过按 reason 配置 disruption budgets 继续控制NodeClaim 未漂移但仍带有该状态条件——Karpenter 移除它。自动化强制方法自动化强制方法会在条件满足时立即开始排空节点。与上述优雅方法不同这些方法无法通过 NodePool Disruption Budgets 限速也不会等待预启动的替换节点健康后再调度 Pod。应用层面的 Pod Disruption Budgets 仍可用于限制应用扰动。Expiration过期Expiration 是一种强制扰动方法一旦节点存活时间超过其所属 NodeClaim 的spec.expireAfter字段设置的时长立即开始排空该节点。对所属 NodePool 的spec.template.spec.expireAfter的修改不会更新现有 NodeClaim 的该字段——它会诱导 NodeClaim 漂移替换节点将使用更新后的值。Expiration 可与terminationGracePeriod配合使用以强制最大节点生命周期。默认情况下expireAfter为720h30 天。注意expireAfter定义的是节点的最大生命周期上界而非保证的最小值。节点可能被其他扰动方法如 Drift、Consolidation 或 Emptiness在其expireAfter之前扰动前提是它们的 disruption budgets 允许。例如一个expireAfter: 720h30 天的 NodePool如果节点因 AMI 更新而漂移且预算允许漂移型扰动仍可能更早被终止。要强制一个不被其他扰动方法缩短的真正最大节点生命周期请将expireAfter与精心配置的 disruption budgets 结合使用限制或阻止其他扰动原因。警告配置错误的 PDB 与带karpenter.sh/do-not-disrupt注解的 Pod 可能无限期阻塞排空。因此如果你的集群中存在带karpenter.sh/do-not-disrupt注解的 Pod不建议只设置expireAfter而不设置terminationGracePeriod。这样做可能导致部分排空的节点卡在集群中推高集群成本并可能需要人工介入解决。Interruption中断如果启用了 interruption-handlingKarpenter 会监视即将发生的、会造成工作负载中断的非自愿中断事件包括Spot Interruption WarningsSpot 中断警告Scheduled Change Health Events计划变更健康事件 / 维护事件Instance Terminating Events实例终止事件Instance Stopping Events实例停止事件Instance Status Check Failures实例状态检查失败当 Karpenter 检测到这些事件将影响节点时它会在中断事件到来之前自动对节点执行 taint、drain 与 terminate为工作负载清理留出最大时间。这使terminationGracePeriod较长或清理至关重要的场景得以优雅地清理 Pod。对于 Spot 中断NodePool 一看到 Spot 中断警告就立即启动新节点。Spot 中断在 Amazon EC2 回收实例前有2 分钟通知。Karpenter 收到警告后会一边排空节点一边并行置备新节点。Karpenter 的平均节点启动时间意味着通常有足够时间让新节点在 EC2 对 Spot 实例发起终止前变为 Ready。注意Karpenter 会为上述所有事件向节点发布 Kubernetes 事件此外还有Spot Rebalance Recommendations。Karpenter 目前不支持对 Spot Rebalance Recommendations 执行 taint、drain、terminate 逻辑。如果需要处理 Spot Rebalance Recommendations可以在 Karpenter 旁使用 AWS Node Termination Handler (NTH)。Karpenter 通过监视一个SQS 队列来处理大多数中断事件该队列接收来自 AWS 服务的、可能影响节点的关键事件。Karpenter 要求预先置备 SQS 队列并添加 EventBridge 规则与目标把来自 AWS 服务的中断事件转发到 SQS 队列。基础设施的置备细节见 Getting Started Guide 中的 CloudFormation 模板。要启用完整的中断处理请配置--interruption-queueCLI 参数为已置备的中断队列名称对应环境变量INTERRUPTION_QUEUE未配置时中断处理被禁用。从源码看AWS 提供方在 pkg/controllers/interruption/controller.go 中实现了该控制器它持续轮询 SQS 队列获取aws.ec2与aws.health的事件通过EventParser解析为内部 Message 类型如 spot interruption、scheduled change、state change、capacity reservation interruption 等见 pkg/controllers/interruption/messages并行处理并删除消息对应的事件类型在 pkg/controllers/interruption/parser.go 中注册。端到端的中断流程可在 test/suites/interruption/suite_test.go 的集成测试中看到包括通过 FIS 实验触发 Spot 中断、在 SQS 队列中注入 scheduled change 健康事件以及禁用 SQS 队列后仅由实例状态控制器处理中断等场景。此外Karpenter 利用 EC2 DescribeInstanceStatus API 检查由 Karpenter 管理的不健康 EC2 实例。Karpenter 响应的状态检查包括System Status——底层物理主机硬件或软件的故障Instance Status——虚拟机的故障Scheduled Maintenance Events——可能影响实例的即将到来的维护事件这些状态检查不要求配置--interruption-queue只需要 EC2 DescribeInstanceStatus 的 IAM 权限。Node Auto Repair节点自动修复功能状态Karpenter v1.1.0 alphaNode Auto Repair 自动识别并替换集群中的不健康节点帮助维护整体集群健康。节点可能经历影响硬件、文件系统或容器环境的各种故障这些故障可能通过节点条件呈现如网络不可用、磁盘压力、内存压力或节点诊断代理报告的其他条件。当 Karpenter 检测到这些不健康条件时会根据云提供商定义的修复策略自动替换受影响的节点。一旦节点处于不健康状态超过其配置的容忍时长toleration durationKarpenter 将强制终止该节点及其对应的 NodeClaim绕过标准的排空与宽限期流程以确保快速替换问题节点。为防止级联故障Karpenter 内置了安全机制如果 NodePool 中超过 20% 的节点不健康则不执行修复对于独立 NodeClaim则对照集群中所有节点评估该阈值。这确保即使在正常节点终止流程可能受节点不健康状态影响的场景下集群也能以最少的人工介入保持健康。启用 Node Auto Repair 的步骤确保已部署 Node Monitoring Agent 或任何会为节点添加受支持状态条件的代理如 Node Problem Detector启用 feature flagNodeRepairtrueNode AutoRepair 将根据云提供商的修复策略在节点出现不健康状态条件时自动终止节点。Karpenter 在发起修复动作时监视以下节点状态条件Kubelet 节点条件TypeStatusToleration DurationReadyFalse30 分钟ReadyUnknown30 分钟Node Monitoring Agent 条件TypeStatusToleration DurationAcceleratedHardwareReadyFalse10 分钟StorageReadyFalse30 分钟NetworkingReadyFalse30 分钟KernelReadyFalse30 分钟ContainerRuntimeReadyFalse30 分钟上述修复策略在 AWS 提供方代码中通过RepairPolicies()返回见 pkg/cloudprovider/cloudprovider.go#L305-L346包含ReadyFalse/ReadyUnknown各 30 分钟的 Kubelet 条件以及AcceleratedHardwareReady10 分钟、StorageReady、NetworkingReady、KernelReady、ContainerRuntimeReady各 30 分钟的 Node Monitoring Agent 条件。启用该功能需设置NodeRepairfeature gate参见 Feature Gates当前仓库默认NodeRepairfalse。控制手段TerminationGracePeriod要配置最大终止时长应使用terminationGracePeriod。它通过 NodePool 的spec.template.spec.terminationGracePeriod字段配置并持久化到创建的 NodeClaimspec.terminationGracePeriod。对 NodePool 上spec.template.spec.terminationGracePeriod字段的修改不会改变现有 NodeClaim——它会诱导 NodeClaim 漂移替换节点将使用更新后的terminationGracePeriod。一旦节点通过优雅或强制方法被扰动Karpenter 就会开始排空节点。此时terminationGracePeriod的倒计时开始。一旦terminationGracePeriod到期剩余 Pod 将被强制删除底层实例被终止。如果所有可扰动 Pod 已排空完毕节点可能在terminationGracePeriod到期前就被终止。与expireAfter配合使用时terminationGracePeriod可用于强制绝对最大节点生命周期节点在expireAfter到期后开始排空在terminationGracePeriod到期后被强制终止因此最大节点生命周期为两个字段之和。此外配置terminationGracePeriod会改变Drift扰动的资格标准。配置后即使节点上有阻塞性 PDB 或带karpenter.sh/do-not-disrupt注解的 Pod节点仍可因漂移而被扰动。这使集群管理员能够确保关键更新例如修复 CVE 的 AMI 更新不会被错误配置的应用阻塞。警告为确保排空 Pod 的terminationGracePeriodSeconds值被尊重Pod 会在 Node 的terminationGracePeriod到期之前被预先删除包括带阻塞性 pod disruption budgets 或karpenter.sh/do-not-disrupt注解 的 Pod。考虑如下示例一个terminationGracePeriod为 1 小时的 Node 已被扰动并开始排空。一个带karpenter.sh/do-not-disrupt注解、terminationGracePeriodSeconds为 300 秒5 分钟的 Pod 调度到该节点。如果 Pod 在 Node 开始排空 55 分钟后仍在运行Pod 将被删除以确保其terminationGracePeriodSeconds值被尊重。如果 Pod 的terminationGracePeriodSeconds值超过其所调度 Node 的terminationGracePeriodKarpenter 会优先采用 Node 的terminationGracePeriod。Pod 会在 Node 一开始排空就被删除且无法获得完整的terminationGracePeriodSeconds。NodePool 扰动预算Disruption Budgets你可以通过 NodePool 的spec.disruption.budgets限制 Karpenter 的扰动速率。如果未定义Karpenter 默认使用一条nodes: 10%的预算。预算会考虑因任何原因正在被删除的节点并且只会阻止 Karpenter 通过 drift、emptiness 与 consolidation自愿扰动节点。注意NodePool Disruption Budgets不会阻止Karpenter 终止已过期的节点。Reasons原因Karpenter 允许指定预算是否适用于Drifted、Underutilized或Empty中的任意原因。当预算没有列出 reasons 时视为适用于所有原因。计算某个原因允许的扰动数量时Karpenter 会取列了该原因或未定义 reasons 的预算中的最小值。Nodes节点数计算预算是否会阻止节点扰动时Karpenter 会列出 NodePool 拥有的节点总数减去该 NodePool 当前正在被删除的节点以及NotReady的节点。如果被 Karpenter 或其他进程删除的节点数大于允许的扰动数则该节点的扰动不会继续。如果预算配置为百分比值如20%Karpenter 将允许的扰动数计算为allowed_disruptions roundup(total * percentage) - total_deleting - total_notready。如果定义为非百分比值Karpenter 直接将其作为静态上限non_percentage_value - total_deleting - total_notready。对于 NodePool 中的多条预算Karpenter 取各预算的最小值最严格。例如以下包含三条预算的 NodePool 定义了如下需求第一条预算仅允许该 NodePool 拥有的 20% 节点在 empty 或 drifted 时被扰动。例如若 NodePool 拥有 19 个节点从19 * .2 3.8向上取整可扰动 4 个 empty 或 drifted 节点。第二条预算作为第一条的上限当节点超过 25 个时仅允许 5 次扰动。最后一条预算仅在一天的前 10 分钟阻止扰动0 次扰动被允许且仅适用于 underutilized 节点。apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: default spec: disruption: consolidationPolicy: WhenEmptyOrUnderutilized budgets: - nodes: 20% reasons: - Empty - Drifted - nodes: 5 - nodes: 0 schedule: daily duration: 10m reasons: - UnderutilizedSchedule调度Schedule 是一个 cron 调度。通常 cron 语法是五个空格分隔的值选项如下并支持yearly、monthly、weekly、daily、hourly等特殊宏。请参考 Kubernetes 文档 了解 cron 语法的更多信息。目前不支持时区调度始终为 UTC。# ┌───────────── minute (0 - 59) # │ ┌───────────── hour (0 - 23) # │ │ ┌───────────── day of the month (1 - 31) # │ │ │ ┌───────────── month (1 - 12) # │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday; # │ │ │ │ │ 7 is also Sunday on some systems) # │ │ │ │ │ OR sun, mon, tue, wed, thu, fri, sat # │ │ │ │ │ # * * * * *Duration时长Duration 支持分钟和小时的复合时长如10h5m、30m或160h。由于 cron 语法不接受小于分钟的计量单位用户只能定义分钟或小时。注意Duration 与 Schedule 必须一起定义。省略时预算始终生效。定义后schedule 决定预算开始执行的起点duration 决定从该起点起预算被执行多久。Pod 级控制Pod-Level Controls带阻塞性 PDB 的 Pod 不会被 Termination Controller 驱逐也不会被纳入自愿扰动动作的考虑范围。当一个节点上的多个 Pod 有不同的 PDB 时所有 PDB 都不阻塞Karpenter 才能自愿扰动该节点。这会产生复杂的驱逐场景如果一个 Pod 匹配多个 PDB通过 label selector则所有这些 PDB 都必须允许扰动当同一节点上的不同 Pod 属于不同 PDB 时所有 PDB 必须同时允许驱逐单个阻塞性 PDB 就可以阻止整个节点被自愿扰动。例如考虑一个具有以下 Pod 与 PDB 的节点Pod A匹配 PDB-1maxUnavailable: 0与 PDB-2maxUnavailable: 1Pod B匹配 PDB-3minAvailable: 100%Pod C无 PDB在此场景中Karpenter 无法自愿扰动该节点因为Pod A 被 PDB-1 阻塞尽管 PDB-2 允许扰动Pod B 被 PDB-3 的 100% 可用性要求阻塞。如该示例所示影响节点的 PDB 越多Karpenter 就越难找到执行自愿扰动动作的机会。其次可以通过给 Pod 添加karpenter.sh/do-not-disrupt注解来阻止 Karpenter 自愿扰动和排空该 Pod。该注解支持两种格式格式示例行为布尔值karpenter.sh/do-not-disrupt: true提供永久的扰动保护时长Go duration 字符串karpenter.sh/do-not-disrupt: 30m在 Pod 开始运行后的指定时长内提供基于时间的保护注意如果指定了无效的时长该注解会被忽略并会在 Pod 上发出事件提示时长格式无效。你可以将此注解视为单个 Pod 的阻塞性 PDB它在永久布尔格式或时长未到期期间时长格式处于激活状态。这有以下后果带有激活的karpenter.sh/do-not-disruptPod 的节点会被排除在 Consolidation 之外并有条件地被排除在 Drift 之外。如果节点所属 NodeClaim 配置了terminationGracePeriod它仍可通过 drift 被扰动。与带阻塞性 PDB 的 Pod 一样带激活的karpenter.sh/do-not-disrupt注解的 Pod不会被 Termination Controller 优雅驱逐。Karpenter 无法完成节点终止直到满足以下条件之一所有带karpenter.sh/do-not-disrupt注解的 Pod 被移除或其注解变为非激活时长已到期所有带karpenter.sh/do-not-disrupt注解的 Pod 已进入终态Succeeded或Failed所属 NodeClaim 的terminationGracePeriod已到期。该注解在仓库中的使用可见于 test/suites/drift/suite_test.go集成测试会在 Pod 上设置与移除karpenter.sh/do-not-disrupt注解验证 Drift 行为是否按预期受到抑制或恢复。示例永久保护——适用于希望从头到尾运行而不被打断的 Pod例如不想被打断的交互式游戏或被打断就需要重来的长时批处理任务如机器学习任务apiVersion: apps/v1 kind: Deployment spec: template: metadata: annotations: karpenter.sh/do-not-disrupt: true基于时长的保护——适用于预期运行一段时间、到期后扰动可被接受的 Pod。对集群管理员而言这有助于确保长时运行或行为异常的应用与任务不会阻塞 drift 或 consolidation 等集群操作apiVersion: apps/v1 kind: Deployment spec: template: metadata: annotations: # Protect for 30 minutes after pod starts running karpenter.sh/do-not-disrupt: 30m注意karpenter.sh/do-not-disrupt注解不会将节点排除在强制扰动方法之外Expiration、Interruption、Node Repair 以及手动删除如kubectl delete node ...。中断与节点修复对终止时间都有隐式上界而 expiration 与手动终止则没有。可能需要进行人工介入移除带karpenter.sh/do-not-disrupt注解的 Pod 以解除节点终止阻塞。因此如果未同时配置terminationGracePeriod不建议将karpenter.sh/do-not-disrupt注解与expireAfter一起使用。Node 级控制Node-Level Controls你可以通过给 Node 设置karpenter.sh/do-not-disrupt: true注解来阻止 Karpenter 自愿选择扰动某些节点。这将阻止针对该节点的自愿扰动动作。apiVersion: v1 kind: Node metadata: annotations: karpenter.sh/do-not-disrupt: true示例在 NodePool 上禁用扰动要禁用 NodePool 启动的所有节点的扰动可以配置其.spec.disruption.budgets。将预算设置为零个节点将阻止这些节点中的任何一个被纳入自愿扰动考虑apiVersion: karpenter.sh/v1 kind: NodePool metadata: name: default spec: disruption: budgets: - nodes: 0实战配置建议综合以上机制生产环境中的典型组合如下控制扰动激进程度consolidationPolicy: WhenEmpty最保守WhenEmptyOrUnderutilized最激进Balanced居中v1.14 起可用配合karpenter_consolidation_score指标观察打分决策为临时性负载留出稳定窗口设置合适的consolidateAfter如30s或1m避免节点刚启动就被整合强制节点生命周期上限同时配置expireAfter与terminationGracePeriod保证任何情况下节点都能在确定时间内被回收避免卡死节点推高成本按时间窗限速用budgets的scheduledurationUTC cron在业务高峰禁止 drift/consolidation低谷放开保护关键 Pod对无法容忍重启的 Pod 使用karpenter.sh/do-not-disrupt: true对需要时间窗口的批处理任务使用时长格式保障关键更新不被阻塞为 NodePool 配置terminationGracePeriod使 AMI 修复类漂移在关键节点上仍可执行。所有配置均以 NodePool 的spec.disruption块为中心完整 API 定义可参考 NodePool CRD 清单 与 NodeClaim CRD 清单结合 v1.14 概念文档 中关于 NodePool 的章节即可精确控制 Karpenter 在何时、以多快速度、以何种方式重组你的节点。【免费下载链接】karpenter-provider-awsKarpenter is a Kubernetes Node Autoscaler built for flexibility, performance, and simplicity.项目地址: https://gitcode.com/GitHub_Trending/ka/karpenter-provider-aws创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考