k8s–基础–20–污点和容忍度
1、什么是污点和容忍度
1.1、官方解释
- 节点亲和性,是pod的一种属性(偏好或硬性要求),它使pod被吸引到一类特定的节点。
- Taint(污点)与节点亲和性相反,它使节点能够排斥一类特定的pod。
- Taint(污点)和toleration(容忍度)相互配合,可以用来避免pod被分配到不合适的节点上。
- 每个节点上都可以应用一个或多个taint,这表示对于那些不能容忍这些taint的pod,是不会被运行在该节点上。
- 如果将toleration应用于pod上,则表示这些pod可以(但不要求)被调度到具有匹配taint的节点上。
1.2、自我理解:
- 污点和容忍度是相互匹配的关系,我们在node上定义一个污点,pod上定义容忍度
- 如果pod能容忍这个污点,就会被调度到拥有这个污点的节点上
- 如果pod不能容忍这个污点,就不会被调度到拥有这个污点的节点上
- 如果node节点上没有定义污点,那么任何pod都会调度到这个节点上
- 我们可以给node节点打一个污点,pod如果不能容忍这个节点上定义的污点,那就调度不到这个节点上
- taints:污点
- 定义在节点上,是键值数据
- tolerations:容忍度
- 定义在pod上,可以定义能容忍哪些污点
2、一个toleration和一个taint是怎么匹配的
2.1、案例
2.1.1、给node1节点增加一个taint
kubectl taint nodes node1 k1=v1:NoSchedule
给节点node1增加一个taint,它的key是k1,value是v1,effect是NoSchedule。
这表示只有拥有和这个taint相匹配的toleration的pod才能够被分配到node1这个节点。
2.1.2、给一个pod增加tolerations
tolerations:
- key: "k1"
operator: "Equal"
value: "v1"
effect: "NoSchedule"
tolerations:
- key: "k1"
operator: "Exists"
effect: "NoSchedule"
上面两个容忍标签都与2.1.1创建的污点"匹配", 因此具有任一容忍标签的Pod都可以将其调度到node1上
2.2、总结
一个toleration和一个taint相"匹配"是指它们有一样的key和effect
- 如果 operator 是 Exists,此时toleration不能指定value
- 如果 operator 是 Equal,此时它们的value应该相等
- 如果一个toleration的effect为空,则key值与之相同的相匹配taint的effect可以是任意值。
tolerations:
- key: "key"
operator: "Exists"
2.2.1、effect:用来定义节点污点对pod对象的排斥效果
- NoSchedule:不允许调度,已经调度的不受影响
- PreferNoSchedule
- 表示k8s将尽量避免将pod调度到这个污点的节点上,但是如果没有节点可以被调度,也是可以调度到拥有这个污点的node节点上的
- NoExecute:
- 当pod能够容忍这个节点污点,会被调度到节点
- 当pod不能容忍节点污点,将会被驱逐
2.2.2、注意
- 可以给一个节点添加多个taint
- 可以给一个pod添加多个toleration。
3、pod调度到节点的过程
3.1、原理
Kubernetes处理多个taint和toleration的过程就像一个过滤器,假设存在一个pod(A),存在一个节点(node1),A调度到node1的过程如下:
- node1节点上的所有taint和A中的toleration匹配,过滤掉匹配掉的taint
- 过滤后,如果node1上不存在taint
- A可以分配到node1节点
- 过滤后,如果node1上存在taint,剩余taint的effect值决定了A是否会被分配到node1
3.1.1、过滤后,剩余taint的effect值决定了A是否会被分配到node1
- taint中存在一个以上effect值为NoSchedule的taint,则Kubernetes不会将A分配到node1节点上。
- taint中存在一个以上effect值为NoExecute的taint
- 如果A未在node1上运行,则Kubernetes不会将A分配到node1节点上
- 如果A在node1上运行,将A从该node1上驱逐
- taint中不存在effect值为NoSchedule的taint,但是存在effect值为PreferNoSchedule的taint,则Kubernetes会尝试将A分配到node1s上。
3.2、案例1
给node1节点添加了如下的taint
kubectl taint nodes node1 k1=v1:NoSchedule
kubectl taint nodes node1 k1=v1:NoExecute
kubectl taint nodes node1 k2=v2:NoSchedule
然后存在一个pod(A),它有两个toleration:
tolerations:
- key: "k1"
operator: "Equal"
value: "v1"
effect: "NoSchedule"
- key: "k1"
operator: "Equal"
value: "v1"
effect: "NoExecute"
- 在这个例子中,A不会被分配到node1节点,因为其没有toleration和第3个taint相匹配。
- 但是如果在给节点添加上述taint之前,该pod已经在上述节点运行,那么它还可以继续运行在该节点上,因为第三个taint是三个taint中唯一不能被这个pod容忍的。
- 通常情况下,如果给一个节点添加了一个effect值为 NoExecute 的taint,则任何不能忍受这个taint的pod都会马上被驱逐,任何可以忍受这个taint的pod都不会被驱逐。
- 但是,如果pod存在一个effect值为 NoExecute 的toleration指定了可选属性 tolerationSeconds 的值,则表示在给节点添加了上述taint之后,pod 还能继续在节点上运行的时间。
例如,
tolerations:
- key: "k1"
operator: "Equal"
value: "v1"
effect: "NoExecute"
tolerationSeconds: 3600
这表示如果这个pod正在运行,然后一个匹配的taint被添加到其所在的节点,那么pod还将继续在节点上运行 3600 秒,然后被驱逐。如果在此之前上述taint被删除了,则pod不会被驱逐。
4、使用场景
- 可以灵活地让 pod避开某些节点
- 可以灵活地让 pod从某些节点驱逐。
4.1、专用节点
将某些节点专门分配给特定的一组用户使用
4.1.1、操作
操作1:给这些节点添加一个taint
kubectl taint nodes nodename dedicated=groupName:NoSchedule
操作2:给特定用户的pod添加一个相对应的 toleration
通过编写一个自定义的 admission controller
4.1.2、总结
- 拥有上述toleration的pod就能够被分配到上述专用节点,同时也能够被分配到集群中的其它节点。
- 如果你希望这些pod只能被分配到上述专用节点,那么你还需要给这些专用节点另外添加一个和上述taint类似的label(例如:dedicated=groupName),同时 还要在上述 admission controller 中给pod增加节点亲和性,要求上述pod只能被分配到添加了 dedicated=groupName 标签的节点上。
4.2、配备了特殊硬件的节点
在部分节点配备了特殊硬件(比如 GPU)的集群中,我们希望如下
- 不需要这类硬件的pod 不要 被分配到这些特殊节点
- 只有需要这类硬件的pod 才 被分配到这些特殊节点
4.2.1、操作
操作1:给配备了特殊硬件的节点添加taint
kubectl taint nodes nodename special=true:NoSchedule
# 或者
kubectl taint nodes nodename special=true:PreferNoSchedule
操作2:给使用了这类特殊硬件的pod添加一个相匹配的 toleration
和专用节点的例子类似,添加这个toleration的最简单的方法是使用自定义 admission controller。比如
1. 我们推荐使用 Extended Resources 来表示特殊硬件,给配置了特殊硬件的节点添加taint时包含 extended resource 名称
2. 然后运行一个 ExtendedResourceToleration admission controller。
4.2.2、总结
此时,因为节点已经被打上taint了,没有对应toleration的pod会被调度到这些节点。但当你创建一个使用了 extended resource 的pod时,ExtendedResourceToleration admission controller 会自动给pod加上正确的toleration,这样pod就会被自动调度到这些配置了特殊硬件件的节点上。
这样就能够确保这些配置了特殊硬件的节点专门用于运行 需要使用这些硬件的 Pod,并且你无需手动给这些pod添加 toleration。
4.2、基于taint的驱逐
当节点出现问题,pod就不会被驱逐
5、基于taint的驱逐
5.1、taint的effect值为NoExecute,它会影响已经在节点上运行的pod
- 如果pod不能忍受effect值为NoExecute的taint,那么pod将马上被驱逐
- 如果pod能够忍受effect值为NoExecute的taint,但是在toleration定义中没有指定tolerationSeconds,则pod还会一直在这个节点上运行。
- 如果pod不能够忍受effect值为NoExecute的taint,而且指定了tolerationSeconds,则pod还能在这个节点上继续运行这个指定的时间长度。
5.2、当某种条件为真时,node controller会自动给节点添加一个taint
当前内置的taint如下
5.2.1、node.kubernetes.io/not-ready
- 节点未准备好。
- 相当于节点状态 Ready 的值为 “False”。
5.2.2、node.kubernetes.io/unreachable
- 节点控制器访问不到节点
- 相当于节点状态 Ready 的值为 “Unknown”。
5.2.3、node.kubernetes.io/out-of-disk
节点磁盘耗尽。
5.2.4、node.kubernetes.io/memory-pressure
节点存在内存压力。
5.2.5、node.kubernetes.io/disk-pressure
节点存在磁盘压力。
5.2.6、node.kubernetes.io/network-unavailable
节点网络不可用。
5.2.7、node.kubernetes.io/unschedulable
节点不可调度。
5.2.8、node.cloudprovider.kubernetes.io/uninitialized
如果kubelet启动时指定了一个 “外部” cloud provider,它将给当前节点添加一个taint将其标志为不可用。
在cloud-controller-manager的一个controller初始化这个节点后,kubelet将删除这个taint。
5.3、自动给节点添加和删除污点
- 在节点被驱逐时,节点控制器或者kubelet会添加带有NoExecute效应的相关污点。
- 在节点异常状态恢复正常,节点控制器或者kubelet会移除相关的污点。
5.4、怎么避免pod被大量驱逐
- 为了保证由于节点问题引起的pod驱逐rate limiting行为正常,系统实际上会以rate-limited 的方式添加taint。 在像 master 和 node 通讯中断等场景下,这避免了pod被大量驱逐。
- 使用这个功能特性,结合tolerationSeconds,pod就可以指定当节点出现一个或全部上述问题时还将在这个节点上运行多长的时间。
5.4.1、案例1
一个pod在网络断开时,仍然希望停留在当前节点上运行一段较长的时间,愿意等待网络恢复以避免被驱逐。在这种情况下,pod的toleration可能是下面这样的:
tolerations:
-key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 6000
5.5、DefaultTolerationSeconds admission controller
给pod自动添加如下tolerations
tolerations:
-key: "node.kubernetes.io/not-ready"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 300
tolerations:
-key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 300
- 这种自动添加toleration机制保证了在其中一种问题被检测到时pod默认能够继续停留在当前节点运行5分钟。
- 这两个默认toleration是由 DefaultTolerationSeconds admission controller添加的。
- DaemonSet中的pod被创建时,针对以下taint自动添加的NoExecute的toleration将不会指定tolerationSeconds,这保证了出现上述问题时DaemonSet中的pod永远不会被驱逐。
node.kubernetes.io/unreachablenode.kubernetes.io/not-ready
6、基于节点状态添加taint
- Node生命周期控制器会自动创建与Node条件相对应的带有NoSchedule效应的污点。同样,调度器不检查节点条件,而是检查节点污点。
这确保了节点条件不会影响调度到节点上的内容。用户可以通过添加适当的pod容忍度来选择忽略某些Node的问题(表示为Node的调度条件)。
- 自Kubernetes1.8起,DaemonSet控制器自动为所有守护进程添加如下NoSchedule toleration以防DaemonSet崩溃
node.kubernetes.io/memory-pressurenode.kubernetes.io/disk-pressurenode.kubernetes.io/out-of-disk (只适合 criticalpod)node.kubernetes.io/unschedulable (1.10 或更高版本)node.kubernetes.io/network-unavailable (只适合 host network)
添加上述toleration确保了向后兼容,你也可以选择自由的向DaemonSet添加toleration。
7、pod容忍度,node污点 操作命令
7.1、给节点添加污点
kubectl taint nodes node1 k1=v1:NoSchedule
在node1上添加了污点. 这个污点的key是k1,value是v1, 污点的effect是NoSchedule
如果pod没有定义容忍度的话就不会调度到拥有这个污点的节点上
7.2、给节点移除污点
kubectl taint nodes node1 k1=v1:NoSchedule-
7.3、给Pod设置容忍
spec:
tolerations: #设置容忍性
- key: "test"
operator: "Equal" # 如果操作符为Exists,那么value属性可省略,如果不指定operator,则默认为Equal
value: "16"
effect: "NoSchedule"
- 意思是这个Pod要容忍的有污点的Node的key是test,value是16,effect是NoSchedule,
- 注意:
- tolerations属性下各值必须使用引号
- 容忍的值都是设置Node的taints时给的值。
7.4、修改effect为NoExecute
一般不要玩
kubectl taint nodes node1 k1=v1:NoExecute
7.5、tolerations属性补充
其中的key、value、effect与Node的Taint设置需保持一致,还有以下几点说明
- 如果operator的值是Exists,则value属性可省略。
- 如果operator的值是Equal,则表示其key与value之间的关系是equal(等于)。
- 如果不指定operator属性,则默认值为Equal。
- 还有两个特殊值:
- 空的key 如果再配合Exists,就能匹配所有的key与value,也就是能容忍所有node上的所有Taints。
- 空的effect,匹配所有的effect
8、验证
验证effect是NoSchedule情况
8.1、node1添加污点
kubectl taint nodes node1 k1=v1:NoSchedule
8.2、一个没有容忍度的pod
8.2.1、定义
vi /root/test2/tolerations-no.yaml
内容
apiVersion: v1
kind: Pod
metadata:
name: tolerations-no
spec:
containers:
- name: nginx
image: nginx
8.2.2、执行
kubectl apply -f /root/test2/tolerations-no.yaml
kubectl get pods
kubectl describe pods tolerations-no
显示pod不能容忍节点污点,不能完成调度
8.3、一个有容忍度的pod
8.3.1、定义
vi /root/test2/tolerations-yes.yaml
内容
apiVersion: v1
kind: Pod
metadata:
name: tolerations-yes
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: k1
value: v1
effect: NoSchedule
8.3.2、执行
kubectl apply -f /root/test2/tolerations-yes.yaml
kubectl get pods -o wide
可以看到tolerations-yes已经完成调度了,可以调度到node1节点上