Kubernetes 高级调度 - Affinity

Kubernetes 高级调度 - Affinity_第1张图片

Author:rab


目录

    • 前言
    • 一、Node 亲和性
      • 1.1 NodeAffinity
        • 1.1.1 Hard Node Affinity
        • 1.1.2 Soft Node Affinity
      • 1.2 NodeAntiAffinity
    • 二、Pod 亲和性
      • 2.1 PodAffinity
        • 2.1.1 Hard Pod Affinity
        • 2.1.2 Soft Pod Affinity
      • 2.2 PodAntiAffinity
    • 总结


前言

Kubernetes 中的 Affinity(亲和性)和 AntiAffinity(反亲和性)是用于 Pod 调度的关键概念,它们允许我们控制 Pod 在集群中的分布以满足不同的需求。这些概念分为两类:NodeAffinity(节点亲和性)和PodAffinity(Pod亲和性),以及它们的反对应概念,NodeAntiAffinity(节点反亲和性)和PodAntiAffinity(Pod反亲和性)。

首先我们要明白:Kubernetes 中的调度策略可以大致分为两种:

  • 全局调度策略:在启动调度器时配置,包括 kubernetes 调度器自带的各种 predicates、priorities 算法。
  • 运行时调度策略:也就是我们本次即将提到的 Affinity 与 AntiAffinity。

接下来,我们将对 Affinity 与 AntiAffinity 分别进行案例分析。

一、Node 亲和性

1.1 NodeAffinity

1、功能

NodeAffinity 允许我们定义 Pod 应该调度到具有特定节点标签或标签选择器匹配的节点上。通过使用 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution 字段,我们可以设置节点亲和性规则,要求或首选 Pod 与特定节点条件匹配。通常用于确保 Pod 在特定类型的节点上运行,以满足硬件、软件或其他特定的要求。

2、案例(片段)

...
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: "gpu"
          operator: In
          values:
          - "true"
...

因此,定义节点亲和性规则有 2 种:硬亲和性(Hard Node Affinity)和软亲和性(Soft Node Affinity)。

  • 硬亲和性(Hard Node Affinity)对应字段:requiredDuringSchedulingIgnoredDuringExecution
  • 软亲和性(Soft Node Affinity)对应字段:preferredDuringSchedulingIgnoredDuringExecution

接下来分别看看这两种亲和性的具体应用。

1.1.1 Hard Node Affinity

1、功能

硬亲和性是一种强制性规则,要求 Pod 只能在满足特定条件的节点上运行。如果硬亲和性规则不满足,Pod 将不被调度,这意味着 Pod 可能无法运行。硬亲和性适用于需要绝对满足特定硬件或软件要求的情况,例如只在带有 GPU 的节点上运行。

2、案例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hard-affinity-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: "gpu"
                operator: In
                values:
                - "true"
      containers:
      - name: my-container
        image: my-image:latest

在这个示例中,我们创建了一个名为 hard-affinity-deployment 的 Deployment 对象。在 Pod 模板中,我们设置了硬亲和性规则,要求 Pod 只能在带有 “gpu=true” 标签的节点上运行,如果没有满足此条件的节点可用,Pod将无法被调度。

这里需要注意的是:在 Pod 资源基于节点亲和性规则调度到某个节点之后,如果节点的标签发生了改变,调度器不会将 Pod对象从该节点上移除,因为该规则仅对新建的Pod对象有效。

1.1.2 Soft Node Affinity

1、功能

软亲和性是一种容忍性规则,它提供了一个首选条件,但不强制要求 Pod 在特定条件下运行。如果条件不满足,Pod 仍然可以被调度到不满足条件的节点上(但它会优先考虑满足条件的节点)。软亲和性适用于需要首选条件,但允许有一定的灵活性的情况。它可以用于提高性能或可用性,但不会阻止 Pod 的调度。

2、案例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: soft-affinity-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: "rack"
                operator: In
                values:
                - "rack-1"
            weight: 50
      containers:
      - name: my-container
        image: my-image:latest

在这个示例中,我们创建了一个名为 soft-affinity-deployment 的 Deployment。在 Pod 模板中,我们设置了软亲和性规则,优先在带有 “rack=rack-1” 标签的节点上运行(且权重为 50,数值越大则权重越高,则越优先匹配)。如果没有满足此条件的节点可用,Pod 仍然可以被调度到其他节点上,但它会优先考虑满足条件的节点。

那 Node 软硬亲和性是否可以结合使用呢?

答案是可以的,我们可以将上面的两个案例联合起来,具体 yaml 文件如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: combined-affinity-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: "gpu"
                operator: In
                values:
                - "true"
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: "rack"
                operator: In
                values:
                - "rack-1"
            weight: 50
      containers:
      - name: my-container
        image: my-image:latest

我们设置了硬亲和性规则和软亲和性规则:

  • 硬亲和性规则要求 Pod 只能在带有 “gpu=true” 标签的节点上运行。如果没有满足此条件的节点可用,Pod 将无法被调度。
  • 软亲和性规则优先在带有 “rack=rack-1” 标签的节点上运行,但如果没有满足此条件的节点可用,Pod仍然可以被调度到其他节点上,但它会优先考虑满足条件的节点。

这个示例演示了如何同时使用硬亲和性和软亲和性规则,以控制 Pod 的调度行为,确保它们在满足硬性要求的节点上运行,并在有多个选择时优先考虑软亲和性要求(从而避免了 Pod 无法调度的问题)。这种配置可以用于更复杂的调度策略,以满足不同的需求。

1.2 NodeAntiAffinity

1、功能

NodeAntiAffinity 允许我们定义 Pod 不应该调度到带有特定节点标签或标签选择器匹配的节点上。通常用于提高容错性,防止相同应用的多个实例在同一节点上运行。应用也很简单,将 yaml 文件中的 nodeAffinity 改为 nodeAntiAffinity 即可,这里不再演示。通常用于提高容错性,防止相同应用的多个实例在同一节点上运行。

2、案例(片段)

...
affinity:
  nodeAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: "app"
          operator: In
          values:
          - "my-app"
...

二、Pod 亲和性

2.1 PodAffinity

1、功能

PodAffinity 允许我们定义 Pod 应该一起调度在相同节点上的规则。同样通过使用 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution字段,我们可以设置 Pod 亲和性规则,要求或首选 Pod 与其他具有特定标签的 Pod 一起调度。通常用于确保相关的服务或应用实例在相同节点上运行,以减少网络延迟或提高性能。

2、案例(片段)

...
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: "gpu"
          operator: In
          values:
          - "true"
...

因此,与 Node 亲和性一样,Pod 亲和性也分为硬性软性

2.1.1 Hard Pod Affinity

1、首先我们要定义一些我们即将规划用于部署服务的 Node 标签

为什么要给节点定义标签?

原因:为了组建拓扑域,让满足要求的 Pod 被调度到你指定的拓扑域节点中。

# node1 节点
kubectl label nodes k8s-node01 zone=www
kubectl label nodes k8s-node01 disk=ssd

# node2 节点
kubectl label nodes k8s-node02 zone=www
kubectl label nodes k8s-node02 disk=hdd

# node3 节点
kubectl label nodes k8s-node03 zone=www-test
kubectl label nodes k8s-node03 disk=hdd

...

2、定义 Pod 亲和性

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hard-affinity-pod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hard-affinity-pod
  template:
    metadata:
      labels:
        app: hard-affinity-pod
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - hard-affinity-pod
              topologyKey: "zone"
      containers:
        - name: my-container
          image: my-image
          ports:
            - containerPort: 80

这里说一下上面案例中 topologyKey 字段:这里会涉及到拓扑域(Topology Domain)的概念。

topologyKey 是亲和性和反亲和性中的一个关键字段,用于定义节点的拓扑域(Topology Domain)。拓扑域是指 Kubernetes 集群中的节点分组,可以根据节点的标签或其他属性进行定义。常见的拓扑域包括节点所在的区域(Region)、可用区(Availability Zone)或机架(Rack)等。

说白了,若多个 Node 节点具有相同的标签信息(即 Node 节点标签键/值均相同),则表示这些 Node 节点就在同一拓扑域。

因此,在上述示例中,我们定义了一个 Deployment 资源,其中 Pod 具有硬亲和性。并指定了拓扑域为 zone,这意味着只有满足 Pod 标签为 app: hard-affinity-pod 的 Pod 才会被调度到 zone 域中的节点上(不满足要求则无法调度)。那 zone 域中有哪些节点呢?我们说了,根据 Node 节点标签来划分,很明显,zone 域中的节点有 k8s-node01k8s-node02

2.1.2 Soft Pod Affinity
apiVersion: apps/v1
kind: Deployment
metadata:
  name: soft-affinity-pod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: soft-affinity-pod
  template:
    metadata:
      labels:
        app: soft-affinity-pod
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: app
                      operator: In
                      values:
                        - soft-affinity-pod
                topologyKey: "disk"
      containers:
        - name: my-container
          image: my-image
          ports:
            - containerPort: 80

与 Node 软亲和性类似,满足 Pod 标签为 app: hard-affinity-pod 的 Pod 会优先被调度到 disk 域中的节点上,如果发现没有满足的条件,依然可正常部署与其他节点上。

2.2 PodAntiAffinity

1、功能

PodAntiAffinity 允许我们定义 Pod 不应该一起调度在相同节点上的规则,即要求或首选 Pod 不与其他具有特定标签的 Pod 一起调度。通常用于提高容错性,防止相同应用的不同实例在同一节点上运行。

2、案例(片段)

...
affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
        - key: "app"
          operator: In
          values:
          - "my-app"
    topologyKey: "kubernetes.io/hostname"
...

总结

  • NodeAffinity:
    • 匹配标签:主机标签
    • 支持操作符:In/NotIn/Exists/DoesNotExist/Gt/Lt
    • 是否支持拓扑域:
    • 实现功能:决定 Pod 可以部署在哪些主机上
  • NodeAntiAffinity:
    • 匹配标签:主机标签
    • 支持操作符:In/NotIn/Exists/DoesNotExist/Gt/Lt
    • 是否支持拓扑域:
    • 实现功能:决定 Pod 不可以部署在哪些主机上
  • PodAffinity:
    • 匹配标签:Pod 标签
    • 支持操作符:In/NotIn/Exists/DoesNotExist
    • 是否支持拓扑域:
    • 实现功能:决定 Pod 可以和哪些 Pod 部署在同一拓扑域上
  • PodAntiAffinity:
    • 匹配标签:Pod 标签
    • 支持操作符:In/NotIn/Exists/DoesNotExist
    • 是否支持拓扑域:
    • 实现功能:决定 Pod 不可以和哪些 Pod 部署在同一拓扑域上

—END

你可能感兴趣的:(云原生,kubernetes)