目录
一. Taint(污点)和 Toleration(容忍)
在生产环境中,经常会有这样的需求:
- master 节点只部署系统组件容器,比如 Calico、Metrics Server、Dashboard 等,不应该部署业务应用
- 新添加节点不应该立即就允许部署业务容器,也就是新节点需要经过完整性及稳定性测试才可以
被允许调度 - 某些节点可能需要进行系统升级或者其他维护,可能会引起节点上的容器不可用,此时需要将该节点上的 Pod 漂移至其他节点,再进行维护
有一些 GPU 服务器或其他专用节点服务器,除了指定的 Pod 之外,并不想让他们部署其他的 Pod
面对这样的需求,Kubernetes 抽象了污点(Taint)和容忍(Toleration)的概念,可以非常方便的实现这些需求
1. 污点和容忍的基本概念
Taint(污点)作用在节点上,能够使节点排斥一类特定的 Pod
Toleration(容忍)作用在 Pod 上,也就是可以兼容某类污点
比如有一批 GPU服务器只能部署要使用 GPU 的 Pod。每个节点上都可以应用一个或多个 Taint,这表示对于那些不能容忍这些 Taint 的 Pod 是不能部署在该服务器上的。如果 Pod 配置了 Toleration,则表示这些 Pod 可以被调度到设置了 Taint 的节点上,当然没有设置 Taint 的节点也是可以部署的
Taint(污点)和 Toleration(容忍)可以作用于 node 和 pod 上,其目的是优化 pod 在集群间的调度,这跟节点亲和性类似,只不过它们作用的方式相反,具有 taint 的 node 和 pod 是互斥关系,而具有节点亲和性关系的 node 和 pod 是相吸的。另外还有可以给 node 节点设置 1abel,通过给 pod 设置nodeselector 将 pod 调度到具有匹配标签的节点上
Taint 和 Toleration 相互配合,可以用来避免 Pod 被分配到不合适的节点上。每个节点上都可以应用一个或多个 taint ,这表示对于那些不能容忍这些 taint 的 Pod,是不会被该节点接受的。如果将 toleration 应用于 Pod 上,则表示这些 Pod 可以(但不一定)被调度到具有匹配 taint 的节点上
2. 污点的使用
如果一个节点被标记为有污点,那么意味着不允许 pod 调度到该节点,除非 pod 也被标记为可以容忍污点节点
在使用 kubeadm 部署的 k8s 集群的时候应该会发现,通常情况下,应用是不会调度到 master 节点的。因为 kubeadm 部署的 k8s 集群默认给 master 节点加了 Taints(污点)
①:给节点 node01 增加一个污点,它的键名是 key1,键值是 value1,效果是 NoSchedule。 这表示只有拥有和这个污点相匹配的容忍度的 Pod 才能够被分配到 node1 这个节点

②:查看节点是否为污点

③:删除污点

每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,efect 描述污点的作用效果,语法为 key=value:effec
当前 taint effect 支持如下三个选项:
| 选项 | 含义 |
|---|---|
| NoSchedule | 表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上 ,不会驱逐已存在该节点上的 Pod。如果一个 pod 没有声明容忍这个 Taint,则系统不会把该 Pod 调度到有这个 Taint的 node 上 |
| PreferNoschedule | 表示 k8s 将尽量避免将 Pod 调度到具有该污点的 Node 上,不会驱逐已存在该节点上的 Pod。这是 NoSchedule 的软限制版本,如果一个 Pod 没有声明容忍这个 Taint,则系统会尽量避免把这个 pod 调度到这一节点上去,但不是强制的 |
| NoExecute | 表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去,若节点上设置了污点并用的是 NoExecute 策略,node 节点上的 pod 会被全部驱逐,但是如果是 Deployment 或者 statefulset 资源类型,为了维持副本数量则会在别的Node上在创建新的Pod |
备注:
NoExecute 这个 Taint 效果对节点上正在运行的 pod 有以下影响:
(1)没有设置 Toleration 的 Pod 会被立刻驱逐
(2)配置了对应 Toleration 的 pod,如果没有为 tolerationseconds 赋值,则会一直留在这一节点中
(3)配置了对应 Toleration 的 pod 且指定了 tolerationseconds 值,则会在指定时间后驱逐
tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Node 上继续保留运行的时间,即 60秒后该 pod 会被驱逐掉,默认的是一天
tolerationseconds 用于描述当 Pod 需要被驱逐时可以在 Node 上继续保留运行的时间,即 60秒后该 pod 会被驱逐掉,默认的是一天
3. 容忍的定义
设置了污点的 Node 将根据 taint 的 effect: Noschedule、PreferNoschedule、NoExecute 和 Pod之间产生互斥的关系,Pod 将在一定程度上不会被调度到 Node 上。 但我们可以在 Pod 上设置容忍(Toleration),意思是设置了容忍的 Pod 将可以容忍污点的存在,可以被调度到存在污点的 Node 上
4. 示例
(1)设置污点

(2)编写 yaml 文件
[root@k8s-master ~]# vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: nginx:1.7.9
(3)创建 pod

(4)查看结果
在两个 Node 上都设置了污点后,此时 Pod 将无法创建成功

(5)修改 yaml 文件
[root@k8s-master ~]# vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp001
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: nginx:1.7.9
tolerations:
- key: check
operator: Equal
value: mycheck
effect: NoExecute
tolerationSeconds: 60
(6)创建新 Pod

(7)在设置了容忍之后,Pod 创建成功

(8)删除污点

5. 容忍的基本用法
(1)容忍污点的条件
operator 的值为 Exists 将会忽略 value值,即存在即可,为 Equal 时需要指定污点的 value.pod 的 Toleration 声明中的 key和 efect 需要与]aint 的设置保持一致,并且满足以下条件之一
#不完全匹配,operator 的值为 Exists,这时无需指定 value
tolerations:
- key: check
operator:"Exists'
effect:NoExecute
#完全匹配,operator 的值为 Equal 并且 value 相等(可以设置多个 tolerations
tolerations:
- key: check
operator: Equal
value:mycheck
effect: NoExecute
#如果不指定 operator,则默认值为 Equal
tolerations:
- key:check
value:mycheck
effect:NoExecute
(2)特例
#空的 key 、value、effect 配合 Exists 操作符能够匹配所有的键和值,即能容忍所有污点
tolerations:
operator:"Exists'
#空的 effect 匹配所有的 effect,即能容忍任何 key 名为 check 的污点
tolerations:
- key: check
operator:"Exists"
(3)使用场景
#有多个 Master 存在时,为了防止资源浪费,可以将 master 节点设置为PreferNoschedule 污点,让Pod 可在 Master 上临时创建:
kubectl taint node k8s-master node-role,kubernetes,io/master=:PreferNoSchedule
#如果某个 Node 更新升级系统组件,为了防止业务长时间中断,可以先在该 Node 设置 NoExecute 污点,把该 Node 上的 Pod 都驱逐出去
kubectl taint node k8s-node01 check=mycheck:NoExecute
#此时如果别的 Node 资源不够用,可临时给 Master 设置 PreferNoSchedule 污点,让 Pod 可在Master 上临时创建
kubectl taint node k8s-master node-role.kubernetes.io/master=:PreferNoschedule
#待所有 Node 的更新操作都完成后,再去除污点
kubectl taint node node01 check=mycheck:NoExecute
6. 多污点与多容忍配置
系统允许在同一个 node 上设置多个 taint,也可以在 pod 上设置多个 Toleration
Kubernetes 调度器处理多个 Taint 和 Toleration 能够匹配的部分,剩下的没有忽略掉的Taint 就是对 Pod 的效果了。下面是几种特殊情况
- 如果剩余的 Taint 中存在 effect=NoSchedule,则调度器不会把该 pod 调度到这一节点上
- 如果剩余的 Taint 中没有 Noschedule 的效果,但是有 PreferNoschedule 效果,则调度器会尝试不会将 pod 指派给这个节点
- 如果剩余 Taint 的效果有 NoExecute 的,并且这个 pod 已经在该节点运行,则会被驱逐;如果没有在该节点运行,也不会再被调度到该节点上
创建污点:
kubectl taint nodes k8s-node01 key1=valuel:NoSchedule
kubectl taint nodes k8s-node01 key1=value1:NoExecute
kubectl taint nodes k8s-node01 key2=value2:NoSchedule
去除污点:
kubectl taint nodes k8s-node01 key1=valuel:Noschedule-
kubectl taint nodes k8s-node01 key1=value1:NoExecute-
kubectl taint nodes k8s-node01 key2=value2:NoSchedule-
二. 警戒(cordon)和 转移(drain)
1. 设置警戒
警戒是指将 Node 标记为不可调度的状态这样就不会让新创建的 Pod 在此 Node 上运行,命令如下

该 node 将会变为 SchedulingDisabled 状态

2. 取消警戒
[root@k8s-master ~]# ku uncordon k8s-node01
[root@k8s-master ~]# ku get node

3. 驱逐(转移)pod
kubectl drain 可以让 Node 节点开始释放所有 pod,并且不接收新的 pod 进程。drain 本意排水,意思是将出问题的 Node 下的 Pod 转移到其它 Node 下运行

执行 drain 命令,会自动做了两件事情:
- 设定此 node 为不可调度状态(cordon)
- evict(驱逐)了 Pod
备注:
| 命令字 | 含义 |
|---|---|
| -ignore-daemonsets | 无视 Daemonset 管理下的 Pod |
| -delete-local-data | 如果有 mount local volume 的 pod,会强制杀掉该 pod |
| -force | 强制释放不是控制器管理的 Pod,例如 kube-proxy |
注意:
实验完成后,将节点设置为可调度
kubectl uncordon k8s-node01
三. k8s 亲和性和非亲和性
关于 K8S 对 Pod 的调度,通常情况下 Pod 被分配到哪些 Node 是不需要我们操心的,这个过程会由scheduler 自动实现。但有时,我们需要让 Pod 按照我们的预想运行在 Node 上(例如某些应用“必须/或者尽量"跑在具有 SSD 存储的节点上,有些彼此相关的 Pod 应用应该跑在同-个节点上)。为此,k8s为我们提供了这样的策略,我们可以通过使用“亲和性/非亲和性”制定一些规则来实现我们的需求
1. 亲和性调度可以分成软策略和硬策略两种方式
| 方式 | 含义 |
|---|---|
| 硬策略 | 可以理解为必须,就是如果没有满足条件的节点的话,就不断重试直到满足条件为止。对应的配置规则为 requiredDuringSchedulingIgnoredDuringExecution |
| 软策略 | 可以理解为尽量,就是如果现在没有满足调度要求的节点的话,pod 就会忽略这条规则,继续完成调度的过程,说白了就是满足条件最好了,没有的话也无所谓对应的配置规则为preferredDuringSchedulingIgnoredDuringExecution |
2. 亲和性的配置规则
分为 Node 亲和性、Pod 亲和性、Pod 反亲和性
| 亲和性 | 含义 |
|---|---|
| nodeAffinity | 节点亲和性,用来控制 Pod 要部署在哪些节点上,以及不能部署在哪些节点上的,这个是 Pod 与 Node 之间匹配规则的 |
| podAffinity | pod 亲和性,这个是 Pod 与 Pod 之间匹配规则的 |
| podAntiAffinity | pod 反亲和性,与 podAffinity 相反,用来指定 Pod 不要部署到哪些节点 |
3. 节点硬亲和性
节点的亲和性可以通过 pod.spec.affinity.nodeAffinity 字段定义,nodeAffinity 字段中支持使用 matchExpressions 属性构建更为复杂的标签选择器
(1)设置节点标签
首先对两个 node 加标签,设置两个 node 标签分别为 node1 和 node2 。加标签的语法如下
| kubectl label nodes = |
|---|

备注:
如果需要重命名 node 标签,可以使用如下命令
[root@k8s-master ~]# kubectl label nodes k8s-node01 type=node1 --overwrite
如果要删除 node 标签(标签名为“type”),可以使用如下命令
[root@k8s-master ~l# kubectl label node k8s-node01 type-
(2)查看节点标签

(3)设置 pod 亲和性 为 type=node01
[root@k8s-master ~]# vim test01.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod01
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: type, operator: In, values: ["node01"]}
containers:
- name: pod01
image: nginx:1.7.9
备注:
values:["nodeB1"1 node1 为节点的标签,该 pod 要调度到标签为 node1 的节点,即 k8s-node01
(4)部署 pod 并查看信息

(5)设置 pod 亲和性 为 type=node02
[root@k8s-master ~]# vim test02.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod02
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: type, operator: In, values: ["node02"]}
containers:
- name: pod02
image: nginx:1.7.9
(6)部署 pod 并查看信息

4. 节点软亲和性
节点软亲和性为节点选择提供了一种柔性的控制器逻辑,当条件不满足时,也能够接受被编排在其他不符合条件的节点之上。同时他还为每种倾向性提供了 weight 属性以便用于自定义优先级,范围是 1-108.越大越优先
(1)为 pod 设置软亲和性
[root@k8s-master ~]# vim test02.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod03
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 60
preference:
matchExpressions:
- {key: type, operator: In, values: ["node02"]}
- weight: 90
preference:
matchExpressions:
- {key: tpye, operator: In, values: ["node01"]}
containers:
- name: pod03
image: nginx:1.7.9
(2)部署 pod 并查看信息

5. Pod 硬亲和度
出于某些需求,将一些 Pod 对象组织在相近的位置(同一节点、机架、区域等),此时这些 pod 对象间的关系为 pod 亲和性
Pod 的亲和性调度也存在硬亲和性和软亲和性的区别,他们表示的约束意义同节点亲和性相似
Pod 硬亲和性调度也使用 requiredDuringSchedulingIgnoreDuringExecution 属性进行定义
首先创建两个基础 Pod,并对它打标签,分别部署到 node01 和 node02 上
(1)部署第一个基础 Pod,名字为 pod4,使其节点硬亲和到 node01
[root@k8s-master ~]# vim test04.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod04
labels:
app: pod04
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: type, operator: In, values: ["node01"]}
containers:
- name: pod04
image: nginx:1.7.9
(2)部署 pod 并查看信息

(3)部署第二个基础 Pod,名字为 pod5,使其节点硬亲和到 node02
[root@k8s-master ~]# vim test05.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod05
labels:
app: pod05
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: type, operator: In, values: ["node02"]}
containers:
- name: pod05
image: nginx:1.7.9
(4)部署 pod 并查看信息

可以看到,一个位于 node01,一个位于 node02
(5)用 pod 硬亲和创建一个亲和 pode5 的 pod
[root@k8s-master ~]# vim test06.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod06
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod05"]}
topologyKey: kubernetes.io/hostname
containers:
- name: pod06
image: nginx:1.7.9
(6)部署 pod 并查看信息

7. Pod 软亲和度
Pod 软亲和调度使用方法与 Node 软亲和调度方法类似
(1)编辑 pod07 的 pod
[root@k8s-master ~]# vim test07.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod07
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 20
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod05"]}
topologyKey: kubernetes.io/hostname
- weight: 80
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod04"]}
topologyKey: kubernetes.io/hostname
containers:
- name: pod07
image: nginx:1.7.9
(2)部署 pod 并查看信息

pod04 的标签是 pod04,所在的节点标签是 node01
(3)编辑 pod08 的 pod
修改 yam1 文件中的权重,使其与 pod84 亲和性更高,因为 pod04 在 node01 上,pod08 也会被部署到 node01 上
[root@k8s-master ~]# vim test08.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod08
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod05"]}
topologyKey: kubernetes.io/hostname
- weight: 20
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod04"]}
topologyKey: kubernetes.io/hostname
containers:
- name: pod08
image: nginx:1.7.9
(4)部署 pod 并查看信息

8. pod 反亲和
(1)编辑 pod09 的 pod
[root@k8s-master ~]# vim test09.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod09
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["pod05"]}
topologyKey: kubernetes.io/hostname
containers:
- name: test09
image: nginx:1.7.9
(2)部署 pod 并查看信息

査看 pod09 所在的节点,因为设置的反亲和 pod85,所以,pod05在 node02的话,pod09 就会在 node01
总结:
污点是阻止 Pod 调度的硬性条件,而亲和性是影响调度决策的软性指导。在 Kubernetes 调度过程中,污点的约束始终优先于亲和性的指导
- 污点优先级高于亲和性:如果一个节点上有污点,而 Pod 没有相应的容忍度,那么无论亲和性规
则如何,Pod 都不能被调度到该节点上 - 亲和性不影响污点的约束:即使 Pod 的亲和性规则允许它被调度到某个节点,如果该节点上有污点而 Pod 没有容忍度,Pod 仍然不能被调度上去

182

被折叠的 条评论
为什么被折叠?



