节点池 - NodePool

让我们先从基本配置开始,看看 Karpenter 在幕后是如何工作的。

什么是节点池?

  • Karpenter NodePool是一种 Kubernetes 自定义资源,可以让我们配置 Karpenter 在集群中的行为。

节点池的作用是什么?

  • Karpenter 的工作是添加节点来处理无法调度的 pod,在这些节点上调度 pod,并在不需要时删除这些节点。
  • 要配置 Karpenter,我们需要创建NodePool,定义 Karpenter 如何管理无法调度的 pod 和过期节点。
  • 节点池设置了 Karpenter 可以创建的节点以及可以在这些节点上运行的 pod 的约束条件。

创建NodePool是必要的,Karpenter 在至少配置了一个NodePool之前,将保持非活动状态

什么是 EC2NodeClass?

  • 每个节点池都必须使用 spec.template.spec.nodeClassRef 引用一个 EC2NodeClass。

部署NodePool

让我们创建一个NodePool和NodeClass,我们在下面的NodePool中指定的一些详细信息如下:

  • consolidateAfter: 由于利用率低而缩减节点的等待时间(秒)
    • 在下面的示例中,如果 Karpenter 发现利用率低,节点将在 30 秒内缩减
  • requirements: 约束配置节点参数的要求。这些要求与 pod.spec.affinity.nodeAffinity 规则结合使用。
    • 在下面的示例中,我们要求配置实例类别为 [“c”、“m”、“r”]、架构为 “amd64” 和容量类型为 “on-demand” 的节点。
  • labels: 标签是应用于所有节点的任意键值对
    • 在下面的示例中,我们有一个标签 “eks-immersion-team: my-team”。我们将使用它作为 nodelSelector,以确保我们的应用程序只能在具有此标签的节点上部署。
  • nodeClassRef: 引用特定于云提供商的自定义资源。此引用将特定于云提供商
    • 在下面的示例中,我们引用了默认的nodeClass
  • limits: 集群总大小的资源限制。 Karpenter 在达到限制时停止创建新实例。
    • 在下面的示例中,我们添加了 CPU 限制为 “10”

如果我们使用自己的方式创建 EKS 集群,请确保相应地更改下面节点类规范中的 “subnetSelector” 和 “securityGroupSelector” 的值。

mkdir ~/environment/karpenter
cd ~/environment/karpenter
cat <<EoF> basic.yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: default
spec:
  disruption:
    consolidateAfter: 30s
    consolidationPolicy: WhenEmpty
    expireAfter: Never
  limits:
    cpu: "10"
  template:
    metadata:
        labels:
         eks-immersion-team: my-team
    spec:
      nodeClassRef:
        name: default
      requirements:
      - key: karpenter.k8s.aws/instance-category
        operator: In
        values: ["c", "m", "r"]
      - key: kubernetes.io/arch
        operator: In
        values: ["amd64"]
      - key: karpenter.sh/capacity-type # If not included, the webhook for the AWS cloud provider will default to on-demand
        operator: In
        values: ["on-demand"]
      - key: kubernetes.io/os
        operator: In
        values: ["linux"]

---
apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: AL2
  role: karpenterNodeRole-$CLUSTER_NAME
  securityGroupSelectorTerms:
  - tags:
      alpha.eksctl.io/cluster-name: $CLUSTER_NAME
  subnetSelectorTerms:
  - tags:
      alpha.eksctl.io/cluster-name: $CLUSTER_NAME
  tags:
    intent: apps
    managed-by: karpenter
EoF

kubectl apply -f basic.yaml

部署后,看到:

image-20240803155045776

部署应用测试

Karpenter 提供了一种自动扩展机制,可以根据未调度的 pod 来扩展节点。当在 Kubernetes 中创建一个 pod 时,Kubernetes 调度器负责将该 pod 调度到集群中的一个节点上。如果没有可用的节点可以容纳该 pod,它将保持在 Pending 状态,直到有节点可用。Karpenter 可以监控集群中的pending pod,并通过创建新节点来扩展集群以满足 pod 的需求。在本示例中,我们将看到当我们扩展应用程序 pod 并且它们处于pending状态时,Karpenter 如何创建新节点。

部署应用程序

让我们部署我们的第一个应用程序,副本数为零。

  • 容器资源请求为"1” CPU。
  • 我们在创建 NodePool 时添加了标签 “eks-immersion-team: my-team”。现在在 pod spec中添加 nodeSelector 可确保pending的 pod 始终落在 Karpenter NodePool 创建的实例上。
cd ~/environment/karpenter
cat <<EoF> basic-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 0
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      terminationGracePeriodSeconds: 0
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
          resources:
            requests:
              cpu: 1
      nodeSelector:
        eks-immersion-team: my-team
EoF

kubectl apply -f basic-deploy.yaml
deployment.apps/inflate created

让我们先看看当前 EKS 集群中有多少个节点。打开kube ops view, 我们可以看到有两个节点,这些节点是在 EKS 集群创建设置过程中创建的:

image-20240803160840498

扩展应用程序

现在,让我们将replica从 0 扩展到 5 个

kubectl scale deployment inflate --replicas 5
deployment.apps/inflate scaled

image-20240803160926626

检查 Karpenter 的日志(我们应该在 karpenter 控制器 pod 的日志中看到此日志)。

kubectl -n karpenter logs -l app.kubernetes.io/name=karpenter

我们应该在日志中看到 launched nodeclaim 消息

image-20240803161149159

在 kube ops view中,我们将看到 Karpenter 创建了一个 c6a.2xlarge (具有 8 个 vCPU) 的节点。

image-20240803161040781

检查NodePool 管理的节点:

kubectl get nodes -l eks-immersion-team=my-team

image-20240803161240903

可以看到有七个 pod 落在这个新节点上。 还可以检查 Karpenter 创建的节点的元数据:

kubectl get node -l eks-immersion-team=my-team -o json | jq -r '.items[0].metadata.labels'

image-20240803161331549