Please enable Javascript to view the contents

Kubernetes 调度器之亲和性

 ·  ☕ 3 分钟

1. Kubernetes 中的调度器

kube-scheduler 是 Kubernetes 中决定 Pending 状态的 Pod 运行在哪个 Node 的组件,被称之为调度器。

Kubernetes 中内置了大量的调度策略,也提供了一些高级调度策略(nodeAffinity、podAffinity 等),以供用户使用,基本能够满足绝大部分的业务需求。

前面的文档 Kubernetes 之 Labels、Selectors 中提到, Labels、Selectors 是 Kubernetes 中非常重要的功能。Labels 关联了 Pod 、Deployment 、Service ,也用于调度策略,下面我们就来看看怎么使用 Labels 定制调度策略。

2. nodeSelector

首先查看,Node 有哪些 Labels :

1
2
3
4
5
6
kubectl get nodes --show-labels

NAME    STATUS   ROLES           AGE   VERSION    LABELS
node1   Ready    master,worker   17h   v1.15.12   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node1,kubernetes.io/os=linux,node-role.kubernetes.io/master=
node2   Ready    worker          17h   v1.15.12   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node2,kubernetes.io/os=linux,node-role.kubernetes.io/worker=
node3   Ready    worker          17h   v1.15.12   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node3,kubernetes.io/os=linux,node-role.kubernetes.io/worker=

回顾一下 Labels 的基本操作:

  • 增加标签
1
kubectl label node node1 node-role.kubernetes.io/worker=ci
  • 修改标签
1
kubectl label --overwrite node1 node-role.kubernetes.io/worker=
  • 删除标签
1
kubectl label node node1 node-role.kubernetes.io/worker-

在使用 nodeSelector 时,在 Pod 的 Spec 字段中增加 nodeSelector ,说明 Node 需要同时满足的全部 Label 条件即可。下面这个例子,将 Pod 调度到具有 kubernetes.io/hostname=node1 Label 的 Node 上。

spec:
  containers:
  - ...
  nodeSelector:
    kubernetes.io/hostname: node1

在 1.2 版本之后,Kubernetes 引入了 nodeAffinity ,功能上类似 nodeSelector ,nodeSelector 在后续版本中将被废除。

3. nodeAffinity

nodeAffinity 主要用于控制 Pod 应该运行在哪个 Node 上。亲和性调度有两种方式:

  • 软策略,尽量满足
  • 硬策略,必须满足

这些策略是通过 Label 匹配进行判断的,Kubernetes 提供了几种操作符:

  • In, Label 在某个列表中
  • NotIn, Label 不在某个列表中
  • Gt, Label 大于某个值
  • Lt, Label 小于某个值
  • Exists, Label 存在
  • DoesNotExist,Label 不存在

通过这些操作符和 Label ,我们就可以定制自己的调度策略。下面是一个官方的示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
spec:
  containers:
  - ...
  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

在 Pod 的 Spec 字段中,新增 nodeAffinity 字段进行描述。

如果同时指定多个 nodeSelectorTerms ,那么 Node 只要满足其中一个条件即可调度。如果指定多个 matchExpressions ,那么 Node 必须满足所有条件才可以调度。

4. podAffinity

podAffinity 与 nodeAffinity 类似,只不过 nodeAffinity 描述的是 Pod 对 Node 的选择,而 podAffinity 描述的是 Pod 对 Pod 的选择。

podAffinity 多了一个 topologyKey (拓扑域),这相当于给 Pod 的调度策略增加了一个选择 Node 的维度。首先 Node 的 Label 需要满足 topologyKey 的要求,再考察运行中的 Pod 带的 Label 是否满足亲和性的要求。

下面这个例子要求 Pod 调度需要满足:

  • Node 的 Label 必须有 failure-domain.beta.kubernetes.io/zone
  • Node 上运行的 Pod Label 必须有 security=S1
  • 尽量不要调度到 Label 有 kubernetes.io/hostname ,并且 Pod Label 有 security=S2 的 Node 上
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
spec:
  containers:
  - ...
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution: #硬策略,强制满足
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: failure-domain.beta.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution: #软策略,尽量满足
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: kubernetes.io/hostname

5. taints、tolerations

taints 针对的是 Node , tolerations 针对的是 Pod。如果一个 Node 被标记为 taint ,那么这个 Node 将不被调度,除非 Pod 被设置 tolerations 容忍这个 taint。taints、tolerations 通常用在一些特殊的 Node 调度上,比如 master 、具有 GPU 的 Node 、SSD 硬盘的 Node 、内存很大的 Node 等。

taint 的格式为:<key>=<value>:<effect>

其中 key、value(均可为空) 用于 tolerations 匹配,而 effect 有三个值:

- PreferNoSchedule ,尽量不要调度
- NoSchedule ,不能调度
- NoExecute ,不能调度,同时驱逐已有 Pod
  • 给 Node 增加一个 taint
1
kubectl taint nodes node1 key1=value1:NoSchedule
  • 查看 Node 的 taint
1
kubectl describe nodes node1
  • 给 Node 去掉 taint
1
kubectl taint nodes node1 key1:NoSchedule-
  • Pod 容忍 taint

在 Pod 的 Spec 字段,新增 tolerations 描述容忍的 taint 。下面的例子,正好可以容忍上面打的 taint :

1
2
3
4
5
6
7
8
spec:
  containers:
  - ...
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoSchedule"

6. 参考


微信公众号
作者
微信公众号