本文介绍如何为 Azure Kubernetes 服务(AKS)节点自动预配(NAP)节点配置节点中断策略,并详细介绍中断的工作原理,以优化资源利用率和成本效益。
NAP 通过以下方式优化群集:
- 删除或替换未充分利用的节点。
- 合并工作负荷以降低成本。
- 遵守中断预算和维护时间窗口。
- 根据需要提供手动控制。
在您开始之前
节点中断如何适用于 NAP 节点?
Karpenter 对其预配的每个节点和节点声明设置一个 Kubernetes 终结器。 终结器会阻止删除节点对象,而终结控制器在删除底层节点声明之前会对节点施加污点并进行清空。
当节点上的工作负荷缩减时,NAP 使用节点池规范上的中断规则来确定何时以及如何删除这些节点,并可能重新计划工作负荷以提高效率。
节点中断方法
NAP 自动发现符合中断条件的节点,并在需要时启动替换项。 可以通过自动方法(如 Expiration、 合并和 Drift、手动方法或外部系统)触发中断。
过期日期
过期后,可以设置 NAP 节点的最大期限。 节点在达到为节点池 spec.disruption.expireAfter 值指定的年龄后标记为过期和中断。
过期配置示例
以下示例演示如何将 NAP 节点的过期时间设置为 24 小时:
spec:
disruption:
expireAfter: 24h # Expire nodes after 24 hours
Consolidation
NAP 的工作原理是,通过确定何时可以删除节点,因为它们为空或未充分利用,或者节点可以替换为价格较低的变体,从而积极降低群集成本。 此过程称为 合并。 NAP 主要使用合并来删除或替换节点以获得最佳 Pod 位置。
NAP 执行以下类型的合并以优化资源利用率:
- 空节点合并:并行删除任何空节点。
- 多节点合并:删除多个节点,可能启动单个替换。
- 单节点合并:删除任何单个节点,可能启动替换。
可以通过节点池规范中的spec.disruption.consolidationPolicy字段,以及使用WhenEmpty或WhenEmptyOrUnderUtilized设置来触发整合。 还可以设置 consolidateAfter 字段,这是一种基于时间的条件,用于确定 NAP 在发现合并机会后等待的时间,然后再中断节点。
合并配置示例
以下示例演示如何将 NAP 配置为在节点为空时合并节点,并在发现合并机会后等待 30 秒,然后再中断节点:
disruption:
# Describes which types of nodes NAP should consider for consolidation
# `WhenEmptyOrUnderUtilized`: NAP considers all nodes for consolidation and attempts to remove or replace nodes when it discovers that the node is empty or underutilized and could be changed to reduce cost
# `WhenEmpty`: NAP only considers nodes for consolidation that don't contain any workload pods
consolidationPolicy: WhenEmpty
# The amount of time NAP should wait after discovering a consolidation decision
# Currently, you can only set this value when the consolidation policy is `WhenEmpty`
# You can choose to disable consolidation entirely by setting the string value `Never`
consolidateAfter: 30s
Drift
偏移处理对 NodePool/AKSNodeClass 资源的更改。 在 NodeClaimTemplateSpec/AKSNodeClassSpec 中的值会以设置时的相同方式进行反映。 如果关联的 NodeClaimNodePool 中的值与 / 中的值不匹配,则会检测到 AKSNodeClass 偏移为 NodeClaim。 与 Pod 的上游deployment.spec.template关系类似,Karpenter 对关联的NodePool/AKSNodeClass使用NodeClaimTemplateSpec的哈希值进行标注,以检查偏移情况。 Karpenter 在Drifted的以下场景中移除状态条件:
-
Drift功能门未启用,但NodeClaim已发生漂移。 -
NodeClaim没有漂移,但有状态条件。
Karpenter 或云提供商接口可能会发现由更改触发的特殊情况。
偏移的特殊情况
在特殊情况下,偏移可以对应于多个值,并且必须以不同的方式进行处理。 对已解析字段的偏移可能会导致发生偏移但不更改自定义资源定义 (CRD) 的情况,或者 CRD 更改不会导致漂移的情况。
例如,如果NodeClaim具有node.kubernetes.io/instance-type: Standard_D2s_v3,并且要求从node.kubernetes.io/instance-type In [Standard_D2s_v3]变为node.kubernetes.io/instance-type In [Standard_D2s_v3, Standard_D4s_v3],NodeClaim不会偏移,因为其值仍然符合新要求。 相反,如果 NodeClaim 使用一个 NodeClaimimageFamily,但 spec.imageFamily 字段发生更改,则 Karpenter 会检测到 NodeClaim 已"漂移",并更新节点以符合该规范。
重要
Karpenter 监视子网配置更改,并在vnetSubnetID中AKSNodeClass被修改时检测漂移。 在管理自定义网络配置时,理解此行为至关重要。 有关详细信息,请参阅 子网偏移行为。
有关详细信息,请参阅 Drift Design。
终止宽限期
可以使用节点池规范中的字段为 NAP 节点 spec.template.spec.terminationGracePeriod 设置终止宽限期。 此设置允许你配置 Karpenter 等待 Pod 正常终止的时间。 此设置优先于 Pod 的 terminationGracePeriodSeconds 并绕过 PodDisruptionBudgets 和 karpenter.sh/do-not-disrupt 注释。
示例终止宽限期配置
以下示例演示如何为 NAP 节点设置 30 秒的终止宽限期:
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
terminationGracePeriod: 30s
中断预算
通过修改节点池规范中的 spec.disruption.budgets 字段,可以对 Karpenter 的中断进行速率限制。 如果您不定义此设置,Karpenter 的默认设置是一个预算nodes: 10%。 预算考虑因任何原因而删除的节点,它们只会阻止 Karpenter 通过过期、偏移、空虚和合并进行自愿中断。
在计算预算是否会阻止节点受干扰时,Karpenter 将计算节点池拥有的总节点数,然后减去正在删除的节点和节点 NotReady。 如果预算配置了一个百分比值(例如20%),Karpenter 会将允许的中断次数计算为 allowed_disruptions = roundup(total * percentage) - total_deleting - total_notready。 对于节点池中的多个预算,Karpenter 采用每个预算的最低(最严格)值。
计划和持续时间字段
使用预算时,可以选择设置 schedule 和 duration 字段来创建基于时间的预算。 通过这些字段,可以定义维护时段或更严格的中断限制时的特定时间范围。
-
“计划”使用带有特殊宏的 cron 作业语法,例如 、
@yearly、@monthly、@weekly、@daily@hourly。 -
“持续时间”允许复合持续时间,例如 、
10h5m或30m160h。 “持续时间”和“计划”必须一起定义。
计划和持续时间示例
维护时段预算
在工作时间防止中断:
budgets:
- nodes: "0"
schedule: "0 9 * * 1-5" # 9 AM Monday-Friday
duration: 8h # For 8 hours
仅限周末的中断
仅在周末允许中断:
budgets:
- nodes: "50%"
schedule: "0 0 * * 6" # Saturday midnight
duration: 48h # All weekend
- nodes: "0" # Block all other times
逐步推出预算
允许增加中断率:
budgets:
- nodes: "1"
schedule: "0 2 * * *" # 2 AM daily
duration: 2h
- nodes: "3"
schedule: "0 4 * * *" # 4 AM daily
duration: 4h
预算配置示例
以下 NodePool 规范配置了三个预算:
- 第一个预算允许节点池中 20% 的节点同时发生中断。
- 第二个预算充当上限,仅允许在超过 25 个节点时发生五次中断。
- 最近的预算会防止每天的前10分钟内的中断。
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
expireAfter: 720h # 30 * 24h = 720h
budgets:
- nodes: "20%" # Allow 20% of nodes to be disrupted
- nodes: "5" # Cap at maximum 5 nodes
- nodes: "0" # Block all disruptions during maintenance window
schedule: "@daily" # Scheduled daily
duration: 10m # Duration of 10 minutes
手动节点中断
可以使用kubectl手动中断 NAP 节点,或通过删除NodePool资源来实现这种中断。
使用 kubectl 删除节点
可以使用命令手动删除节点 kubectl delete node 。 可以使用标签删除特定节点、所有 NAP 托管节点或来自特定节点池的节点。
# Delete a specific node
kubectl delete node $NODE_NAME
# Delete all NAP-managed nodes
kubectl delete nodes -l karpenter.sh/nodepool
# Delete nodes from a specific nodepool
kubectl delete nodes -l karpenter.sh/nodepool=$NODEPOOL_NAME
删除 NodePool 资源
NodePool 通过所有者引用拥有 NodeClaims。 在删除关联的 NodePool 时,NAP 通过级联删除来平稳地终止节点。
通过批注控制中断
可以使用注释阻断或禁用特定 Pod、节点或整个节点池的干扰。
Pod 控件
通过设置 karpenter.sh/do-not-disrupt: "true" 注释来阻止 NAP 中断某些 Pod:
apiVersion: apps/v1
kind: Deployment
spec:
template:
metadata:
annotations:
karpenter.sh/do-not-disrupt: "true"
此批注可防止过期、合并和偏移的自愿中断。 但是,它无法阻止外部系统引起的干扰,也无法通过kubectl或NodePool删除来阻止手动干扰。
节点控件
阻止 NAP 中断特定节点:
apiVersion: v1
kind: Node
metadata:
annotations:
karpenter.sh/do-not-disrupt: "true"
节点池控件
禁用 NodePool中所有节点的故障。
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
metadata:
annotations:
karpenter.sh/do-not-disrupt: "true"
后续步骤
有关 AKS 中的节点自动预配的详细信息,请参阅以下文章: