Featured image of post k8s的亲和性与反亲和性

k8s的亲和性与反亲和性

k8s的亲和性与反亲和性

k8s环境:

1
2
3
4
5
6
[root@master ~]# kubectl get node
NAME     STATUS   ROLES    AGE    VERSION
master   Ready    master   363d   v1.18.2
node1    Ready    <none>   363d   v1.18.2
node2    Ready    <none>   363d   v1.18.2
node3    Ready    <none>   363d   v1.18.2

共有四个节点,master、node1、node2、node3,本文都在该环境下进行测试

背景

Scheduler调度器做为Kubernetes三大核心组件之一,承载着整个集群资源的调度功能,其根据特定调度算法和策略,将Pod调度到最优工作节点上,从而更合理与充分的利用集群计算资源。

节点亲和性就是在调度器中的NodeAffinity实现的

nodeSelector

nodeSelector是节点调度最简单的方式,可以实现将Pod调度到带有对应标签的目标节点上。

  • 打标签
    kubectl label nodes <node-name> <label-key>e=<label-value>,通过如下命令给node2节点打上s=node2的标签:
1
kubectl label nodes node2 s=node2 

结果如下:

1
2
3
4
5
6
[root@master ~]# kubectl get node --show-labels
NAME     STATUS   ROLES    AGE    VERSION   LABELS
master   Ready    master   363d   v1.18.2   ...
node1    Ready    <none>   363d   v1.18.2   ...
node2    Ready    <none>   363d   v1.18.2   ...,s=node2
node3    Ready    <none>   363d   v1.18.2   ...
  • 创建资源
    创建pod-node2.yaml资源,该yaml通过nodeSelector将pod调度到node2节点上,yaml文件内容如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    s: node2

使用如下命令创建资源:

1
kubectl apply -f pod-node2.yaml
  • 检测结果
1
2
3
[root@master k8s-sch]# kubectl get pod nginx -owide
NAME    READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
nginx   2/2     Running   0          99s   10.244.1.144   node2   <none>           <none>

pod已被正确调度到node2节点上

亲和性与反亲和性

  • 亲和性与反亲和性提供一种比nodeSelector有更强控制力的调度方式。

节点亲和性

节点亲和性概念上类似于nodeSelector,根据节点上的标签来约束Pod可以调度到哪些节点上,但语法调度控制力更强。节点亲和性有两种:

  • requiredDuringSchedulingIgnoredDuringExecution: (硬亲和)调度器只有在规则被满足时才能执行调度
  • preferredDuringSchedulingIgnoredDuringExecution: (软亲和)调度器尝试寻找满足规则的节点,如果匹配不到,调度器仍会调度

首先我们先给node2和node3节点分别打上region=east、region=west,使用如下命令:

1
2
3
[root@master k8s-sch]# kubectl label nodes node2 region=east && kubectl label nodes node3 region=west
node/node2 labeled
node/node3 labeled

你可以使用spec.affinity.nodeAffinity字段来设置节点亲和性,定义nodeAffinity.yaml资源文件,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: v1
kind: Pod
metadata:
  name: node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: region
                operator: In
                values:
                  - east
                  - west
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
              - key: s
                operator: In
                values:
                  - node2
  containers:
    - name: node-affinity
      image: nginx
  • operator:逻辑操作符,取值有In、NotIn、Exists、DoesNotExist、Gt、Lt
  • weight:节点亲和性权重,取值为1-100

该yaml描述了Pod调度的节点必须有region=east或region=west标签,该节点最好有s=node2的标签

注意:
如果同时指定了nodeSelectornodeAffinity,两者必须都要满足规则,才能将Pod调度到节点上。

如果指定了多个与nodeAffinity类型关联的nodeSelectorTerms,只要其中一个nodeSelectorTerms满足规则,Pod就可以被调度到节点上。

如果指定了多个与同一nodeSelectorTerms关联的matchExpressions, 则只有当所有matchExpressions都满足规则时,Pod才可以被调度到节点上。


Pod亲和性

如果节点(机架、地理区域等)上已经运行了一个或多个满足规则的Pod,则这个pod应该运行在这个节点(机架、地理区域等)上

Pod亲和性有两种:

  • requiredDuringSchedulingIgnoredDuringExecution: (硬亲和)调度器只有在规则被满足时才能执行调度,IgnoredDuringExecution是说明节点标签发生变化,已在节点运行的Pod不受影响
  • preferredDuringSchedulingIgnoredDuringExecution: (软亲和)调度器尝试寻找满足规则的节点,如果匹配不到,调度器仍会调度

在实际中,我们可能将多个Pod调度到同一地理区域,因为它们的通信非常频繁,可以使用spec.affinity.podAffinity字段来设置Pod亲和性

创建pods-one.yaml资源文件,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: apps/v1
kind: Deployment
metadata:
  name: affinity
spec:
  replicas: 2
  selector:
    matchLabels:
      app: affinity
  template:
    metadata:
      labels:
        app: affinity
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - affinity
              topologyKey: region
      containers:
        - name: pod-affinity
          image: nginx
          imagePullPolicy: Always  

topologyKey作用:
pod亲和性和反亲和性调度要求pod运行于同一位置和不能运行于同一位置,这里的同一位置通过topologyKey来定义,topologyKey的值为node的标签名称

比如node2节点的region=east和node3节点的region=west或有更多节点有这两个标签,当topologyKey的值为region时,pod就围绕着east拓扑和west拓扑来调度,相同拓扑下的node就为同一位置

如果topologyKey的值为kubernetes.io/hostname时,同一位置就意味着同一节点,不同节点为不同位置,因为该标签的值通常是不同的

该资源文件定义了一个Deployment,有两个副本,每个副本有app=affinity标签,Pod亲和性表示Pod会调度到具有region=X标签的节点上,并且该节点上至少运行了一个app=affinity的pod 使用kubectl apply -f pods-one.yaml命令发布该资源,预期两个Pod会同时调度到node2或node3节点

1
2
3
4
[root@master k8s-sch]# kubectl get pod -owide
NAME                              READY   STATUS    RESTARTS   AGE    IP             NODE    NOMINATED NODE   READINESS GATES
affinity-6f65798795-7gjvn         2/2     Running   0          39m    10.244.3.85    node3   <none>           <none>
affinity-6f65798795-wqqxq         2/2     Running   0          39m    10.244.3.84    node3   <none>           <none>

无论是增加副本数还是删除Deployment重建,所有pod都会处于同一节点:node2或node3(这两个节点有region键的标签)


Pod反亲和性

如果节点(机架、地理区域等)上已经运行了一个或多个满足规则的Pod,则这个pod不应该运行在这个节点(机架、地理区域等)上

在实际中,我们可能将一组Pod调度到不同的节点上,因为它们是IO密集型或者CPU密集型。可以使用spec.affinity.podAntiAffinity字段来设置Pod反亲和性

创建pods-all.yaml资源文件,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apiVersion: apps/v1
kind: Deployment
metadata:
  name: antiaffinity
spec:
  replicas: 4
  selector:
    matchLabels:
      app: antiaffinity
  template:
    metadata:
      labels:
        app: antiaffinity
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - antiaffinity
              topologyKey: kubernetes.io/hostname
      containers:
        - name: pod-antiaffinity
          image: nginx
          imagePullPolicy: Always  

topologyKey的值为kubernetes.io/hostname,定义副本数量为4(4个node),使用kubectl apply -f pods-all.yaml命令发布资源,我们会得到4个pod分布在不同节点上,结果如下:

1
2
3
4
5
6
[root@master k8s-sch]# kubectl get pod -owide
NAME                              READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
antiaffinity-5b9865945f-2z4nz     2/2     Running   0          36s     10.244.1.145   node2    <none>           <none>
antiaffinity-5b9865945f-8jjmc     2/2     Running   0          36s     10.244.0.29    master   <none>           <none>
antiaffinity-5b9865945f-8xl8m     2/2     Running   0          36s     10.244.2.146   node1    <none>           <none>
antiaffinity-5b9865945f-k2c2g     2/2     Running   0          36s     10.244.3.86    node3    <none>           <none>

4个pod分别位于master、node1、node2、node3四个节点上,与预期一致

调整副本数为5(超过节点数)会发生什么呢?

1
2
3
4
5
6
7
[root@master k8s-sch]# kubectl get pod -owide
NAME                              READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
antiaffinity-5b9865945f-559v4     2/2     Running   0          35s     10.244.0.30    master   <none>           <none>
antiaffinity-5b9865945f-7th59     2/2     Running   0          35s     10.244.2.147   node1    <none>           <none>
antiaffinity-5b9865945f-hdvwz     2/2     Running   0          35s     10.244.3.87    node3    <none>           <none>
antiaffinity-5b9865945f-kqsl8     0/2     Pending   0          35s     <none>         <none>   <none>           <none>
antiaffinity-5b9865945f-vzdt4     2/2     Running   0          35s     10.244.1.146   node2    <none>           <none>

其中一个pod为Pending状态,无法被调度,查看event如下:

1
2
3
[root@master k8s-sch]# kubectl get events
LAST SEEN   TYPE      REASON              OBJECT                               MESSAGE
<unknown>   Warning   FailedScheduling    pod/antiaffinity-5b9865945f-7th59    0/4 nodes are available: 4 node(s) didn't match pod affinity/anti-affinity, 4 node(s) didn't satisfy existing pods anti-affinity rules.

注意:
Pod亲和性和反亲和性都需要相当的计算量,因此会在大规模集群中显著降低调度速度。不建议在包含数百个节点的集群中使用这类设置。

Pod反亲和性需要节点上存在一致性的标签。如果部分或所有节点不存在指定的标签,调度行为可能不符合预期

Please call the seeds under the diligent.
Built with Hugo
主题 StackJimmy 设计