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 调度器必须感知这些边界,才能避免将应用副本全部部署在同一个故障域内。
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。如果集群中同时存在新旧标签,调度器优先使用新版标签。
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)统一注入,避免后期遗漏导致调度策略失效。