更新: Karpenter beta版

Karpenter API 遵循 alpha → beta → stable 的成熟度进程。

从 v0.33.0 版本开始,Karpenter 将仅支持其 v1beta1 API。

从 Alpha 版升级到 Beta 版对 API 进行了重大更改。但从beta版升级到stable版不需要这么大的更改。

从 alpha 版到 beta 版,最重要的是一些API的命名发生改变,例如provisioner

在此版本中,Karpenter 弃用了 Provisioner、AWSNodeTemplateMachine ,同时引入了 NodePool、EC2NodeClassNodeClaim

更新介绍

v1beta1 版本引入了以下新 API,同时弃用了现有 API:

  • karpenter.sh/Provisioner 变为 karpenter.sh/NodePool
  • karpenter.sh/Machine 变为 karpenter.sh/NodeClaim
  • karpenter.k8s.aws/AWSNodeTemplate 变为 karpenter.k8s.aws/EC2NodeClass

让我们看看每项更改以及新的 API 定义是什么样

1. v1alpha5/Provisioner → v1beta1/NodePool

一个Pool是不同实例类型和大小的混合,可参考 https://karpenter.sh/docs/concepts/nodepools/

NodePool 的示例如下所示:

apiVersion: karpenter.sh/v1beta1
kind: NodePool
...
spec:
  template:
    metadata:
      annotations:
        custom-annotation: custom-value
      labels:
        team: team-a
        custom-label: custom-value
    spec:
      nodeClassRef:
        name: default
      requirements:
      - key: karpenter.k8s.aws/instance-category
        operator: In
        values: ["c", "m", "r"]
      ...
      kubelet:
        systemReserved:
          cpu: 100m
          memory: 100Mi
          ephemeral-storage: 1Gi
        maxPods: 20
  disruption:
    expireAfter: 360h
    consolidationPolicy: WhenUnderutilized

我们注意到一个名为disruption的新定义,它其实将alpha版本的ttlSecondsAfterEmpty, ttlSecondsUntilExipred, consolidation.enabled进行了归类,一起放到这个字段了

如果yaml里没有设置这个字段,Karpenter会使用以下默认值:

字段 默认值
spec.disruption.consolidationPolicy WhenUnderutilized
spec.disruption.expireAfter 720h

2. v1alpha1/AWSNodeTemplate → v1beta1/EC2NodeClass

Karpenterspec.instanceProfile字段已从 EC2NodeClass 中删除,取而代之的是该spec.role字段。Karpenter 现在会根据指定的角色在您的 EC2NodeClass 中自动生成实例配置文件。

EC2NodeClass 示例如下:

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: Bottlerocket
  role: KarpenterNodeRole-karpenter-demo
  subnetSelectorTerms:
  - tags:
      karpenter.sh/discovery: karpenter-demo
  securityGroupSelectorTerms:
  - tags:
      karpenter.sh/discovery: karpenter-demo
  tags:
    test-tag: test-value

3. 标签变更

Karpenter v1beta1 对标签karpenter.sh/do-not-evictkarpenter.sh/do-not-consolidate进行了替换,这两个标签已被弃用并统一在单一标签——karpenter.sh/do-not-disrupt。它应用于 Pod 和节点,防止 Karpenter 执行node disruption和 Pod 驱逐。

4. NodeClass 中 AMI、子网和安全组的更灵活选择

现在AMI selector、subnetGroup、securityGroup Selector使用OR(以前是AND)逻辑进行选择,例如:

amiSelectorTerms:
- name: my-name1
  owner: 123456789
- name: my-name2
  owner: 123456789
- name: my-name1
  owner: amazon
- name: my-name2
  owner: amazon
  
securityGroupSelectorTerms:
- id: abc-123
  name: default-security-group # Not the same as the name tag
  tags:
    key: value
# Selector Terms are ORed
- id: abc-123
  name: custom-security-group # Not the same as the name tag
  tags:
    key: value

5. 默认启用Drift检测

从下一个版本(v0.33.0)开始,Drift功能将默认启用。如果您不指定 Drift featureGate,则假定该功能已启用。

如何从alpha迁移到beta

从上面的介绍可以看到,beta版本对Karpenter的一些API进行了更改,所以一些IAM Policy也需要进行更新,新的policy可见: https://github.com/aws/karpenter/blob/main/website/content/en/v0.32/getting-started/getting-started-with-karpenter/cloudformation.yaml (例如将karpenter.sh/nodepool Tag更新为karpenter.sh/provisioner-name

API迁移

要从 alpha 过渡到新的 v1beta1 API,应该首先安装新的 v1beta1 CRD。随后,需要为 Provisioners 和 AWSNodeTemplates 生成每个 alpha API 的 beta 版本。

可以借助工具karpenter-convert ,它是一个命令行实用程序,旨在简化 NodePool 和 EC2NodeClass 对象的创建。

  1. 安装命令行实用程序:go install github.com/aws/karpenter/tools/karpenter-convert/cmd/karpenter-convert@latest
  2. 将每个配置程序迁移到 NodePool 中:karpenter-convert -f provisioner.yaml > nodepool.yaml
  3. 将每个 AWSNodeTemplate 迁移到 EC2NodeClass:karpenter-convert -f nodetemplate.yaml > nodeclass.yaml
  4. 对于该工具生成的每个 EC2NodeClass,您需要手动指定 AWS 角色。该工具留下一个占位符$KARPENTER_NODE_ROLE,您需要将其替换为您的实际角色名称。

对于每个 Provisioner 资源,您需要决定是一次滚动一个节点还是一次性滚动所有 Provisioner 节点。以下部分提供了详细的分步指南:

启用Drift后的Rolling Update

启用漂移后,对于集群中的每个 Provisioner,执行以下操作:

  1. 将您的 alpha CRD 迁移到 v1beta1
  2. 向旧的 Provisioner 添加污点,例如karpenter.sh/legacy=true:NoSchedule
  3. Karpenter Drift将该 Provisioner 拥有的所有机器/节点标记为漂移
  4. Karpenter 在新的 NodePool 资源中,创建出来新的的节点

目前,Karpenter 仅支持一次滚动一个节点,这意味着 Karpenter 可能需要一些时间才能完全滚动单个 Provisioner 下的所有节点

强制删除

对于集群中的每个 Provisioner,执行以下操作:

  1. 在集群中创建 NodePool/EC2NodeClass,该 NodePool/EC2NodeClass 相当于 v1alpha5中的 Provisioner/AWSNodeTemplate

  2. 删除旧的 Provisioner

    kubectl delete provisioner <provisioner-name> --cascade=foreground
    

Karpenter 删除 Provisioner 拥有的每个节点,同时drain所有节点,并在节点进入Drain状态后为pending pod启动新的节点

手动Rolling Update

对于集群中的每个 Provisioner,执行以下操作:

  1. 在集群中创建 NodePool/EC2NodeClass
  2. 向旧的 Provisioner 添加污点,例如karpenter.sh/legacy=true:NoSchedule
  3. 通过运行以下命令,一个一个地删除 Provisioner 拥有的节点kubectl delete node <node-name>