K8S:服务迁移与异常节点隔离
服务迁移是指将应用程序从一个节点或一组节点移动到另一个节点或一组节点。通常在以下情况下需要进行服务迁移:
- 节点维护:例如节点升级或硬件维护。
- 负载均衡:重新分配负载以防止某些节点过载。
- 资源优化:将资源密集型应用迁移到更高性能的节点。
手动迁移
1.标记节点不可调度:
使用 kubectl cordon
命令将节点标记为不可调度,防止新的 Pod 被调度到该节点。
kubectl cordon <node_name>
2.驱逐节点上的 Pod:
使用 kubectl drain
命令驱逐节点上的所有 Pod。这个命令会安全地终止 Pod,并将它们重新调度到其他可用的节点。
kubectl drain <node_name> --ignore-daemonsets --delete-local-data
3.节点维护或迁移完成后重新启用节点:
使用 kubectl uncordon
命令将节点标记为可调度。
kubectl uncordon <node_name>
手动异常节点隔离
异常节点隔离是指将集群中发生故障或不稳定的节点隔离开,以防止其影响整个集群的稳定性。通常在以下情况下需要进行异常节点隔离:
- 节点故障:如硬件故障、网络故障等。
- 节点过载:节点资源耗尽,无法正常运行工作负载。
- 节点不稳定:节点频繁出现问题或无法正常通信。
cordon
1.标记节点不可调度:
使用 kubectl cordon
命令将节点标记为不可调度,防止新的 Pod 被调度到该节点。
kubectl cordon <node_name>
2.驱逐节点上的 Pod:
使用 kubectl drain
命令驱逐节点上的所有 Pod。这个命令会安全地终止 Pod,并将它们重新调度到其他可用的节点。
kubectl drain <node_name> --ignore-daemonsets --delete-local-data
3.节点维护或迁移完成后重新启用节点:
使用 kubectl uncordon
命令将节点标记为可调度。
kubectl uncordon <node_name>
1.标记节点不可调度:
使用 kubectl cordon
命令将节点标记为不可调度,防止新的 Pod 被调度到该节点。
kubectl cordon <node_name>
2.驱逐节点上的 Pod:
使用 kubectl drain
命令驱逐节点上的所有 Pod。这个命令会安全地终止 Pod,并将它们重新调度到其他可用的节点。
kubectl drain <node_name> --ignore-daemonsets --delete-local-data
patch
#隔离
kubectl patch node <node_name> -p ‘{“spec”:{“unschedulable”:true}}’
#恢复
kubectl patch node <node_name> -p ‘{“spec”:{“unschedulable”:false}}’
unschedule_node.yaml
文件隔离(可能会报错)
unschedule_node.yaml
文件通常是用于配置 Kubernetes 节点不可调度的。将节点设置为不可调度状态意味着新的 Pod 将不会调度到该节点上,但是现有的 Pod 不会被自动迁移。使用drain驱逐这些 Pod。
配置文件 unschedule_node.yaml
apiVersion: v1
kind: Node
metadata:
name: <node_name>
spec:
unschedulable: true
# 对node状态进行修改
# kubectl replace -f unschedule_node.yaml
# 观察node状态,是否包含 SchedulingDisabled
# kubectl get nodes
# 报错
# The Node "k8s-node1" is invalid: spec.podCIDRs: Forbidden: node updates may not change podCIDR except from "" to valid
使用自动故障检测和隔离
使用 Kubernetes 的节点健康检查和自愈功能,例如使用 NodeStatus
和 PodDisruptionBudget
。如果节点被标记为不可达,Kubernetes 会自动将其隔离并重新调度其上的 Pod。
NodeStatus
NodeStatus
是 Kubernetes 节点的状态信息。它包含了节点的各种状态,包括节点是否可达、可用资源、运行的 Pod 等信息。NodeStatus
是由 Kubernetes 控制平面自动管理的,但了解它的内容和使用方法对于集群管理是很重要的。
查看节点状态
使用 kubectl get nodes
和 kubectl describe node <node_name>
命令查看节点的状态信息。
kubectl get nodes
#输出
NAME STATUS ROLES AGE VERSION
node1 Ready master 5d v1.20.0
node2 Ready <none> 5d v1.20.0
要查看具体节点的详细状态信息
kubectl describe node node1
#输出
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
MemoryPressure False Wed, 04 Aug 2021 16:25:50 +0000 Wed, 04 Aug 2021 16:13:37 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Wed, 04 Aug 2021 16:25:50 +0000 Wed, 04 Aug 2021 16:13:37 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Wed, 04 Aug 2021 16:25:50 +0000 Wed, 04 Aug 2021 16:13:37 +0000 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Wed, 04 Aug 2021 16:25:50 +0000 Wed, 04 Aug 2021 16:14:37 +0000 KubeletReady kubelet is posting ready status
PodDisruptionBudget (PDB)
PodDisruptionBudget
(PDB) 是 Kubernetes 提供的一种机制,用于确保在进行主动的 Pod 终止操作时,有足够数量的 Pod 处于可用状态,从而保护应用程序的高可用性。
创建 PDB 的示例 YAML 文件:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: my-app
该 PDB 确保匹配标签 app: my-app
的 Pod 至少有 2 个可用。
也可以指定 maxUnavailable
,而不是 minAvailable
:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-pdb
spec:
maxUnavailable: 1
selector:
matchLabels:
app: my-app
表示最多可以有 1 个 Pod 不可用。
应用 PDB
使用 kubectl apply
命令创建或更新 PDB:
kubectl apply -f my-pdb.yaml
查看 PDB
使用 kubectl get pdb
命令查看集群中的 PDB:
kubectl get pdb
#输出
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
my-pdb 2 N/A 0 5m
多节点隔离
要一次隔离多个节点,可以通过编写一个脚本来批量执行 kubectl cordon
命令,也可以使用 kubectl
命令的批量处理能力。
使用脚本批量隔离多个节点:
#!/bin/bash
# 节点列表
nodes=("node_name1" "node_name2" "node_name3")
# 遍历节点列表
for node in "${nodes[@]}"; do
# 标记节点为不可调度
kubectl cordon "$node"
# 驱逐节点上的 Pod
kubectl drain "$node" --ignore-daemonsets --delete-local-data --force
done
使用 kubectl 批量处理:
可以将多个节点的名称放在一个文件中,并使用 xargs
命令批量处理。
1.创建一个包含节点名称的文件,例如 nodes.txt
:
node_name1
node_name2
node_name3
2.使用 xargs
批量执行 kubectl cordon
命令:
cat nodes.txt | xargs -I {} kubectl cordon {}
cat nodes.txt | xargs -I {} kubectl drain {} --ignore-daemonsets --delete-local-data --force
使用单行命令批量隔离:
for node in node_name1 node_name2 node_name3; do
kubectl cordon $node
kubectl drain $node --ignore-daemonsets --delete-local-data --force
done