3. 故障域概念与设计

3.1 故障域定义

故障域(Failure Domain)是平台工程中隔离故障影响范围的基本单位。在 Kubernetes 和 IDP 环境中,故障域通常分为三个层级:可用区(Zone)、集群(Cluster)和节点(Node)。每个层级对应不同的物理或逻辑隔离边界,决定了故障传播的半径。

故障域层级 定义 典型故障场景 隔离粒度
可用区(Zone) 同一地域内独立的数据中心或电力/网络单元 区域电力中断、光纤断裂、AZ 级网络故障 物理数据中心级
集群(Cluster) 一组控制面和数据面节点组成的 Kubernetes 集群 API Server 过载、etcd 脑裂、集群证书过期 逻辑控制面级
节点(Node) 单个物理机或虚拟机,运行 kubelet 和容器 磁盘故障、OOM、内核 Panic、硬件老化 单机级
关键原则:故障域层级越高,故障影响范围越大,恢复时间越长。IDP 设计应优先保证跨可用区冗余,其次才是集群内节点级反亲和。

3.2 IDP 中的故障域映射策略

平台工程 IDP 需要将抽象的工作负载(Helm Release、微服务、中间件)映射到底层故障域。映射策略决定了当某个故障域失效时,哪些工作负载会同时受损。

  • Zone → Cluster 映射:每个可用区部署一个或多个 Kubernetes 集群,集群内的节点全部位于同一可用区。这种映射简单直接,但跨 AZ 流量需要集群间网络打通。
  • Cluster → Node 映射:集群内的节点按可用区打上 topology.kubernetes.io/zone 标签,通过 NodeAffinity 和 PodAntiAffinity 控制 Pod 分布。
  • Helm Release → 故障域:在 Helm values 中声明 topologySpreadConstraints 和 affinity 规则,将 Release 内的 Pod 分散到不同故障域。
实践建议:在 IDP 的 Helm Chart 模板中,将故障域配置抽象为全局变量 .Values.global.topology.failureDomain,避免在每个子 Chart 中重复定义。
IDP 故障域映射策略 可用区 A 可用区 B 可用区 C 集群 cluster-az1 集群 cluster-az2 集群 cluster-az3 node-1 node-2 node-3 node-4 node-5 node-6 node-7 Pod-A1 Pod-A2 Pod-B1 Pod-B2 Pod-C1 每个可用区独立部署集群,Pod 通过反亲和策略分散到不同节点,实现故障域隔离

3.3 反亲和性设计原则

反亲和性(Anti-Affinity)是故障域隔离的核心实现手段。在 Helm Chart 中通过 podAntiAffinity 和 topologySpreadConstraints 控制 Pod 分布,确保同一工作负载的多个副本不会落在同一故障域内。

3.3.1 反亲和性策略对比

策略类型 Kubernetes 资源 作用范围 适用场景
PodAntiAffinity spec.affinity.podAntiAffinity 节点级(hostname) 严格禁止同节点部署两个相同副本
TopologySpreadConstraints spec.topologySpreadConstraints Zone / Region / 自定义拓扑 跨可用区均匀分布,容忍部分倾斜
NodeAntiAffinity spec.affinity.nodeAntiAffinity 节点标签选择器 避免部署到特定硬件或网络属性的节点

3.3.2 Helm 模板中的反亲和配置示例

# values.yaml
affinity:
  podAntiAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
        - key: app.kubernetes.io/name
          operator: In
          values:
          - {{ .Values.nameOverride | default .Chart.Name }}
      topologyKey: kubernetes.io/hostname
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: ScheduleAnyway
    labelSelector:
      matchLabels:
        app.kubernetes.io/name: {{ .Values.nameOverride | default .Chart.Name }}
避坑提示:requiredDuringSchedulingIgnoredDuringExecution 是硬约束,当集群节点数少于副本数时会导致 Pod 无法调度。容量突增场景建议使用 preferredDuringSchedulingIgnoredDuringExecution 或配合 topologySpreadConstraints 的 ScheduleAnyway 模式。

3.3.3 反亲和性设计原则总结

  • 分层隔离:先保证跨可用区(Zone)分布,再保证跨节点(Host)分布,最后考虑跨机架或跨交换机。
  • 软硬结合:核心服务(etcd、API Server)使用硬反亲和;普通微服务使用软反亲和 + TopologySpreadConstraints。
  • 容量感知:反亲和规则必须与集群容量规划联动,避免因约束过严导致资源碎片。
  • Helm 参数化:将反亲和策略暴露为 values 参数,允许运维人员在突增时动态调整约束强度。
反亲和性设计原则分层模型 第1层:跨可用区(Zone)— topology.kubernetes.io/zone 第2层:跨节点(Host)— kubernetes.io/hostname 第3层:跨机架(Rack)— topology.kubernetes.io/rack(自定义标签) 每层约束强度递减,但故障隔离粒度更细;建议至少实现前两层

3.4 故障域与 Helm 水位预测的关联

在容量突增场景下,故障域设计直接影响 Helm 水位预测的准确性。如果反亲和约束过于严格,突增时 Pod 可能因找不到满足约束的节点而处于 Pending 状态,导致实际水位低于预期。因此,水位预测模型必须将故障域约束作为输入参数,计算有效可调度容量。

核心公式:有效可调度容量 = 集群总容量 − 故障域约束损耗 − 已有资源占用。其中故障域约束损耗 = Σ(每个故障域内因反亲和规则无法调度的资源量)。