K8S:服务迁移与异常节点隔离

服务迁移是指将应用程序从一个节点或一组节点移动到另一个节点或一组节点。通常在以下情况下需要进行服务迁移:

  1. 节点维护:例如节点升级或硬件维护。
  2. 负载均衡:重新分配负载以防止某些节点过载。
  3. 资源优化:将资源密集型应用迁移到更高性能的节点。

手动迁移

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. 节点故障:如硬件故障、网络故障等。
  2. 节点过载:节点资源耗尽,无法正常运行工作负载。
  3. 节点不稳定:节点频繁出现问题或无法正常通信。

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 的节点健康检查和自愈功能,例如使用 NodeStatusPodDisruptionBudget。如果节点被标记为不可达,Kubernetes 会自动将其隔离并重新调度其上的 Pod。

NodeStatus

NodeStatus 是 Kubernetes 节点的状态信息。它包含了节点的各种状态,包括节点是否可达、可用资源、运行的 Pod 等信息。NodeStatus 是由 Kubernetes 控制平面自动管理的,但了解它的内容和使用方法对于集群管理是很重要的。

查看节点状态

使用 kubectl get nodeskubectl 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