Kubernetes 亲和性调度

一般情况下我们部署的Pod是通过集群的自动调度策略来选择节点的,默认情况下调度器考虑的是资源足够,并且负载尽量平均,但有些时候我们需要能够更加细粒度的去控制Pod的调度,比如我们内部的一些服务Gitlab之类,我们不希望对外的一些服务和内部的服务泡在同一个节点,怕内部服务对外部服务产生影响,但有时候我们的服务之间交流比较频繁,又希望能够将这二个服务的Pod调度到同一个节点上,就需要用到Kubernetes里的概念:亲和性(nodeAffinity)和pod 反亲和性(podAffinity)以及podAntiAffinity(pod 反亲和性)。

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

  • 软策略就是如果你没有满足调度要求的节点的话,pod 就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有的话也无所谓了的策略

  • 硬策略就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是你必须满足我的要求,不然我就不干的策略

  • 对于亲和性和反亲和性都有这两种规则可以设置: preferredDuringSchedulingIgnoredDuringExecution和requiredDuringSchedulingIgnoredDuringExecution,前面的就是软策略,后面的就是硬策略

nodeSelector
1
2
3
4
5
# 查看节点的标签
Kubectl get nodes --show-labels

# 手动给节点增加标签
kubectl label nodes <node-name> com=zhengwe
node-demo例子
 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
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: busybox-pod
  name: test-bs
spec:
  containers:
  - command:
    - sleep
    - "3600"
    image: busybox
    name: test-bs
  nodeSelector:
    kubernetes.io/hostname: n1  # 这是我的node节点标签

# 创建
kubectl create -f node-selector.yaml

# 查看可以看到被调度到固定node节点n1
kubectl get pod  -o wide
test-bs          1/1     Running   0          14s   10.244.40.151   n1     <none>           <none>

# 查看详情
kubectl describe po test-bs
nodeAffinity 节点亲和性

节点亲和性主要是用来控制pod 要部署在哪些主机上,以及不能部署在哪些主机上,上面例子 nodeSelector无法做到把某个服务不部署在哪些主机上,节点亲和性它可以进行一些简单的逻辑组合,不只是简单的相等匹配。

使用deployment管理三个副本
 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: affinity
  labels:
    app: affinity
spec:
  replicas: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: affinity
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - name: http
          containerPort: 80
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname   # 这里策略不希望调度到node n3上面
                operator: NotIn
                values:
                - n3
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - n1

# 创建 pod
kubectl create -f node-affinity.yaml

# 查看 pod
kubectl get po -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE   NOMINATED NODE   READINESS GATES
affinity-b555d669-p56f9   1/1     Running   0          30s   10.244.40.153   n1     <none>           <none>
affinity-b555d669-sg7xz   1/1     Running   0          30s   10.244.217.35   n2     <none>           <none>
affinity-b555d669-x4xmp   1/1     Running   0          30s   10.244.40.152   n1     <none>           <none>
podAffinity

pod亲和性主要解决可以和哪些pod部署在同一个拓扑域中的问题(其中拓扑域用主机标签实现,可以是单个主机,也可以是多个主机组成的 cluster、zone等等),而pod反亲和性主要是解决pod不能和哪些pod部署在同一个拓扑域中的问题,他们都是处理pod与pod之间的关系,比如一个pod在一个节点上了,那么我这个也得在这个节点,或者你这个pod在节点上了,那么我就不想和你待在同一个节点上。

使用deployment创建三个副本案列
 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
29
30
31
32
33
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: affinity
  labels:
    app: affinity
spec:
  replicas: 3
  revisionHistoryLimit: 10
  template:
    metadata:
      labels:
        app: affinity
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - name: http
          containerPort: 80
      affinity:
        podAffinity:  # podAntiAffinity pod反亲和性 
          requiredDuringSchedulingIgnoredDuringExecution:   #硬策略
          - labelSelector:         # 匹配pod的标签
              matchExpressions:
              - key: app
                operator: In
                values:
                - busybox-pod
            topologyKey: kubernetes.io/hostname

# 创建pod
kubectl create -f pod-affinity.yaml 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
kubectl get po -o wide
NAME                        READY   STATUS    RESTARTS   AGE     IP              NODE   NOMINATED NODE   READINESS GATES
affinity-859c5cfc4d-2d849   1/1     Running   0          14s     10.244.40.162   n1     <none>           <none>
affinity-859c5cfc4d-7nsdq   1/1     Running   0          14s     10.244.40.160   n1     <none>           <none>
affinity-859c5cfc4d-rpbq8   1/1     Running   0          14s     10.244.40.161   n1     <none>           <none>

kubectl get pod -l app=busybox-pod -o wide
NAME      READY   STATUS    RESTARTS   AGE     IP              NODE   NOMINATED NODE   READINESS GATES
test-bs   1/1     Running   1          6d23h   10.244.40.155   n1     <none>           <none>

kubectl get po --show-labels -o wide
test-bs                     1/1     Running   1          6d23h   10.244.40.155   n1     <none>           <none>            app=busybox-pod

# 可以看到创建的pod副本被调度到 app=busybox 的 n1节点

pod反亲和性把上面deployment案列 podAffinity: 改为podAntiAffinity: