背景
由于业务需求要做节点迁移,旧节点要被废弃,正好可以试试 k8s 的 taint
污浊节点操作。
taint
基本用法:$ kubectl taint --help
# 添加/更新一个节点的污浊标识效果
kubectl taint nodes <节点名称> <键>=<值>:<效果>
# 删除一个节点的污浊标识效果,在后面加一个小横杆 -
kubectl taint nodes <节点名称> <键>:<效果>-
# 删除一个节点这个key的所有效果
kubectl taint nodes <键>-
## 如果要改动所用节点可以用 --all=true
taint 分为三部分,键、值和效果(key=value:effect),其中健和值构成关联的键值对用于和pod匹配的,effect
用来表示 node 的效果,主要包括:
PerferNoSchedule
,会让k8s尽量不去调度这个节点(不保证,比如如果其他节点资源满了的情况)NoSchedule
,表示这个节点不可调度,也就是新pod不会再被分配到这个节点上,旧节点依然能运行NoExecute
,表示这个节点不能运行 pod ,不仅不可调度新的pod,旧的正在运行的pod也会被移除
effect 虽然会影响 pod 调度的不同行为,但同时也受到 pod 的 tolerations 设置的影响,比如我们可以通过设置 pod 的 tolerations
让他在 NoExecute
节点继续运行或者 NoSchedule
进行调度,这里就会用到键和值,这个后面再细将。
上面三种 effect 的核心区别: 首先是 PerferNoSchedule
和 NoSchedule
, 他们之间的区别就是,即使不设置 pod 的容忍度,PerferNoSchedule
的节点在特定的条件下也可能会被调度,是一种不严格的限制策略,而 NoSchedule
只有在 pod 设置了对应的tolerations
的情况下才能被调度。然后是 NoSchedule
和 NoExecute
,一个是不让调度,一个不让响应节点调度同时 kill 掉不匹配的 pod。
tolerations
pod 里面主要包括五部分,key
、value
、operator
、effect
、tolerationSeconds
key
和value
是键值对,会和 node 节点的key
和value
匹配,如果operator
为Existes
的时候只会匹配key
,value
可以不用,如果key
为空表示匹配所有的taint
的key
值operator
包含两个值Equal
和Exists
,默认是Equal
,即键和值都要完全匹配才能容忍污浊。tolerationSeconds
表示可以容忍的时间,这个设置只对NoExecute
这种 effec 生效,默认是永久容忍。effect
和 node 的 taint 一样
注意的是:
DaemonSet 创建的pod 的 tolerations
不会指定 tolerationSeconds
,这样保证了其面对node.kubernetes.io/unreachable
和node.kubernetes.io/not-ready
的时候永远不会被驱逐
实战:节点pod迁移
集群原来两个 node 节点 10.213.20.183
和 10.213.20.215
由于资源不足,需要纵向扩容,需要将里面的 pod 移除到其他节点,实施步骤:
- 将两个节点设置为不可调度
NoSchedule
,观测资源运行情况 - 逐个节点进行驱逐
设置NoSchedule
# 这里10.213.20.183 是 node 名字 |
查看一下:$ kubectl get nodes 10.213.20.215 -ojson | jq '.spec.taints'
[
{
"effect": "NoSchedule",
"key": "node-tranfer"
}
]
okay, 设置成功
观测在 pod 上运行的节点:$ kubectl get pods -A -owide | grep 10.213.20.215
...
对pod进行扩容测试:$ kubectl scale --replicas=5 deployment/<名称>
将pod从节点驱逐
通过设置NoExecute
驱逐 pod:$ kubectl taint nodes 10.213.20.215 node-expel:NoExecute
node/10.213.20.215 tainted
查看:$ kubectl get nodes 10.213.20.215 -ojson | jq '.spec.taints'
[
{
"effect": "NoExecute",
"key": "node-expel"
},
{
"effect": "NoSchedule",
"key": "node-tranfer"
}
]
查看pod 状况:kubectl get po -A -owide --watch
设置 PodDiscruptionBudget
pod 的销毁可以分为自愿干扰(Voluntary Disruptions)和非自愿干扰(Involuntary Disruptions),非自愿干扰一般是由硬件或软件系统错误导致,比如:
- 节点下层物理机的硬件故障
- 集群管理员错误地删除虚拟机(实例)
- 云提供商或虚拟机管理程序中的故障导致的虚拟机消失
- 内核错误
- 节点由于集群网络隔离从集群中消失
- 由于节点资源不足导致 pod 被驱逐。
自愿干扰,是指由应用程序所有者发起的操作,比如:
- 删除 Deployment 或其他管理 Pod 的控制器
- 更新了 Deployment 的 Pod 模板导致 Pod 重启
- 直接删除 Pod(例如,因为误操作)
我们自己驱逐节点也算自愿干扰的一种。对于自愿干扰, k8s 提供了 PodDiscruptionBudget 的资源对象来确保高可用,通过 PodDiscruptionBudget(PDB) 可以确保宕机的 pod 数量副本数量不超过某一比例。
PDB资源文件:apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
name: app-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: rcmd
上面的 PDB 表示所有 labels 为app:rcmd
的 pod 在 自愿干扰下不会少于 2 个有效副本,minAvailable
和maxUnavailable
除了直接使用副本数量还可以使用百分比。