pod 调度详解:亲和污点和容忍

Posted 看,未来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pod 调度详解:亲和污点和容忍相关的知识,希望对你有一定的参考价值。

文章目录

兔子的故事

在讲解本章之前,我先通过一个故事,来描绘一下 k8s 中 node 和 pod 的爱恨情仇。

雄性(node)| 雌性(pod)

在银河系以外的一个星球上,有着一群两性生物,分别是雌性(pod)和雄性(node)。雌性生物居多,而雄性生物由于优胜劣汰,只剩下 3 只优质的雄性生物(node)。雄雌在一起就容易产生吸引,就会有以下的情况产生:

(1)雄(node)少雌(pod)多,而这三只优质的雄性生物性格、优点都是一致的,雌性生物选谁都一样。于是,雌性生物就分为均等分为三列和三只雄性生物在一起。这种类似于平均分配的原则。

k8s 中的概念:在 k8s 中是最常见最普通的 pod 分布方式,常用与 deployment 和 daemonset 控制器。

(2)时间一长,生物开始了进化。三只雄性(node)生物各自有了不一样的地方,编号 1 的雄性学会了种植(node01 label skill=‘grow’);编号 2 的雄性学会了打猎(node02 label skill=‘hunt’);编号 3 的雄性啥也没学会(没学会就保持默认)。普通的雌性(pod)仍然保持着平均分配的原则。而一些进化快的雌性(pod)生物发现了三只优质雄性(node)生物各自的不同,各自也开始有了一些选择。一些雌性更加青睐学会种植的雄性生物(nodeSelector skill=‘grow’) ;一些雌性更加青睐学打猎的雄性生物(nodeSelector skill=‘hunt’) ;而有些雌性生物喜欢的特点很奇特,它们喜欢会飞的雄性,而仅存的三只雄性生物都无法满足这一特点。如果有天一只雄性生物进化会飞了,它们就会依附与会飞的雄性生物,如果始终没有进化出会飞的雄性生物,则它们一直等下去这在 k8s 中,就是 yaml 文件中 nodeSelector 的使用。

k8s 中的概念:当 node 打上特定的标签后,会出现如下情况:

  1. pod 中未指定 nodeSelector ,则保持默认 schedule 调度算法的方式;
  2. pod 中指定了 nodeSelector ,且指定 nodeSelector 中的 key、value 符合某一个 node 中的某一个 key、value,则这个 pod 直接调度到该 node;
  3. pod 中指定了 nodeSelector ,指定 nodeSelector 中的 key、value 不包含在任何一个 node 中,则这个 pod 会一直处于 padding 状态。

(3)三只雄性(node)不仅优点增长了,缺点也随之而来。编号 1 的雄性喜欢打脸(node01 taint hobby=‘face’);编号 2 的雄性喜欢打屁股(node01 taint hobby=‘hunkers’);编号 3 的雄性喜欢踩脚(node01 taint hobby=‘foot’);普通的雌性(pod)生物仍然保持平均分配的原则,而一些再次进化的雌性生物也有了自己的性格。能够容忍打脸的雌性则和编号 1 的雄性在一起(tolerations hobby=‘face’),但是这个容忍可能是永久,也可能是 1 天(tolerationSeconds=86400)。而这三只雄性生物偶尔会在一起鬼混,编号 1 的雄性生物说不定哪天就嗜好就变为了喜欢睡懒觉。而一些无法容忍它睡懒觉嗜好的雌性生物就会隔一段时间或者马上就离开它。

k8s 中的概念:这就是 污点容忍


在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。但是在实际使用中,这并不满足的需求,因为很多情况下,我们想控制某些Pod到达某些节点上,那么应该怎么做呢?这就要求了解kubernetes对Pod的调度规则,kubernetes提供了四大类调度方式:

  • 自动调度:运行在哪个节点上完全由Scheduler经过一系列的算法计算得出
  • 定向调度:NodeName、NodeSelector
  • 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
  • 污点(容忍)调度:Taints、Toleration

自动调度

在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。


定向调度

利用在pod上声明nodeName或者nodeSelector,以此将Pod调度到期望的node节点上。注意,这里的调度是强制的,这就意味着即使要调度的目标Node不存在,也会向上面进行调度,只不过pod运行失败而已。

NodeName用于强制约束将Pod调度到指定的Name的Node节点上。这种方式,其实是直接跳过Scheduler的调度逻辑,直接将Pod调度到指定名称的节点。示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: node1 # 指定调度到node1节点上

NodeSelector用于将pod调度到添加了指定标签的node节点上。它是通过kubernetes的label-selector机制实现的,也就是说,在pod创建之前,会由scheduler使用MatchNodeSelector调度策略进行label匹配,找出目标node,然后将pod调度到目标节点,该匹配规则是强制约束。示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeselector
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeSelector: 
    nodeenv: pro # 指定调度到具有nodeenv=pro标签的节点上

亲和性调度

它在NodeSelector的基础之上的进行了扩展,可以通过配置的形式,实现优先选择满足条件的Node进行调度,如果没有,也可以调度到不满足条件的节点上,使调度更加灵活。

Affinity主要分为三类:

  • nodeAffinity(node亲和性):以Node为目标,解决Pod可以调度到那些Node的问题。
  • podAffinity(pod亲和性):以Pod为目标,解决Pod可以和那些已存在的Pod部署在同一个拓扑域中的问题。
  • podAntiAffinity(pod反亲和性):以Pod为目标,解决Pod不能和那些已经存在的Pod部署在同一拓扑域中的问题。

关于亲和性和反亲和性的使用场景的说明:

  • 亲和性:如果两个应用频繁交互,那么就有必要利用亲和性让两个应用尽可能的靠近,这样可以较少因网络通信而带来的性能损耗。
  • 反亲和性:当应用采用多副本部署的时候,那么就有必要利用反亲和性让各个应用实例打散分布在各个Node上,这样可以提高服务的高可用性。

nodeAffinity

nodeAffinity 就是节点亲和性,调度可以分成软策略和硬策略两种方式,软策略就是如果你没有满足调度要求的节点的话,Pod 就会忽略这条规则,继续完成调度过程,说白了就是满足条件最好了,没有的话也无所谓了的策略;而硬策略就比较强硬了,如果没有满足条件的节点的话,就不断重试直到满足条件为止,简单说就是你必须满足我的要求,不然我就不干的策略。nodeAffinity就有两上面两种策略:

  • requiredDuringSchedulingIgnoredDuringExecution :硬策略
  • preferredDuringSchedulingIgnoredDuringExecution :软策略

示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    nodeAffinity: #设置node亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        nodeSelectorTerms:
        - matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]
apiVersion: v1
kind: Pod
metadata:
  name: pod-nodeaffinity-preferred
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    nodeAffinity: #设置node亲和性
      preferredDuringSchedulingIgnoredDuringExecution: # 软限制
      - weight: 1
        preference:
          matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签(当前环境没有)
          - key: nodeenv
            operator: In
            values: ["xxx","yyy"]

PodAffinity

podAffinity主要实现以运行的Pod为参照,实现让新创建的Pod和参照的Pod在一个区域的功能。

pod.spec.affinity.podAffinity
  requiredDuringSchedulingIgnoredDuringExecution  硬限制
    namespaces       指定参照pod的namespace
    topologyKey      指定调度作用域
    labelSelector    标签选择器
      matchExpressions  按节点标签列出的节点选择器要求列表(推荐)
        key    键
        values 值
        operator 关系符 支持In, NotIn, Exists, DoesNotExist.
      matchLabels    指多个matchExpressions映射的内容
  preferredDuringSchedulingIgnoredDuringExecution 软限制
    podAffinityTerm  选项
      namespaces      
      topologyKey
      labelSelector
        matchExpressions  
          key    键
          values 值
          operator
        matchLabels 
    weight 倾向权重,在范围1-100

示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podaffinity-requred
  namespace: dev
spec:
  containers: # 容器配置
    - name: nginx
      image: nginx:1.17.1
      imagePullPolicy: IfNotPresent
      ports:
        - name: nginx-port
          containerPort: 80
          protocol: TCP
  affinity: # 亲和性配置
    podAffinity: # Pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
        - labelSelector:
            matchExpressions: # 该Pod必须和拥有标签podenv=xxx或者podenv=yyy的Pod在同一个Node上,显然没有这样的Pod
              - key: podenv
                operator: In
                values:
                  - "xxx"
                  - "yyy"
          topologyKey: kubernetes.io/hostname

PodAntiAffinity

PodAntiAffinity主要实现以运行的Pod为参照,让新创建的Pod跟参照pod不在一个区域中的功能。

它的配置方式和选项跟PodAffinty是一样的,这里不再做详细解释,直接做一个测试案例。

示例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-podantiaffinity-required
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    podAntiAffinity: #设置pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: # 匹配podenv的值在["pro"]中的标签
          - key: podenv
            operator: In
            values: ["pro"]
        topologyKey: kubernetes.io/hostname

污点和容忍

在 Kubernetes 中,节点亲和性 NodeAffinity 是 Pod 上定义的一种属性,能够使 Pod 按我们的要求调度到某个节点上,而 Taints(污点) 则恰恰相反,它是 Node 上的一个属性,可以让 Pod 不能调度到带污点的节点上,甚至会对带污点节点上已有的 Pod 进行驱逐。当然,对应的 Kubernetes 可以给 Pod 设置 Tolerations(容忍) 属性来让 Pod 能够容忍节点上设置的污点,这样在调度时就会忽略节点上设置的污点,将 Pod 调度到该节点。一般时候 Taints 通常与 Tolerations 配合使用。


  • 一个 node 可以有多个污点;
  • 一个 pod 可以有多个容忍;
  • kubernetes 执行多个污点和容忍方法类似于过滤器

如果一个 node 有多个污点,且 pod 上也有多个容忍,只要 pod 中容忍能包含 node 上设置的全部污点,就可以将 pod 调度到该 node 上。如果 pod 上设置的容忍不能够包含 node 上设置的全部污点,且 node 上剩下不能被包含的污点 effect 为 PreferNoSchedule,那么也可能会被调度到该节点。

注意:

当 pod 存在容忍,首先 pod 会选择没有污点的节点,然后再次选择容忍污点的节点。

  • 如果 node 上带有污点 effect 为 NoSchedule,而 pod 上不带响应的容忍,kubernetes 就不会调度 pod 到这台 node 上。
  • 如果 Node 上带有污点 effect 为 PreferNoShedule,这时候 Kubernetes 会努力不要调度这个 Pod 到这个 Node 上。
  • 如果 Node 上带有污点 effect 为 NoExecute,这个已经在 Node 上运行的 Pod 会从 Node 上驱逐掉。没有运行在 Node 的 Pod 不能被调度到这个 Node 上。一般使用与当某个节点处于 NotReady 状态下,pod 迅速在其他正常节点启动。

污点(Taints)

查看污点

查看 node 的污点

$ kubectl describe nodes k8s-master
...
Taints:             node-role.kubernetes.io/master:NoSchedule
...

# 也可通过下面操作查看:
$ kubectl get nodes k8s-master -o go-template=.spec.taints
[map[effect:NoSchedule key:node-role.kubernetes.io/master]]

污点内容一般组成为 key、value 及一个 effect 三个元素,表现为:

<key>=<value>:<effect>

这里的 value 可以为空,表现形式为:

node-role.kubernetes.io/master:NoSchedule
- key: node-role.kubernetes.io/master
- value:- effect: NoSchedule

设置污点

一般我们需要想要设置某个节点只允许特定的 Pod 进行调度,这时候就得对节点设置污点,可以按 kubectl taint node [node] key=value[effect] 格式进行设置,其中 effect 可取值如下:

  • PreferNoSchedule: 尽量不要调度。
  • NoSchedule: 一定不能被调度。
  • NoExecute: 不仅不会调度, 还会驱逐 Node 上已有的 Pod。

一般时候我们设置污点,就像下面例子一样对齐进行设置:

# 设置污点并不允许 Pod 调度到该节点
$ kubectl taint node k8s-master key1=value1:NoSchedule
# 设置污点尽量阻止污点调度到该节点
$ kubectl taint node k8s-master key2=value2:PreferNoSchedule
# 设置污点,不允许普通 Pod 调度到该节点,且将该节点上已经存在的 Pod 进行驱逐
$ kubectl taint node k8s-master key3=value3:NoExecute

删除污点

上面说明了如何对 Node 添加污点阻止 Pod 进行调度,下面再说一下如何删除节点上的污点,可以使用下面命令:

kubectl taint node [node] [key]-

上面语法和创建污点类似,不过需要注意的是删除污点需要知道 key 和最后面设置一个 “-” 两项将污点删除,示例如下:

为了方便演示,先给节点设置污点:

# 设置污点1
$ kubectl taint node k8s-master key1=value1:PreferNoSchedule
node/k8s-master tainted
# 设置污点2
$ kubectl taint node k8s-master key2=value2:NoSchedule
node/k8s-master tainted
# 设置污点3,并且不设置 value
$ kubectl taint node k8s-master key2=:PreferNoSchedule
node/k8s-master tainted

查看污点,可以看到上面设置的三个值:

$ kubectl describe nodes k8s-master
...
Taints:             key2=value2:NoSchedule
                    node-role.kubernetes.io/master:NoSchedule
                    key1=value1:PreferNoSchedule
                    key2:PreferNoSchedule
...

然后删除污点

删除污点,可以不指定 value,指定 [effect] 值就可删除该 key[effect] 的污点
$ kubectl taint node k8s-master key1:PreferNoSchedule-

也可以根据 key 直接将该 key2 的所有 [effect] 都删除:
$ kubectl taint node k8s-master key2-

再次查看污点,可以看到以上污点都被删除:

$ kubectl describe nodes k8s-master
...
Taints:             node-role.kubernetes.io/master:NoSchedule
...

容忍 (toleratints)

Pod 设置容忍

为了使某些 Pod 禁止调度到某些特定节点上,就可以对节点设置污点 taints。当然,如果希望有些 Pod 能够忽略节点的污点,继续能够调度到该节点,就可以对 Pod 设置容忍,让 Pod 能够容忍节点上设置的污点,例如:

对一个节点设置污点:

kubectl taint node k8s-node01 key=value:NoSchedule

对于 Pod 设置容忍, 以下两种方式都可以:

# 容忍的 key、value 和对应 effect 也必须和污点 taints 保持一致
......
tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "NoSchedule"
# 容忍 tolerations 的 key 和要污点 taints 的 key 一致,且设置的 effect 也相同,不需要设置 value
......
tolerations:
- key: "key"
  operator: "Exists"
  effect: "NoSchedule"

Deployment 中设置容忍

在 kubernetes 中 deployment 设置容忍,示例如下:

apiVersion: apps/vl
kind: Deployment
metadata:
  name: example
spec:
  replicas: 5
  template:
    spec:
      ......
      tolerations:
      - key: "key"
        operator: "Equal"
        value: "value"
        effect: "NoSchedule"

设置容忍时间

正常情况下, 如果一个污点带有 effect=NoExecute 被添加到了这个 Node。那么不能容忍这个污点的所有 Pod 就会立即被踢掉。而带有容忍标签的 Pod 就不会踢掉。然而,一个带有 effect=Noexecute 的容忍可以指定一个 tolerationSeconds 来指定当这个污点被添加的时候在多长时间内不被踢掉。例如:

tolerations:
- key: "key"
  operator: "Equal"
  value: "value"
  effect: "Noexecute"
  tolerationSeconds: 3600

如果这个 Pod 已经在这个带污点且 effect 为 NoExecute 的 node 上。这个 pod 可以一直运行到 3600s 后再被踢掉。如果这时候 Node 的污点被移除了,这个 Pod 就不会被踢掉。

容忍示例

Operator 默认是 Equal,可设置为 EqualExists 两种,按这两种进行示例:

Operator 是 Exists

容忍任何污点

例如一个空的 key,将匹配所有的 key、value、effect。即容忍任何污点。

tolerations:
- operator: "Exists"

容忍某 key 值的污点

例如一个空的 effect,并且 key 不为空,那么将匹配所有与 key 相同的 effect:

tolerations:
- key: "key"
  operator: "Exists"

Operator 是 Equal

node 上有一个污点

Node 和 Pod 的 key 为 key1、value1 与 effect 相同则能调度:

#污点
key1=value1:NoSchedule

#Pod设置
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"

node 上有多个污点

Node 的污点的 key、value、effect 和 Pod 容忍都相同则能调度:

## 设置污点
key1=value1:NoSchedule
key2=value2:NoExecute

## Pod设置容忍
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key2"
  operator: "Equal"
  value: "value2"
  effect: "NoExecute"

Node 的污点和 Pod 的大部分都相同,不同的是 Node 污点 effect 为 PreferNoSchedule 的,可能会调度:

## 污点
key1=value1:NoSchedule
key2=value2:NoExecute
key3=value3:PreferNoSchedule

## Pod设置容忍
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key2"
  operator: "Equal"
  value: "value2"
  effect: "NoExecute"

Node 的污点和 Pod 的大部分都相同,不同的是 Node 污点 effect 为 NoSchedule 和 NoExecute 的,不会被调度:

## 污点
key1=value1:NoSchedule
key2=value2:NoExecute
key3=value3:PreferNoSchedule

## Pod设置容忍
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key3"
  operator: "Equal"
  value: "value3"
  effect: "PreferNoSchedule"

对比理解 Exists 和 Equal 之间的区别:

  • Exists 是包含,Equal 是等于,Exists 使用范围更广,而 Equal 则是精准匹配。
  • 当污点中存在 NoExecute 时,而容忍中不存在 NoExecute 时,不会被调度到该节点。
  • Exists 可以不写 value , 而 Equal 则一定要指定对应的 value

污点驱逐

在使用 kubernetes 时,会遇到 某个 node 节点明明已经 宕机了,查看 node 状态从 Ready 状态变为 NotReady 状态,但是 节点所在的 pod 却已经处于 running 状态,过了很长一段时间才会转为 Terminating 状态,这是为什么呢?

污点是对于 node 节点来讲,如果 node 节点 effect 设置为 NoExecute ,它会影响节点上已经运行的 Pod,如下所示:

  • 立即将没有匹配容忍的 pod 驱逐。
  • 设置容忍但是没有指定 tolerationSeconds 参数的,那么该容忍永久生效,不会被驱逐。
  • 设置容忍但是有指定 tolerationSeconds 参数的,那么在指定的时间内容忍有效,超过指定时间后将被剔除。(pod 默认设置,tolerationSeconds = 300s)

此外,当某些条件为 true 时,节点控制器会自动污染节点。内置以下污点:

key注释
node.kubernetes.io/not-ready节点尚未准备好。这对应于 NodeCondition Ready 为 false。
node.kubernetes.io/unreachable无法从节点控制器访问节点。这对应于 NodeCondition Ready 为 Unknown。
node.kubernetes.io/out-of-disk节点磁盘不足。
node.kubernetes.io/memory-pressure节点有内存压力。
node.kubernetes.io/disk-pressure节点有磁盘压力。
node.kubernetes.io/network-unavailable节点的网络不可用。
node.kubernetes.io/unschedulable节点不可调度。
node.cloudprovider.kubernetes.io/uninitialized当 kubelet 从 “外部” 云提供程序开始时,此污点在节点上设置为将其标记为不可用。来自 cloud-controller-manager 的控制器初始化此节点后,kubelet 删除此污点。

通过上面知识的铺垫,当一个节点宕机时,kubernetes 集群会给它打上什么样的污点呢?

一个 Ready 状态的节点

$ kubectl get node k8s-node02 -o go-template=.spec.taints
<no value>

一个 NotReady 状态的节点

$ kubectl get node k8s-node02 -o go-template=.spec.taints
[map[effect:NoSchedule key:node.kubernetes.io/unreachable timeAdded:2022-07-0423T13:49:58Z] 
map[effect:NoExecute key:node.kubernetes.io/unreachable timeAdded:2021-07-04T13:50:03Z]]

处于 NotReady 状态的节点被打上了下面两个污点:

Taints:             node.kubernetes.io/unreachable:NoExecute
                    node.kubernetes.io/unreachable:NoSchedule

接下来测试 kubernetes 集群会给 Pod 分配什么样的容忍。

$ kubectl get po nginx-745b4df97d-mgdmp -o yaml
...
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300  ## 300/60=5min
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300 ## 300/60=5min
...

看到这里,Pod 的失效机制已经很明白了, 当 node 节点处于 NotReady 状态或者 unreachable 状态时,Pod 会容忍它 5 分钟,然后被驱逐。而这 5 分钟内就算 Pod 处于 running 状态,也是无法正常提供服务的。因此,可以在 yaml 清单中 手动指明 0 容忍,清单文件如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 4
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      tolerations:
      - effect: NoExecute
        key: node.kubernetes.io/not-ready
        operator: Exists
        tolerationSeconds: 0
      - effect: NoExecute
        key: node.kubernetes.io/unreachable
        operator: Exists
        tolerationSeconds: 0
      containers:
      - image: nginx:alpine
        name: nginx

生成 Pod

$ kubectl get po -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
nginx-84f6f75c6-c76fm   1/1     Running   0          6s    10.244.3.16   k8s-node02   <none>           <none>
nginx-84f6f75c6-hsxq5   1/1     Running   0          6s    10.244.3.15   k8s-node02   <none>           <none>
nginx-84f6f75c6-wkt52   1/1     Running   0          6s    10.244.1.63   k8s-node01   <none>           <none>
nginx-84f6f75c6-xmkjs   1/1     Running   0          6s    10.244.3.17   k8s-node02   <none>           <none>

接下来强制关闭 k8s-node02 节点,查看 Pod 是否转移。

$ kubectl get po -o wide
NAME                    READY   STATUS        RESTARTS   AGE    IP            NODE         NOMINATED NODE   READINESS GATES
nginx-84f6f75c6-c76fm   1/1     Terminating   0          116s   10.244.3.16   k8s-node02   <none>           <none>
nginx-84f6f75c6-csqf4   1/1     Running       0          13s    10.244.1.66   k8s-node01   <none>           <none>
nginx-84f6f75c6-hsxq5   1/1     Terminating   0          116s   10.244.3.15   k8s-node02   <none>           <none>
nginx-84f6f75c6-r2v4p   1/1     Running       0          13s    10.244.1.64   k8s-node01   <none>           <none>
nginx-84f6f75c6-v4knq   1/1     Running       0          13s    10.244.1.65   k8s-node01   <none>           <none>
nginx-84f6f75c6-wkt52   1/1     Running       0          116s   10.244.1.63   k8s-node01   <none>           <none>
nginx-84f6f75c6-xmkjs   1/1     Terminating   0          116s   10.244.3.17   k8s-node02   <none>           <none>

在 node 节点转为 NotReady 状态后,Pod 立刻进行了转移。这是通过 在 yaml 清单文件中明确指定 容忍时间。还可以直接修改 apiserver 配置来修改默认容忍时间。

vim /etc/kubernetes/manifests/kube-apiserver.yaml
...
spec:
  containers:
  - command:
    - kube-apiserver
    - --advertise-address=192.168.1.11
    - --default-not-ready-toleration-seconds=1    ## 新增行
    - --default-unreachable-toleration-seconds=1  ## 新增行
...

修改保存后, kube-apiserver-k8s-masterpod 会自动重载最新配置。

$ kubectl get po nginx-84f6f75c6-wkt52 -o yaml
...
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 0
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 0
...

对于小型集群,可以直接设置全局变量。

注意:当 kubernetes 集群只有一个 node 节点时,无法做到 Pod 转移,因为 Pod 已经无路可退了。

以上是关于pod 调度详解:亲和污点和容忍的主要内容,如果未能解决你的问题,请参考以下文章

k8s 实践经验pod 详解

Kubernetes 调度使用介绍(亲和反亲和污点容忍)

Kubernetes 调度使用介绍(亲和反亲和污点容忍)

Kubernetes 调度使用介绍(亲和反亲和污点容忍)

运维实操——kubernetes调度nodeNamenodeSelector亲和性污点容忍删除节点

k8s 亲和性和反亲和性 以及污点和容忍