1. 故障域概念:什么是故障域,为什么在 K8s 中需要划分故障域

1.1 故障域的定义与层级

故障域(Fault Domain)是指系统中一组共享单一故障点的物理或逻辑资源集合。当该故障点失效时,集合内的所有资源将同时不可用。在数据中心与 Kubernetes 集群中,故障域通常按物理隔离粒度划分为三个层级:Region(区域)、Availability Zone(可用区) 和 Rack(机架)。

故障域层级 典型故障范围 隔离粒度 K8s 对应标签
Region 整个数据中心或地理区域(地震、电力中断) 跨城市/跨洲 topology.kubernetes.io/region
Availability Zone 独立数据中心建筑或电力/网络域(AZ 级故障) 同城多机房 topology.kubernetes.io/zone
Rack 单机架电源/交换机故障 同机房内 kubernetes.io/hostname + 自定义拓扑键
关键认知:故障域的本质是共享风险组。同一机架上的两台服务器共享同一台 ToR 交换机和 PDU,因此它们属于同一个故障域。K8s 调度器必须感知这些边界,才能避免将应用副本全部部署在同一个故障域内。
故障域层级与故障范围 Region(区域) 故障范围:地震、大面积电力中断、骨干网络故障 隔离粒度:跨城市 / 跨洲 Availability Zone(可用区) 故障范围:单数据中心建筑火灾、整层交换机故障 隔离粒度:同城多机房 Rack(机架) 故障范围:ToR 交换机宕机、PDU 跳闸、电源模块失效 隔离粒度:同机房内单机架

1.2 为什么 Kubernetes 需要划分故障域

Kubernetes 的调度器默认以 Pod 为最小单位进行调度,但它并不天然感知底层物理拓扑。如果不显式划分故障域,调度器可能将同一个 Deployment 的所有副本全部调度到同一台物理机或同一个机架上,导致单点故障引发整个应用不可用。划分故障域的核心目的包括:

  • 高可用与容灾:将应用副本分散到不同 AZ 或 Rack,确保单个故障域失效时仍有副本提供服务。
  • 流量与负载均衡:避免所有流量集中到同一网络路径或同一组物理节点,降低局部过载风险。
  • 可观测性边界:故障域是告警聚合和指标下钻的自然维度,便于快速定位故障影响范围。
  • 资源预留与成本控制:通过拓扑约束(Topology Spread Constraints)和 Pod 反亲和性,精确控制资源分布策略。
实践案例:某在线电商平台在双 11 大促期间,由于未配置 Pod 反亲和性,导致 80% 的订单处理 Pod 集中在同一个 AZ 内。该 AZ 因电力闪断整体宕机 3 分钟,造成数十万订单失败。事后通过添加 topologySpreadConstraints 将副本均匀分布到 3 个 AZ,单 AZ 故障时仅损失 33% 的容量,系统仍可降级运行。

1.3 故障域在 K8s 中的表达方式

Kubernetes 通过 Node 标签(Labels) 和 拓扑键(Topology Keys) 来表达故障域。每个 Node 在加入集群时,云厂商或运维人员会为其打上对应的拓扑标签:

# 查看节点拓扑标签示例
kubectl get nodes --show-labels

# 输出片段(以阿里云 ACK 为例)
node-1  labels: ...
  topology.kubernetes.io/region=cn-hangzhou
  topology.kubernetes.io/zone=cn-hangzhou-f
  kubernetes.io/hostname=node-1
  failure-domain.beta.kubernetes.io/region=cn-hangzhou
  failure-domain.beta.kubernetes.io/zone=cn-hangzhou-f

在 Pod 调度时,通过 topologySpreadConstraints 或 podAntiAffinity 引用这些拓扑键,即可实现故障域感知的分布策略:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 6
  template:
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: ScheduleAnyway
注意:旧版标签 failure-domain.beta.kubernetes.io/region 和 failure-domain.beta.kubernetes.io/zone 已被弃用,建议统一使用 topology.kubernetes.io/region 和 topology.kubernetes.io/zone。如果集群中同时存在新旧标签,调度器优先使用新版标签。
K8s 故障域拓扑标签与调度关系 Node 拓扑标签 region=cn-hangzhou zone=cn-hangzhou-f hostname=node-1 region=cn-hangzhou zone=cn-hangzhou-g hostname=node-2 region=cn-hangzhou zone=cn-hangzhou-h hostname=node-3 Kube-Scheduler topologySpreadConstraints Pod 分布(6副本) Pod-A1 → zone-f (node-1) Pod-A2 → zone-g (node-2) Pod-A3 → zone-h (node-3) Pod-B1 → zone-f (node-1) Pod-B2 → zone-g (node-2) Pod-B3 → zone-h (node-3) 每个 zone 最多 2 个 Pod maxSkew=1 保证均匀分布

1.4 故障域划分对可观测性的影响

在指标采集与告警分层设计中,故障域是天然的下钻维度。没有故障域标签的指标是“平面化”的,无法区分故障是局部机架问题还是整个区域灾难。划分故障域后,可观测性系统可以实现:

  • 指标多维聚合:按 region、zone、hostname 聚合 CPU、内存、网络等资源指标,快速识别异常范围。
  • 告警分层抑制:当某个 AZ 整体宕机时,上层 Region 告警应抑制该 AZ 内所有主机级告警,避免告警风暴。
  • 故障域感知的 SLO 计算:计算跨 AZ 部署的应用可用性时,需排除单个 AZ 故障对整体 SLO 的影响。
可观测性最佳实践:在 Prometheus 指标中保留 label_region、label_zone、label_rack 标签,并在 Alertmanager 中配置基于故障域的告警分组与抑制规则。例如:
group_by: ['region', 'zone']
inhibit_rules: [source_match: {severity: 'critical', region: 'cn-hangzhou'}, target_match: {severity: 'warning', zone: 'cn-hangzhou-f'}]

1.5 常见误区与避坑指南

误区 后果 正确做法
认为 K8s 默认会跨故障域调度 Pod 可能全部集中在同一节点或机架 显式配置 topologySpreadConstraints 或 podAntiAffinity
只划分 Region 不划分 Zone 无法感知同城多机房故障 至少划分到 Zone 级别,关键应用划分到 Rack
标签命名不规范 调度器无法识别拓扑键,策略失效 统一使用 topology.kubernetes.io/* 标准标签
告警未按故障域分组 单机架故障触发数百条告警 按 region + zone 分组,配置抑制规则
避坑提醒:在混合云或自建机房场景中,云厂商自动注入拓扑标签,但自建集群需要运维人员手动为每个 Node 打标签。务必在集群初始化阶段通过 kubelet --node-labels 或自动化工具(如 Ansible、Terraform)统一注入,避免后期遗漏导致调度策略失效。