3. 基于 NodePool 的实例类型约束配置

基于 NodePool 的实例类型约束配置 学习卡片

NodePool requirements 的约束语义

NodePool 的 spec.template.spec.requirements 是一组键值约束,Karpenter 在调度待处理 Pod 时,会先按这些约束过滤出允许的实例类型集合,再在该集合内按价格与容量做选择。约束不是“指定某一种实例”,而是“划定可选范围”。

  • node.kubernetes.io/instance-type:直接枚举实例类型,如 m5.large、c5.xlarge。
  • karpenter.k8s.aws/instance-family:按实例族约束,如 m5、c5、t3。
  • karpenter.k8s.aws/instance-size:按规格约束,如 large、xlarge、2xlarge。
  • karpenter.k8s.aws/instance-category:按类别约束,如 c(计算优化)、m(通用)、r(内存优化)。
  • karpenter.sh/capacity-type:按容量类型约束,如 on-demand、spot。
  • kubernetes.io/arch:按 CPU 架构约束,如 amd64、arm64。

每个 requirement 由 key、operator(In、NotIn、Exists、DoesNotExist)和 values 组成。多个 requirement 之间是逻辑与关系,同一 requirement 的多个 value 之间是逻辑或关系。

NodePool requirements instance-family In [m5, c5, t3] instance-size In [large, xlarge] capacity-type In [on-demand] arch In [amd64] instance-category In [c, m] 多个 requirement 之间为逻辑与 同一 requirement 的 values 为逻辑或 过滤 允许实例类型集合 m5.large m5.xlarge c5.large c5.xlarge t3.large t3.xlarge 共 6 种候选 按价格与容量择优 选择 Pod 请求与结果 Pod A cpu: 500m mem: 1Gi Pod B cpu: 2 mem: 4Gi Pod C cpu: 4 mem: 16Gi 选择结果 Pod A → m5.large Pod B → c5.xlarge Pod C → 无匹配 (超出允许规格)

配置示例

以下 NodePool 将可用实例限制在 m5、c5、t3 三个族,规格仅允许 large 和 xlarge,容量类型仅 on-demand,架构仅 amd64:

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: constrained-pool
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-family
          operator: In
          values: ["m5", "c5", "t3"]
        - key: karpenter.k8s.aws/instance-size
          operator: In
          values: ["large", "xlarge"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
  limits:
    cpu: "100"
    memory: "200Gi"
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m

提交不同资源请求的 Pod 并观察选择

创建三个资源请求递增的 Pod,分别观察 Karpenter 选择的实例类型:

# Pod A:小请求
kubectl run pod-a --image=nginx --requests='cpu=500m,memory=1Gi'

# Pod B:中等请求
kubectl run pod-b --image=nginx --requests='cpu=2,memory=4Gi'

# Pod C:大请求,超出允许规格
kubectl run pod-c --image=nginx --requests='cpu=4,memory=16Gi'

查看 Karpenter 为每个 Pod 创建的 NodeClaim 及其选择的实例类型:

kubectl get nodeclaims -o custom-columns=\
NAME:.metadata.name,\
TYPE:.metadata.labels.karpenter\.k8s\.aws/instance-type,\
CPU:.spec.resources.requests.cpu,\
MEMORY:.spec.resources.requests.memory
预期现象:Pod A 和 Pod B 会成功触发节点创建,NodeClaim 的 instance-type 标签落在允许集合内(如 m5.large、c5.xlarge)。Pod C 因请求超出允许规格的最大容量,Karpenter 无法在约束范围内找到匹配实例,Pod 将保持 Pending,事件中会出现类似 no instance type satisfied requirements 的提示。

约束调整与验证

若希望 Pod C 也能被调度,需要放宽 instance-size 约束,加入 2xlarge 或 4xlarge:

kubectl patch nodepool constrained-pool --type=merge -p '
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-size
          operator: In
          values: ["large", "xlarge", "2xlarge", "4xlarge"]
'

调整后再次观察 Pod C 的 NodeClaim,应能看到 Karpenter 从扩展后的集合中选择了满足 4 vCPU / 16 GiB 的实例(如 m5.2xlarge 或 c5.2xlarge)。

注意:放宽约束会扩大候选实例范围,可能引入更高单价的实例。建议结合 limits 字段控制 NodePool 的总资源上限,避免意外扩容到超大规格。同时,instance-size 与 instance-family 的组合约束会显著影响候选数量,约束过窄可能导致 Pod 长期 Pending。

关键验证点

检查项命令通过条件
NodePool 约束生效kubectl get nodepool constrained-pool -o yamlrequirements 字段与预期一致
NodeClaim 实例类型kubectl get nodeclaims -o wideinstance-type 落在允许集合内
Pod 调度状态kubectl get pods -o widePod A/B 为 Running,Pod C 为 Pending
Pending 原因kubectl describe pod pod-c事件提示无匹配实例类型