k8s 亲和 & 反亲和介绍

文章内容来自k8s文档翻译以及个人理解和实际使用过程中的实践内容
参考:https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/

目录

pod调度到node(nodeSelector)

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector: # 匹配节点的label,多个label之间为‘与’关系
    disktype: ssd 

节点内置label: Well-Known Labels, Annotations and

亲和与反亲和(Affinity and anti-affinity)

节点亲和

节点亲和在概念上和nodeSelector类似–根据node的label来约束pod可以调度到哪些节点。

有两种类型的节点亲和

硬亲和 requiredDuringSchedulingIgnoredDuringExecution

软亲和 preferredDuringSchedulingIgnoredDuringExecution

硬亲和指定将pod调度到节点上必须满足的规则(类似于nodeelector,但语法更形象)
软亲和指定首选项,调度器将尝试执行但没有保证。
名称中IgnoredDuringExecution的部分表示:如果pod根据亲和规则被调度到某节点运行之后,此时node上的labels发生变化(不再符合pod上的亲和性规则)不会对在该节点上运行的pod造成影响。
在未来,k8s计划提供requireduringschedulingrequireduringexecution,除了从不再符合pod亲和规则的节点上会自动驱逐pod,其他功能和requireduringschedulingignoredduringexecution一致。

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/e2e-az-name
            operator: In
            values:
            - e2e-az1
            - e2e-az2
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: another-node-label-key
            operator: In
            values:
            - another-node-label-value
  containers:
  - name: with-node-affinity
    image: k8s.gcr.io/pause:2.0

查询表达式中可以使用的操作符有:In, NotIn, Exists, DoesNotExist, Gt, Lt等。操作符为In, NotIn时可以有多个值,Gt, Lt只能有且必须有一个值,Exists, DoesNotExist值必须为空。

可以使用NotInDoesNotExist来实现节点反亲和行为,或使用node taints驱逐特定节点上的Pod。

如果同时指定了nodeSelectornodeAffinity,则必须同时满足这两个条件,才能将pod调度到候选节点上

requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms数组的多个元素之间为的关系

requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[i].matchExpressions数组的多个元素之间为的关系

preferredDuringSchedulingIgnoredDuringExecution数组的多个元素之间为的关系

preferredDuringSchedulingIgnoredDuringExecution中的weight字段的范围是1-100。对于每个满足所有调度要求的节点(资源需求, requireduringscheduling亲和表达式等等),调度程序就计算preferredDuringSchedulingIgnoredDuringExecution下所有匹配MatchExpressions的条目的weight的总和,然后将此分数与该节点的其他优先级函数的分数合并,优先选择总得分最高的节点。

Node affinity per scheduling profile

FEATURE STATE: Kubernetes v1.20 [beta]

另外可以通过kube-scheduler的multiple-profiles特性来实现不同的亲和策略。即在KubeSchedulerConfiguration的profiles中配置不同调度器的亲和规则

apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration

profiles:
  - schedulerName: default-scheduler
  - schedulerName: foo-scheduler
    pluginConfig:
      - name: NodeAffinity
        args:
          addedAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: scheduler-profile
                  operator: In
                  values:
                  - foo

Pod间亲和 & 反亲和

pod间亲和与反亲和调度算法计算量较大,集群规模越大、节点越调度降速越明显,呈指数级增长。需要在使用此特性时考虑对调度速度的影响。

与节点不同,因为Pod是命名空间(因此Pod上的标签是隐式命名空间),所以Pod标签上的标签选择器必须指定选择器应用于哪些命名空间。若namespaces为空,则默认是和pod的namespace相同。

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        namespaces:
        - ns-1
        - ns-2
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: topology.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: k8s.gcr.io/pause:2.0

查询表达式中可以使用的操作符只有:In, NotIn, Exists, DoesNotExist

pod间亲和与反亲和的调度尺度不一定是以节点区分的,还可能是机架、机房、云服务提供商等拓扑域。
其拓扑域是通过topologyKey字段定义的,这个字段的值是node的一个label的key,针对这个label,拥有相同value的节点属于同一拓扑域,pod亲和调度的时候会以拓扑域为基础,即根据该拓扑域(可能是一个节点、也可能是多个节点)中已存在的pod,判断新的pod应该(或不应该)调度到该拓扑域中的节点上。

原则上,topologyKey可以是任何合法的标签的key。然而,出于性能和安全方面的原因,对topologyKey有一些限制:

  1. pod亲和与反亲和的requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution都不允许topologyKey为空。
  2. pod反亲和的requiredDuringSchedulingIgnoredDuringExecution被引入的admission controllerLimitPodHardAntiAffinityTopology限制,只能是kubernetes.io/hostname,如果想使用自定义的topologyKey您可以修改或禁用掉admission controller。

其他需要注意的点:

节点亲和与pod间亲和为&的关系,即需要同时满足两者或三者。

应当避免多个同时部署的的k8s负载资源pod间亲和配置存在相互依赖关系,如果形成死锁会导致无法成功调度。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐