K8s 亲和性和非亲和性(Affinity)

Posted catoop

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了K8s 亲和性和非亲和性(Affinity)相关的知识,希望对你有一定的参考价值。

概念

关于 K8S 对 Pod 的调度,通常情况下Pod被分配到哪些Node是不需要我们操心的,这个过程会由scheduler自动实现。但有时,我们需要让Pod按照我们的预想运行在Node上(例如某些应用 “必须/或者尽量” 跑在具有SSD存储的节点上,有些彼此相关的Pod应用应该跑在同一个节点上)。为此,k8s为我们提供了这样的策略,我们可以通过使用 “亲和性/非亲和性” 制定一些规则来实现我们的需求。

亲和性调度可以分成软策略和硬策略两种方式:

  • 硬策略:可以理解为必须,就是如果没有满足条件的节点的话,就不断重试直到满足条件为止。对应的配置规则为 requiredDuringSchedulingIgnoredDuringExecution
  • 软策略:可以理解为尽量,就是如果现在没有满足调度要求的节点的话,pod就会忽略这条规则,继续完成调度的过程,说白了就是满足条件最好了,没有的话也无所谓。对应的配置规则为 preferredDuringSchedulingIgnoredDuringExecution

亲和性的配置规则分为 Node亲和性、Pod亲和性、Pod反亲和性

  • nodeAffinity :节点亲和性,用来控制 Pod 要部署在哪些节点上,以及不能部署在哪些节点上的,这个是 Pod 与 Node 之间匹配规则的。
  • podAffinity :pod 亲和性,这个是 Pod 与 Pod 之间匹配规则的。
  • podAntiAffinity :pod 反亲和性,与 podAffinity 相反。
  1. 这个亲和性看起来和一直使用的nodeSelector 作用比较重叠,但是你会发现它更的控制更为细致且概念更优。据说官方将会在后续的版本中废除 nodeSelector,故建议大家使用使用亲和性策略。
  2. 节点亲和性相较于 nodeSelector 在调度方式上,有几点增强:① 更多的表达式支持,不仅仅是ADD和精确匹配;② 可以设置soft/preference的调度策略,而不是刚性的要求;③ 可以通过Pod的标签进行调度约束,不仅仅是Node的标签。
  3. podAffinity 处理 Pod 和 Pod 在一起的规则,podAntiAffinity 处理的是 Pod 和 Pod 不能在一起的规则。它俩处理的是Kubernetes集群内部Pod和Pod之间的关系。
  4. 所有规则终究还是以 Label 为元数据的。
AFFINITY SELECTORREQUIREMENTS METREQUIREMENTS NOT METREQUIREMENTS LOST
requiredDuringSchedulingIgnoredDuringExecutionRuns FailsKeepsRunning
preferredDuringSchedulingIgnoredDuringExecutionRuns RunsKeepsRunning
(un-implemented) requiredDuringSchedulingRequiredDuringExecutionRunsFailsFails

对于 label 的匹配规则,可选的操作符有:

操作符规则说明
Inlabel 的值在某个列表中
NotInlabel 的值不在某个列表中
Exists某个 label 存在
DoesNotExist某个 label 不存在
Gtlabel 的值大于某个值(字符串比较)
Ltlabel 的值小于某个值(字符串比较)

如果 nodeAffinity 中 nodeSelectorTerms 有多个选项,则节点满足任何一个条件就可以;
如果 matchExpressions 有多个选项,则只有同时满足这些逻辑选项的节点才能运行 Pod。

实例

  • 我们一般通过 Deployment 和 DaemonSet 来部署 Pod,纯粹部署一个 Pod 的情况却不太常见。
  • 在 Deployment 和 DaemonSet 的 yaml 中配置的 template 节点以下的内容,顾名思义就是其预部署的 Pod 的模板,在 template 节点这里配置的规则内容最终都会实际落实到具体 Pod 的 yaml 文件配置上。
  • 所以,网上看到的一些关于亲和性的示例中 kind: Deploymentkind: Pod 其实在具体规则上你可以认为是一样的。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: affinity-test
  labels:
    app: affinity-test
spec:
  replicas: 8
  selector:
    matchLabels:
      app: affinity-test
  template:
    metadata:
      labels:
        app: affinity-test
    spec:
      containers:
      - name: nginx
        image: nginx:1.20.2
        ports:
        - containerPort: 80
          name: nginxweb
      affinity:
        nodeAffinity:  # 作用域:Pod和Node之间
          requiredDuringSchedulingIgnoredDuringExecution:  # Node亲和性-硬策略
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname
                operator: NotIn
                values:
                - node3
          preferredDuringSchedulingIgnoredDuringExecution:  # Node亲和性-软策略
          - weight: 1
            preference:
              matchExpressions:
              - key: customlabel
                operator: In
                values:
                - weblb
        podAffinity:  # 作用域:Pod和Pod之间
          requiredDuringSchedulingIgnoredDuringExecution:  # Pod亲和性-硬策略
          - labelSelector:
              matchExpressions:
              - key: security
                operator: In
                values:
                - security1
            topologyKey: failure-domain.beta.kubernetes.io/zone
        podAntiAffinity:  # 作用域:Pod和Pod之间
          preferredDuringSchedulingIgnoredDuringExecution:  # Pod非亲和性-软策略
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: security
                  operator: In
                  values:
                  - security2
              topologyKey: kubernetes.io/hostname

(END)

以上是关于K8s 亲和性和非亲和性(Affinity)的主要内容,如果未能解决你的问题,请参考以下文章

Linux CPU Affinity

每期一个小窍门: k8s容器亲和性的小例子

每期一个小窍门: k8s容器亲和性的小例子

每期一个小窍门: k8s容器亲和性的小例子

从相亲的角度理解 K8S 的 Node Affinity, Taints 与 Tolerations

Kubernetes——浅聊 Affinity,就这么点东西