集群环境
IP | Hostname | 用途 |
---|---|---|
10.20.1.139 | k8s-master01 | Master节点 |
10.20.1.140 | k8s-node01 | Node节点 |
10.20.1.141 | k8s-node02 | Node节点 |
10.20.1.142 | k8s-node03 | Node节点 |
一、Cordon
kubectl cordon
命令用于将节点标记为不可调度。这意味着 Kubernetes 调度器不会将任何新的 Pod 调度到该节点上。但是,已经在该节点上运行的 Pod 不会受到影响,它们将继续运行。在 kubectl cordon
节点后删除节点上已有 Pod,Kubernetes 会自动将新的 Pod 调度到其他可用节点上,从而实现 Pod 的迁移。但是,请务必注意控制器、资源限制、节点亲和性/反亲和性以及 Taints 和 Tolerations 等因素,以确保 Pod 能够成功迁移。
1. 使用场景
- 节点维护: 在对节点进行维护(例如,硬件更换、内核更新、资源调整)之前,可以使用
cordon
命令来防止新的 Pod 调度到该节点上。 - 资源调整:在调整节点的计算资源时,可以先使用
cordon
命令,以避免资源竞争。 - 工作负载重新分配:在需要将工作负载重新分配到其他节点时,可以使用
cordon
命令来阻止新的 Pod 调度到目标节点上。
2. 如何使用
将节点设置成不可调度
$ kubectl cordon <node_name> [options] # 具体选项参考官网:https://kubernetes.io/zh-cn/docs/reference/kubectl/generated/kubectl_cordon/
将
<node-name>
替换为要 cordon 的节点的名称。检查节点状态
使用以下命令检查节点的状态,确认节点是否已被 cordon:
kubectl get nodes <node-name>
在输出中,STATUS 列将显示 Ready,SchedulingDisabled,表示节点已被 cordon。
解除节点的不可调度状态
完成维护或调整后,可以使用以下命令将节点标记为可调度:
kubectl uncordon <node-name>
撤销状态后,新的Pod可以调度到该节点上。
3. 案例实操
当前集群节点状态
$ kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME k8s-master01 Ready control-plane 46d v1.29.15 10.20.1.139 <none> Rocky Linux 9.3 (Blue Onyx) 5.14.0-362.8.1.el9_3.x86_64 docker://28.0.4 k8s-node01 Ready <none> 46d v1.29.15 10.20.1.140 <none> Rocky Linux 9.3 (Blue Onyx) 5.14.0-362.8.1.el9_3.x86_64 docker://28.0.4 k8s-node02 Ready <none> 46d v1.29.15 10.20.1.141 <none> Rocky Linux 9.3 (Blue Onyx) 5.14.0-362.8.1.el9_3.x86_64 docker://28.0.4 k8s-node03 Ready <none> 46d v1.29.15 10.20.1.142 <none> Rocky Linux 9.3 (Blue Onyx) 5.14.0-362.8.1.el9_3.x86_64 docker://28.3.1
给节点设置 cordon
# 给 node01 节点设置 cordon $ kubectl cordon k8s-node01 node/k8s-node01 cordoned # 再次查看节点状态,发现 node01 被打上了 SchedulingDisabled 标签 $ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 46d v1.29.15 k8s-node01 Ready,SchedulingDisabled <none> 46d v1.29.15 k8s-node02 Ready <none> 46d v1.29.15 k8s-node03 Ready <none> 46d v1.29.15
创建 Pod
资源清单:
cordon-deployment.yaml
apiVersion: apps/v1 kind: Deployment metadata: name: myapp namespace: default spec: replicas: 1 # 默认副本数量为1 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: my-container image: nginx:1.29.0
执行资源清单
$ kubectl apply -f cordon-deployment.yaml deployment.apps/myapp created # 查看 Pod, 被调度到 node02 节点上 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-85497bd9fb-hdvdn 1/1 Running 0 25s 171.20.58.223 k8s-node02 <none> <none>
增加 Pod 副本数
# Pod 设置10个副本 $ kubectl scale deployment myapp --replicas=10 deployment.apps/myapp scaled # 查看 Pod, 发现10个副本都被分布在 node02 和 node03 节点上,没有被调度到 node01 节点上 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-85497bd9fb-8kzkf 1/1 Running 0 2m52s 171.20.58.225 k8s-node02 <none> <none> myapp-85497bd9fb-9vm9s 1/1 Running 0 2m52s 171.20.58.224 k8s-node02 <none> <none> myapp-85497bd9fb-gtc22 1/1 Running 0 2m52s 171.20.58.227 k8s-node02 <none> <none> myapp-85497bd9fb-hdvdn 1/1 Running 0 4m4s 171.20.58.223 k8s-node02 <none> <none> myapp-85497bd9fb-j2tkd 1/1 Running 0 2m52s 171.20.58.228 k8s-node02 <none> <none> myapp-85497bd9fb-kg9qf 1/1 Running 0 2m52s 171.20.135.147 k8s-node03 <none> <none> myapp-85497bd9fb-mh9dx 1/1 Running 0 2m53s 171.20.135.145 k8s-node03 <none> <none> myapp-85497bd9fb-qvrgl 1/1 Running 0 2m52s 171.20.58.226 k8s-node02 <none> <none> myapp-85497bd9fb-tbcrv 1/1 Running 0 2m52s 171.20.135.149 k8s-node03 <none> <none> myapp-85497bd9fb-wgpwc 1/1 Running 0 2m52s 171.20.135.146 k8s-node03 <none> <none>
节点设置 uncordon
# 给 node01 节点设置 uncordon $ kubectl uncordon k8s-node01 node/k8s-node01 uncordoned # 再次查看 Node 状态,发现 node01 节点的 SchedulingDisabled 已经去除了 $ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 46d v1.29.15 k8s-node01 Ready <none> 46d v1.29.15 k8s-node02 Ready <none> 46d v1.29.15 k8s-node03 Ready <none> 46d v1.29.15
再次增加 Pod 副本数
# 将 Pod 的副本数从 10 增加到 20 $ kubectl scale deployment myapp --replicas=20 deployment.apps/myapp scaled # 再次查看 Pod, 发现可以被调度到 node01 节点了 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-85497bd9fb-6wjg6 1/1 Running 0 36s 171.20.135.151 k8s-node03 <none> <none> myapp-85497bd9fb-8kzkf 1/1 Running 0 6m45s 171.20.58.225 k8s-node02 <none> <none> myapp-85497bd9fb-97lnr 1/1 Running 0 36s 171.20.58.229 k8s-node02 <none> <none> myapp-85497bd9fb-9vm9s 1/1 Running 0 6m45s 171.20.58.224 k8s-node02 <none> <none> myapp-85497bd9fb-d2s9d 1/1 Running 0 36s 171.20.85.195 k8s-node01 <none> <none> myapp-85497bd9fb-f8jqn 1/1 Running 0 36s 171.20.85.254 k8s-node01 <none> <none> myapp-85497bd9fb-gbg7t 1/1 Running 0 36s 171.20.85.251 k8s-node01 <none> <none> myapp-85497bd9fb-gtc22 1/1 Running 0 6m45s 171.20.58.227 k8s-node02 <none> <none> myapp-85497bd9fb-hdvdn 1/1 Running 0 7m57s 171.20.58.223 k8s-node02 <none> <none> myapp-85497bd9fb-j2tkd 1/1 Running 0 6m45s 171.20.58.228 k8s-node02 <none> <none> myapp-85497bd9fb-kg9qf 1/1 Running 0 6m45s 171.20.135.147 k8s-node03 <none> <none> myapp-85497bd9fb-m7zhs 1/1 Running 0 37s 171.20.85.252 k8s-node01 <none> <none> myapp-85497bd9fb-mh9dx 1/1 Running 0 6m46s 171.20.135.145 k8s-node03 <none> <none> myapp-85497bd9fb-nx2nb 1/1 Running 0 36s 171.20.135.150 k8s-node03 <none> <none> myapp-85497bd9fb-q4z5x 1/1 Running 0 36s 171.20.85.255 k8s-node01 <none> <none> myapp-85497bd9fb-qvrgl 1/1 Running 0 6m45s 171.20.58.226 k8s-node02 <none> <none> myapp-85497bd9fb-tbcrv 1/1 Running 0 6m45s 171.20.135.149 k8s-node03 <none> <none> myapp-85497bd9fb-wgpwc 1/1 Running 0 6m45s 171.20.135.146 k8s-node03 <none> <none> myapp-85497bd9fb-x9vdq 1/1 Running 0 36s 171.20.85.253 k8s-node01 <none> <none> myapp-85497bd9fb-xc7q7 1/1 Running 0 36s 171.20.85.198 k8s-node01 <none> <none>
二、Drain
kubectl drain
命令用于安全地将节点上的所有 Pod 驱逐到其他节点。在驱逐 Pod 之前,drain
命令会先 cordon 节点,以防止新的 Pod 调度到该节点上。
1. 使用场景
- 节点维护:在需要关闭或删除节点之前,可以使用
drain
命令将节点上的所有 Pod 驱逐到其他节点,以确保应用程序的可用性。 - 节点缩容:在需要缩减集群规模时,可以使用
drain
命令将要移除的节点上的 Pod 驱逐到其他节点。
2. 如何使用
给节点设置 Drain
kubectl drain <node-name> --ignore-daemonsets --force
--ignore-daemonsets
:忽略 DaemonSet 管理的 Pod。DaemonSet 通常提供节点本地服务,即使节点被标记为不可调度,也应该在节点上运行。--force
:强制驱逐 Pod,即使它们没有被 ReplicationController、Job 或 DaemonSet 管理。
处理 Grace Period
如果 Pod 有较长的 grace period,
drain
命令可能需要较长时间才能完成。可以使用--grace-period
标志来覆盖 Pod 的终止宽限期,并强制立即驱逐:kubectl drain <node-name> --grace-period 0 --force --ignore-daemonsets
请谨慎使用此选项,因为强制停止 Pod 可能会导致数据丢失或应用程序错误。
3. 案例实操
查看当前集群 Pod 运行情况
$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-85497bd9fb-6wjg6 1/1 Running 0 36s 171.20.135.151 k8s-node03 <none> <none> myapp-85497bd9fb-8kzkf 1/1 Running 0 6m45s 171.20.58.225 k8s-node02 <none> <none> myapp-85497bd9fb-97lnr 1/1 Running 0 36s 171.20.58.229 k8s-node02 <none> <none> myapp-85497bd9fb-9vm9s 1/1 Running 0 6m45s 171.20.58.224 k8s-node02 <none> <none> myapp-85497bd9fb-d2s9d 1/1 Running 0 36s 171.20.85.195 k8s-node01 <none> <none> myapp-85497bd9fb-f8jqn 1/1 Running 0 36s 171.20.85.254 k8s-node01 <none> <none> myapp-85497bd9fb-gbg7t 1/1 Running 0 36s 171.20.85.251 k8s-node01 <none> <none> myapp-85497bd9fb-gtc22 1/1 Running 0 6m45s 171.20.58.227 k8s-node02 <none> <none> myapp-85497bd9fb-hdvdn 1/1 Running 0 7m57s 171.20.58.223 k8s-node02 <none> <none> myapp-85497bd9fb-j2tkd 1/1 Running 0 6m45s 171.20.58.228 k8s-node02 <none> <none> myapp-85497bd9fb-kg9qf 1/1 Running 0 6m45s 171.20.135.147 k8s-node03 <none> <none> myapp-85497bd9fb-m7zhs 1/1 Running 0 37s 171.20.85.252 k8s-node01 <none> <none> myapp-85497bd9fb-mh9dx 1/1 Running 0 6m46s 171.20.135.145 k8s-node03 <none> <none> myapp-85497bd9fb-nx2nb 1/1 Running 0 36s 171.20.135.150 k8s-node03 <none> <none> myapp-85497bd9fb-q4z5x 1/1 Running 0 36s 171.20.85.255 k8s-node01 <none> <none> myapp-85497bd9fb-qvrgl 1/1 Running 0 6m45s 171.20.58.226 k8s-node02 <none> <none> myapp-85497bd9fb-tbcrv 1/1 Running 0 6m45s 171.20.135.149 k8s-node03 <none> <none> myapp-85497bd9fb-wgpwc 1/1 Running 0 6m45s 171.20.135.146 k8s-node03 <none> <none> myapp-85497bd9fb-x9vdq 1/1 Running 0 36s 171.20.85.253 k8s-node01 <none> <none> myapp-85497bd9fb-xc7q7 1/1 Running 0 36s 171.20.85.198 k8s-node01 <none> <none>
给 node01 节点设置 Drain
$ kubectl drain k8s-node01 --ignore-daemonsets --force node/k8s-node01 cordoned # 查看节点状态, node01 被打上了 SchedulingDisabled 标签 $ kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master01 Ready control-plane 46d v1.29.15 k8s-node01 Ready,SchedulingDisabled <none> 46d v1.29.15 k8s-node02 Ready <none> 46d v1.29.15 k8s-node03 Ready <none> 46d v1.29.15
查看 node01 节点的 Pod
# 所有pod都被调度到 node02和node03节点了 $ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-85497bd9fb-4cx54 1/1 Running 0 6m37s 171.20.58.233 k8s-node02 <none> <none> myapp-85497bd9fb-6wjg6 1/1 Running 0 79m 171.20.135.151 k8s-node03 <none> <none> myapp-85497bd9fb-8kzkf 1/1 Running 0 85m 171.20.58.225 k8s-node02 <none> <none> myapp-85497bd9fb-97lnr 1/1 Running 0 79m 171.20.58.229 k8s-node02 <none> <none> myapp-85497bd9fb-9vm9s 1/1 Running 0 85m 171.20.58.224 k8s-node02 <none> <none> myapp-85497bd9fb-cv4xb 1/1 Running 0 6m38s 171.20.135.153 k8s-node03 <none> <none> myapp-85497bd9fb-gtc22 1/1 Running 0 85m 171.20.58.227 k8s-node02 <none> <none> myapp-85497bd9fb-hdvdn 1/1 Running 0 86m 171.20.58.223 k8s-node02 <none> <none> myapp-85497bd9fb-j2tkd 1/1 Running 0 85m 171.20.58.228 k8s-node02 <none> <none> myapp-85497bd9fb-kg9qf 1/1 Running 0 85m 171.20.135.147 k8s-node03 <none> <none> myapp-85497bd9fb-mh9dx 1/1 Running 0 85m 171.20.135.145 k8s-node03 <none> <none> myapp-85497bd9fb-nx2nb 1/1 Running 0 79m 171.20.135.150 k8s-node03 <none> <none> myapp-85497bd9fb-qvrgl 1/1 Running 0 85m 171.20.58.226 k8s-node02 <none> <none> myapp-85497bd9fb-rtcjg 1/1 Running 0 6m37s 171.20.135.154 k8s-node03 <none> <none> myapp-85497bd9fb-rwvr7 1/1 Running 0 6m39s 171.20.135.152 k8s-node03 <none> <none> myapp-85497bd9fb-sj22k 1/1 Running 0 6m37s 171.20.135.155 k8s-node03 <none> <none> myapp-85497bd9fb-tbcrv 1/1 Running 0 85m 171.20.135.149 k8s-node03 <none> <none> myapp-85497bd9fb-wgpwc 1/1 Running 0 85m 171.20.135.146 k8s-node03 <none> <none> myapp-85497bd9fb-x98hg 1/1 Running 0 6m38s 171.20.58.231 k8s-node02 <none> <none> myapp-85497bd9fb-z886v 1/1 Running 0 6m38s 171.20.58.232 k8s-node02 <none> <none>
取消 node01 节点的不可调度标签
$ kubectl uncordon k8s-node01 node/k8s-node01 uncordoned
4. drain - 特别说明
kubectl drain 操作会将相应节点上的旧 Pod 删除,并在可调度节点上面起一个对应的 Pod。当旧 Pod 没有被正常删除的情况下,新 Pod 不会起来。例如:旧 Pod 一直处于 Terminating 状态。
对应的解决方式是通过重启相应节点的 kubelet,或者强制删除该 Pod 。
# 重启发生`Terminating`节点的kubelet
systemctl restart kubelet
# 强制删除`Terminating`状态的Pod
kubectl delete pod <PodName> --namespace=<Namespace> --force --grace-period=0
5. 恢复被勿驱逐的节点
如果在执行 drain 命令时,勿将不该驱逐的 Pod 驱逐出去,例如如下情况
# 1.执行 drain 命令,驱逐 node01 节点上的Pod,由于node01部署了 metrics-server,因此发生报错,提示需要添加参数 --delete-emptydir-data
$ kubectl drain k8s-node01 --ignore-daemonsets --force
node/k8s-node01 cordoned
error: unable to drain node "k8s-node01" due to error:cannot delete Pods with local storage (use --delete-emptydir-data to override): kube-system/metrics-server-56cfc8b678-zvqpz, continuing command...
There are pending nodes to be drained:
k8s-node01
cannot delete Pods with local storage (use --delete-emptydir-data to override): kube-system/metrics-server-56cfc8b678-zvqpz
# 查看 metrics-server
$ kubectl get pod -n kube-system -o wide -w | grep metrics-server
metrics-server-56cfc8b678-zvqpz 1/1 Running 2 (2d1h ago) 2d1h 171.20.85.237 k8s-node01 <none> <none>
# 2. 再次执行 drain 命令,node01 上的 Pod都被驱逐了,但也让 calico、etrics-server等组件也被驱逐了
$ kubectl drain k8s-node01 --ignore-daemonsets --force --delete-emptydir-data
node/k8s-node01 already cordoned
Warning: ignoring DaemonSet-managed Pods: ingress-nginx/ingress-nginx-controller-cv9bj, kube-system/calico-node-45x9j, kube-system/kube-proxy-9qk4c
evicting pod test-quota/test-deploy-5587d8c7c4-mptk4
evicting pod default/myapp-85497bd9fb-m7zhs
evicting pod default/myapp-85497bd9fb-gbg7t
evicting pod default/myapp-85497bd9fb-xc7q7
evicting pod default/myapp-85497bd9fb-q4z5x
evicting pod default/myapp-85497bd9fb-f8jqn
evicting pod kube-system/coredns-5f98f8d567-cv75d
evicting pod kube-system/calico-kube-controllers-558d465845-78g6d
evicting pod kube-system/metrics-server-56cfc8b678-zvqpz
evicting pod default/myapp-85497bd9fb-d2s9d
evicting pod default/myapp-85497bd9fb-x9vdq
I0912 11:08:35.913958 761187 request.go:697] Waited for 1.021455195s due to client-side throttling, not priority and fairness, request: GET:https://10.20.1.139:6443/api/v1/namespaces/kube-system/pods/metrics-server-56cfc8b678-zvqpz
I0912 11:08:46.113856 761187 request.go:697] Waited for 1.222486642s due to client-side throttling, not priority and fairness, request: GET:https://10.20.1.139:6443/api/v1/namespaces/kube-system/pods/calico-kube-controllers-558d465845-78g6d
I0912 11:08:56.114006 761187 request.go:697] Waited for 1.222272943s due to client-side throttling, not priority and fairness, request: GET:https://10.20.1.139:6443/api/v1/namespaces/default/pods/myapp-85497bd9fb-d2s9d
pod/myapp-85497bd9fb-gbg7t evicted
pod/myapp-85497bd9fb-d2s9d evicted
pod/myapp-85497bd9fb-m7zhs evicted
pod/test-deploy-5587d8c7c4-mptk4 evicted
I0912 11:09:06.914431 761187 request.go:697] Waited for 1.022353159s due to client-side throttling, not priority and fairness, request: GET:https://10.20.1.139:6443/api/v1/namespaces/kube-system/pods/coredns-5f98f8d567-cv75d
pod/myapp-85497bd9fb-f8jqn evicted
pod/myapp-85497bd9fb-xc7q7 evicted
pod/calico-kube-controllers-558d465845-78g6d evicted
pod/coredns-5f98f8d567-cv75d evicted
pod/metrics-server-56cfc8b678-zvqpz evicted
pod/myapp-85497bd9fb-x9vdq evicted
pod/myapp-85497bd9fb-q4z5x evicted
node/k8s-node01 drained
如何让 calico 、metrics-server 等组件重新调度到node01 节点
# 删除 node01 节点的 SchedulingDisabled 标签
$ kubectl uncordon k8s-node01
node/k8s-node01 uncordoned
# 滚动更新pod,重新调度
$ kubectl rollout restart deployment -n kube-system coredns
deployment.apps/coredns restarted
$ kubectl rollout restart deployment -n kube-system metrics-server
deployment.apps/metrics-server restarted
$ kubectl rollout restart deployment -n kube-system calico-kube-controllers
deployment.apps/calico-kube-controllers restarted
# 再次查看 Pod
$ kubectl get pods -n kube-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
calico-kube-controllers-558d465845-f2mhr 1/1 Running 0 7m46s 171.20.32.129 k8s-master01 <none> <none>
calico-node-45x9j 1/1 Running 0 46d 10.20.1.140 k8s-node01 <none> <none>
calico-node-8rmt5 1/1 Running 0 46d 10.20.1.139 k8s-master01 <none> <none>
calico-node-fzs4f 1/1 Running 0 46d 10.20.1.142 k8s-node03 <none> <none>
calico-node-zhnlk 1/1 Running 0 46d 10.20.1.141 k8s-node02 <none> <none>
calico-typha-5b56944f9b-6gd7p 1/1 Running 0 46d 10.20.1.141 k8s-node02 <none> <none>
coredns-5c988c55b8-ckqnf 1/1 Running 0 30s 171.20.85.196 k8s-node01 <none> <none>
coredns-5c988c55b8-ljzxf 0/1 Running 0 27s 171.20.135.156 k8s-node03 <none> <none>
coredns-5f98f8d567-72vc7 1/1 Terminating 0 46d 171.20.58.192 k8s-node02 <none> <none>
etcd-k8s-master01 1/1 Running 1 46d 10.20.1.139 k8s-master01 <none> <none>
kube-apiserver-k8s-master01 1/1 Running 4 (2d15h ago) 32d 10.20.1.139 k8s-master01 <none> <none>
kube-controller-manager-k8s-master01 1/1 Running 39 46d 10.20.1.139 k8s-master01 <none> <none>
kube-proxy-9qk4c 1/1 Running 0 46d 10.20.1.140 k8s-node01 <none> <none>
kube-proxy-bm6rt 1/1 Running 0 46d 10.20.1.142 k8s-node03 <none> <none>
kube-proxy-dwz4c 1/1 Running 0 46d 10.20.1.139 k8s-master01 <none> <none>
kube-proxy-vsl77 1/1 Running 0 46d 10.20.1.141 k8s-node02 <none> <none>
kube-scheduler-k8s-master01 1/1 Running 37 (24h ago) 46d 10.20.1.139 k8s-master01 <none> <none>
metrics-server-56cfc8b678-znl7h 1/1 Running 1 (7m4s ago) 7m46s 171.20.58.230 k8s-node02 <none> <none>
6. Taints 和 Drain 的区别
在 Kubernetes 中,Taints(污点) 和 Drain(清空节点) 都是用于管理节点调度和 Pod 驱逐的机制,但它们的作用、实现方式和应用场景有显著区别。Taints 是一种更细粒度的调度控制工具,而 Drain 是一个高层的操作命令,用于节点维护。下面我从定义、功能、实现、场景等方面进行详细比较。
6.1 基本定义
Taints(污点):是一种节点属性,用于“排斥”某些 Pod 调度到该节点。只有 Pod 配置了匹配的 Tolerations(容忍) 才能调度到带有该 Taint 的节点。Taints 可以有三种效果(Effect):
NoSchedule:阻止新 Pod 调度到节点(不影响现有 Pod)。
PreferNoSchedule:优先避免调度新 Pod(但可能调度)。
NoExecute:阻止新 Pod 调度,并驱逐现有 Pod(如果 Pod 无匹配 Toleration)。
Drain(清空节点):是一个 kubectl drain 命令,用于安全地从节点上驱逐所有(或指定)Pod,并标记节点为不可调度(相当于 Cordon)。它不是一个独立机制,而是结合了 Cordon 和 Eviction 的过程。
6.2 功能比较
方面 | Taints (污点) | Drain (清空节点) |
---|---|---|
主要作用 | 控制 Pod 调度和驱逐,通过节点“污点”排斥不匹配 Pod。 | 安全驱逐节点上 Pod,并防止新 Pod 调度,用于节点维护。 |
对新 Pod | 通过 NoSchedule 效果阻止调度(需 Pod 有 Toleration 才能调度)。 | 标记节点为 unschedulable,阻止所有新 Pod 调度(忽略 DaemonSet)。 |
对现有 Pod | 通过 NoExecute 效果驱逐不匹配 Pod(渐进式)。 | 强制驱逐所有非 DaemonSet Pod(可配置忽略 PDB、local storage 等)。 |
自动性 | 手动添加/移除 Taint;节点控制器可自动添加(如 out-of-disk)。 | 手动执行命令;自动添加 unschedulable Taint。 |
影响范围 | 细粒度:可针对特定节点组(如专用硬件节点)隔离 Pod。 | 全局:针对整个节点清空,DaemonSet Pod 被忽略(会重建)。 |
恢复方式 | kubectl taint nodes |
kubectl uncordon |
示例命令 | kubectl taint nodes node1 key=value:NoSchedule | kubectl drain node1 –ignore-daemonsets |
6.3 实现机制的区别
Taints 的实现:
- Taints 存储在节点的 spec.taints 字段中,与 Pod 的 Tolerations 匹配。
- Kubernetes 调度器(Scheduler)在调度 Pod 时检查 Taints 和 Tolerations。
- 例如,添加 Taint 后,只有有 Toleration 的 Pod(如 DaemonSet)才能运行。节点控制器会自动添加特定 Taint(如 node.kubernetes.io/not-ready:NoExecute)来处理故障节点。
- 它更灵活,支持自定义键值对(如 dedicated=frontend:NoSchedule),用于节点亲和性反向控制。
Drain 的实现:
- Drain 内部会先执行 cordon(标记节点 unschedulable),相当于添加一个隐式的 Taint node.kubernetes.io/unschedulable:NoSchedule。
- 然后逐个驱逐 Pod(evict),尊重 PodDisruptionBudget (PDB),忽略 DaemonSet。
- 完成后,节点被“清空”,但 DaemonSet Pod 仍运行(因为它们忽略 unschedulable Taint)。
- Drain 不是直接使用 Taints,而是结合了 Taints 的效果(unschedulable Taint) + 手动驱逐逻辑。
关键点:Drain 会自动使用 Taint 来实现部分功能,但 Taints 可以独立使用,而不一定涉及驱逐。
6.4 使用场景
- Taints 适合:
- 专用节点隔离:如将 GPU 节点 Taint 为 gpu=true:NoSchedule,只允许有 GPU Toleration 的 Pod 调度。
- 故障处理:自动驱逐 Pod 到健康节点(NoExecute 效果)。
- 高级调度:结合 Node Affinity,实现复杂亲和规则。
- Drain 适合:
- 节点维护:如升级 kubelet、重启节点前清空 Pod,确保 Pod 迁移到其他节点。
- 临时不可用:快速标记节点维护中,防止新 Pod 调度。
- 两者结合:在 Drain 过程中,Kubernetes 会添加 node.kubernetes.io/unschedulable Taint 来阻止调度。如果你想在 Drain 后进一步隔离,可以添加自定义 Taint。
6.5 注意事项
- 兼容性:DaemonSet Pod 通常有内置 Toleration,能忽略 unschedulable Taint,因此 Drain 不会移除它们。
- 潜在问题:如果 Pod 有本地存储(如 emptyDir),Drain 可能失败,需要 –delete-emptydir-data 参数。
- 最佳实践:Drain 前备份 Pod 配置;使用 Taints 时,确保关键 Pod(如系统组件)有对应 Toleration。
参考链接
https://kubernetes.io/zh-cn/docs/reference/kubectl/generated/kubectl_cordon/
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 george_95@126.com