Pod Density控制

Pod 密度是每个节点的 Pod 数量,Karpenter 还提供 pod density control(Pod 密度控制),允许设置在节点上调度的 Pod 数量。 Kubernetes 默认限制每个节点 110 个 pod,在EKS上Pod 数量还受实例类型的限制。

Pod 密度控制方式

  • Static Pod Density - 在Provisioner配置 .spec.kubeletConfiguration ,指定 maxPods 。 此Provisioner生成的所有节点都将在其 kubelet 上设置此 maxPods 值,并将在调度期间考虑此值。
  • Dynamic Pod Densisty - 设置应在节点的每个 CPU 核心上调度的 pod 数量。 这是通过使用 podsPerCore参数来完成的,该参数指定每个 CPU 核心的 pod 目标数量。

Static Pod Density

默认情况下,EKS根据实例大小决定了节点能创建的最大pod数量。如果想调整这个值,可以调整spec.kubeletConfigurationmaxPods值,这个参数会由Karpenter传给kubelet,在kubelet上设置--max-pods参数。通过提高小机型的pod密度,可以达到成本优化的效果,每个节点上能跑更多的pod。

在下面的例子中,我们将为c5.2xlarge设置Pod密度,让它最多跑六个Pod(它有8个CPU,如果pod需要1个cpu的话能跑8个)

注意设置Static Pod Density的时候很容易遇到一个坑——忽略Daemenset的数量。比如我们node上有六个DaemonSet在跑,那么应用直接启动不起来,因为一启动就会超出maxPods的值

我们将这样设置:

  kubeletConfiguration:
    maxPods: 6

先删除之前创建的资源:

kubectl delete deployment inflate
kubectl delete provisioners.karpenter.sh default
kubectl delete awsnodetemplates.karpenter.k8s.aws default

部署Provisioner和Node Template,注意在spec.kubeletConfiguration部分指定了最大Pod数量:

mkdir ~/environment/karpenter
cd ~/environment/karpenter
cat <<EoF> static.yaml
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  providerRef:
    name: default
  ttlSecondsAfterEmpty: 30

  labels:
    eks-immersion-team: my-team

  requirements:
    - key: "node.kubernetes.io/instance-type"
      operator: In
      values: ["c5.2xlarge"]
    - 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"]
  kubeletConfiguration:
    maxPods: 6

---
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: default
spec:
  subnetSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  securityGroupSelector:
    aws:eks:cluster-name: ${CLUSTER_NAME}
  tags:
    managed-by: "karpenter"
    intent: "apps"
EoF

kubectl apply -f static.yaml

创建应用:

cd ~/environment/karpenter
cat <<EoF> static-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 3  # 这里是因为我们Pod上跑了4个DaemonSet,可以继续将这个值调大
  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 static-deploy.yaml

由于我们每个节点上要跑4个DaemonSet,maxPods设置的为6,所以此时即使要创建三个replica也需要两台机器,一台上跑2个replica,另一台跑1个:

image-20231028215116656

Dynamic Pod Density

可以设置每个CPU核上运行Pod的数量,从而更好的利用CPU资源。Karpenter把这个值传给kubelet的--pods-per-core参数来完成设置。例如如果将其设置为5,Karpenter会尝试每个CPU核上运行5个pod,所以如果你有8核CPU,Karpenter将在上面部署40个Pod:

  kubeletConfiguration:
    podsPerCore: 5

首先清理之前创建的资源:

kubectl delete deployment inflate
kubectl delete provisioners.karpenter.sh default
kubectl delete awsnodetemplates.karpenter.k8s.aws default

部署Provisioner和Node template,为了设置每个CPU核上最大Pod数量,在spec.kubeletConfiguration中指定了podsPerCore

mkdir -p ~/environment/karpenter
cd ~/environment/karpenter
cat <<EoF> dynamic.yaml
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: default
spec:
  providerRef:
    name: default
  ttlSecondsAfterEmpty: 30

  labels:
    eks-immersion-team: my-team

  requirements:
    - key: "node.kubernetes.io/instance-type"
      operator: In
      values: ["c6a.2xlarge"]
    - 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"]
  kubeletConfiguration:
    podsPerCore: 5

---
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: default
spec:
  subnetSelector:
    alpha.eksctl.io/cluster-name: ${CLUSTER_NAME}
  securityGroupSelector:
    aws:eks:cluster-name: ${CLUSTER_NAME}
  tags:
    managed-by: "karpenter"
    intent: "apps"
EoF

kubectl apply -f dynamic.yaml

部署应用

我们创建inflate应用,并让它有45个replica:

cd ~/environment/karpenter
cat <<EoF> dynamic-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
spec:
  replicas: 45
  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: 0.1
      nodeSelector:
        eks-immersion-team: my-team
EoF

kubectl apply -f dynamic-deploy.yaml

c6a.2xlarge具有8个CPU,我们将cpu request设置为0.1,理想情况它上面应该能跑80个pod。但是因为设置了podsPerCore = 5,所以它实际最多只能跑40个pod:

image-20231028221237063