本文主要介绍节点发生故障时,业务负载如何进行容灾和迁移的方案。
Kubernetes 节点承载着用户众多线上业务的运行。容器服务推荐业务负载采用多副本、多节点打散部署的方式,避免单节点故障时,Pod 短时间无法完成迁移而造成业务整体不可用的情况。
多副本、多节点打散部署的示例 YAML 如下所示,更多相关说明,请参见 Kubernetes 官方文档。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 3 # 采用多副本部署 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 topologySpreadConstraints: # 控制 Pod 在集群的拓扑上如何分布。 - maxSkew: 1 # 控制 Pod 的最大偏差数量。设置为 1,表示任意两个 Node 中,属于 app=nginx 的 Pod 数量之差不可以超过 1。 topologyKey: "kubernetes.io/hostname" # 拓扑域,当前配置表示节点级别分布;topology.kubernetes.io/zone 表示区域级别分布。 whenUnsatisfiable: ScheduleAnyway # 设置当 Pod 的分布无法满足约束时的行为,可取值:DoNotSchedule(不调度)或 ScheduleAnyway(尽管约束得不到满足,但还是会尽力调度)。 labelSelector: # 表示 Pod 的 Label 匹配。 matchLabels: app: nginx
但实际业务中因种种原因,可能遇到节点故障导后 Pod 无法迁移导致业务受损的情况,本文围绕节点故障场景,提供多种负载(尤其是 StatefulSet 类型负载)的容灾迁移方案,帮助用户进行快速止损。
在节点发生故障时(人工介入恢复前),不同 Kubernetes 资源有不同的表现。
node.kubernetes.io.unreachable
污点。说明
节点状态的时长由如下 KCM 参数控制:
说明
节点状态的时长由 kube-apiserver 参数控制:
NotReady:NoExecute
的容忍时长,单位为秒,默认 300 秒。默认情况下这一容忍度会被添加到尚未具有此容忍度的每个 Pod 中。Unreachable:NoExecute
的容忍时长,单位为秒,默认 300 秒。默认情况下这一容忍度会被添加到尚未具有此容忍度的每个 Pod 中。说明
如果 Pod 绑定了存储卷声明(PVC),有状态负载的迁移会伴随着存储卷(PV)的释放和重绑动作。节点故障后,关联的存储卷也无法与节点解绑。
subsets.notReadyAddresses
参数下会增加 NotReady 的 Pod 信息,此时 Service 流量将不会到达 NotReady 状态的 Pod。人工介入恢复前,还需要注意如下使用限制:
RollingUpdate
。strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 25% maxSurge: 25%
rollout
命令来完成无状态负载 下 Pod 的快速重建。kubectl rollout restart deployment/nginx
说明
deployment/nginx
为无状态负载名称/其下 Pod 名称
,请替换为您实际的负载名称。
deployment.apps/nginx restarted
通过强制删除 Pod,等待独占资源解绑并释放来完成负载迁移。具体步骤如下:
说明
独占资源没有与原 Pod 解绑时,新 Pod 会卡在 Creating 状态。
预期返回结果如下:kubectl delete pod nginx-1 --force
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely. pod "nginx-1" force deleted
预期返回结果如下:kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-0 1/1 Running 0 100m 192.168.0.108 192.168.0.12 <none> <none> nginx-1 0/1 ContainerCreating 0 8s <none> 192.168.0.13 <none> <none>
预期返回结果如下:kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-1 1/1 Running 0 6m 192.168.0.63 192.168.0.13 <none> <none> nginx-0 1/1 Running 0 114m 192.168.0.108 192.168.0.12 <none> <none>
通过为故障节点打上指定污点,触发 NodeOutOfServiceVolumeDetach 特性门控来快速完成负载迁移。具体步骤如下:
说明
节点状态不可以为 运行中 或节点对应的 ECS 实例状态不可以为 重启中,否则会导致节点出现 mount 挂载残留、Pod 读写异常等一系列不可预期的行为。
node.kubernetes.io/out-of-service
污点。kubectl get statefulset <sts-name> -o jsonpath="{.spec.template.spec.tolerations}"
说明
<sts-name>
为有状态负载的名称,请替换为您实际的负载名称。
key
的取值表示 Pod 容忍的污点(即容忍了temp
这个污点 );若返回结果为空,则表示没有容忍任何污点:[{"key":"temp","effect":"NoSchedule","operator":"Exists"}]
kubectl taint nodes <node-name> node.kubernetes.io/out-of-service=nodeshutdown:NoExecute
说明
请替换<node-name>
为您实际的故障节点名称。