2. Kubernetes 故障域基础:节点、可用区、区域的概念,以及Pod调度与拓扑分布约束

2.1 故障域层次模型

Kubernetes 集群的物理或逻辑基础设施天然存在故障边界。理解这些边界是设计高可用应用交付的前提。故障域从下至上分为三个层级:节点、可用区、区域。

层级 Kubernetes 标签 故障范围 典型故障场景
节点 kubernetes.io/hostname 单台物理机或虚拟机 硬件故障、内核崩溃、磁盘损坏、网络链路中断
可用区 topology.kubernetes.io/zone 数据中心内独立供电/网络单元 机架断电、接入交换机故障、制冷失效
区域 topology.kubernetes.io/region 地理上隔离的完整数据中心群 自然灾害、骨干网中断、大规模电力故障
关键认知: 故障域隔离的核心目标是将应用副本分散到不同故障域中,确保单一故障域失效时,剩余副本仍能维持服务容量。在容量规划基准测试中,必须明确每个故障域可承载的 Pod 数量上限。

2.2 节点级故障域与 Pod 调度基础

节点是 Kubernetes 中最小的调度单元。Pod 调度器默认基于节点资源(CPU、内存)进行打分与绑定,但并未感知故障域分布。以下机制用于控制 Pod 在节点间的分布:

  • nodeSelector:基于节点标签的简单硬约束,用于将 Pod 定向到特定节点池。
  • nodeAffinity:支持 requiredDuringSchedulingIgnoredDuringExecution(硬约束)和 preferredDuringSchedulingIgnoredDuringExecution(软约束)两种语义。
  • Pod 反亲和性(podAntiAffinity):强制或偏好将同一应用的多个副本调度到不同节点上。
# 示例:使用 podAntiAffinity 确保每个节点最多运行一个副本
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 5
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - web-app
            topologyKey: kubernetes.io/hostname
容量规划陷阱: 仅使用节点级反亲和性,当集群跨多个可用区时,Pod 仍可能全部集中到同一个可用区。一旦该可用区故障,所有副本同时丢失。必须结合可用区拓扑约束。

2.3 可用区与区域:拓扑分布约束

Kubernetes 1.19+ 引入 Pod Topology Spread Constraints(Pod 拓扑分布约束),这是实现故障域隔离的推荐方式。它允许用户定义 Pod 在多个拓扑域(如节点、可用区、区域)之间的分布策略。

# 示例:将副本均匀分布到 3 个可用区
apiVersion: apps/v1
kind: Deployment
metadata:
  name: distributed-app
spec:
  replicas: 9
  template:
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: topology.kubernetes.io/zone
        whenUnsatisfiable: DoNotSchedule
        labelSelector:
          matchLabels:
            app: distributed-app
参数 说明 基准测试影响
maxSkew 任意两个拓扑域之间 Pod 数量的最大差值 决定故障域内 Pod 密度上限,直接影响单域故障时的容量损失
topologyKey 用于划分拓扑域的节点标签键 选择 zone 或 region 决定了隔离粒度
whenUnsatisfiable DoNotSchedule(硬约束)或 ScheduleAnyway(软约束) 硬约束保证隔离但可能阻塞调度;软约束允许调度但可能打破均匀分布
容量规划基准测试要点: 在演练前,必须确定每个可用区的节点数量、每个节点的可调度 Pod 上限(受 CNI IP 池、节点资源、DaemonSet 占用影响),然后根据 maxSkew 计算每个可用区可安全调度的副本数。例如:3 个可用区,每个可用区 5 个节点,每个节点最多 30 个 Pod,则每个可用区最多 150 个 Pod,maxSkew=1 时全局副本数上限为 450。

2.4 故障域隔离的架构视图

下图展示了跨区域、跨可用区、跨节点的三层故障域隔离架构,以及 Pod 在拓扑约束下的分布效果。

三层故障域隔离架构与 Pod 拓扑分布 区域 A (Region A) 可用区 A1 节点 A1-1 节点 A1-2 节点 A1-3 P P P P 可用区 A2 节点 A2-1 节点 A2-2 节点 A2-3 P P P P 区域 B (Region B) 可用区 B1 节点 B1-1 节点 B1-2 节点 B1-3 P P P P 可用区 B2 节点 B2-1 节点 B2-2 节点 B2-3 P P P P 区域 A 节点 区域 B 节点 Pod 副本

2.5 故障域隔离的容量规划公式

在进行故障域隔离演练的容量规划基准测试时,需要预先计算以下关键指标:

  1. 单节点最大 Pod 数:min(节点可分配IP数, 节点可分配CPU/Pod, 节点可分配内存/Pod)
  2. 单可用区最大 Pod 数:单节点最大Pod数 × 该可用区节点数
  3. 全局最大副本数(maxSkew=1):单可用区最大Pod数 × 可用区数量
  4. 单故障域失效后剩余容量:全局最大副本数 - 单可用区最大Pod数
基准测试验证点: 在演练中,通过模拟一个可用区完全故障,验证剩余可用区能否接管全部流量,且 Pod 不会因资源不足被驱逐。记录故障注入后的 Pod 重调度时间、服务降级比例、以及是否触发 PDB(PodDisruptionBudget)保护。

2.6 常见配置错误与避坑指南

错误模式 现象 根因 修复方案
仅使用 podAntiAffinity 且 topologyKey=hostname Pod 均匀分布在节点上,但全部集中在同一个可用区 未感知可用区拓扑 增加 topologySpreadConstraints 并设置 topologyKey=zone
maxSkew 设置过大 故障域内 Pod 数量严重不均,单域故障时容量损失过大 容忍度过高 将 maxSkew 设为 1 或 2,根据可用区数量调整
未设置 whenUnsatisfiable: DoNotSchedule 调度器在无法满足分布约束时仍将 Pod 调度到已饱和的故障域 软约束导致隔离失效 关键应用使用硬约束 DoNotSchedule
节点标签缺失或错误 拓扑分布约束不生效,Pod 调度行为异常 节点未正确标记 topology.kubernetes.io/zone 使用 kubectl label node 补全标签,或通过云厂商自动注入
演练前必检项: 使用 kubectl get nodes -o jsonpath='{.items[*].metadata.labels.topology\.kubernetes\.io/zone}' 确认所有节点已正确标记可用区。缺失标签的节点会被调度器忽略,导致拓扑约束失效。