4. 故障域模型:单AZ故障、跨AZ冗余、机架级故障、物理区域隔离
在Kubernetes集群中,故障域(Failure Domain)是划分资源隔离边界的基础单元。OPA策略需要精确验证集群是否按照预期的故障域模型进行调度与约束。本节将四种核心故障域模型进行结构化拆解,并给出对应的OPA策略测试边界条件。
4.1 故障域模型对比总览
| 故障域模型 | 隔离粒度 | 典型标签键 | OPA关注点 |
|---|---|---|---|
| 单AZ故障 | 可用区(Availability Zone) | topology.kubernetes.io/zone |
Pod是否全部集中在同一AZ |
| 跨AZ冗余 | 可用区(跨多个AZ) | topology.kubernetes.io/zone |
工作负载副本是否分布在≥2个AZ |
| 机架级故障 | 物理机架(Rack) | topology.kubernetes.io/rack |
同一机架是否承载过多关键Pod |
| 物理区域隔离 | 数据中心/物理站点 | topology.kubernetes.io/region |
跨站点流量与数据合规边界 |
策略测试要点: 每种故障域模型在OPA中对应不同的
input路径与data查询模式。测试用例必须覆盖“违反约束”与“合规通过”两种状态,并验证边界值(如AZ数量=1、副本数=2等)。
4.2 单AZ故障模型与OPA验证
单AZ故障模型假设整个可用区不可用。OPA策略应确保关键工作负载不将所有副本部署在同一个AZ内。测试边界条件包括:
- 边界1: 当集群只有一个AZ标签的节点时,策略应允许调度(无法跨AZ)。
- 边界2: 当副本数=1且节点分布在多个AZ时,策略应允许(单副本无法跨AZ)。
- 边界3: 当副本数≥2且所有Pod的
zone标签相同时,策略应拒绝。
# OPA策略片段:拒绝所有Pod在同一AZ
deny[msg] {
pods := input.review.object.spec.template.spec.containers
zones := {zone | some i; zone := input.review.object.spec.template.spec.nodeSelector["topology.kubernetes.io/zone"]}
count(zones) == 1
msg := sprintf("所有Pod集中在同一AZ: %v", [zones])
}
测试建议: 使用
mock数据构造一个包含3个节点、2个AZ的集群,分别测试Pod分布在1个AZ和2个AZ的场景。断言deny规则在跨AZ时不应触发。
4.3 跨AZ冗余模型与OPA验证
跨AZ冗余要求工作负载的副本必须分布在至少两个不同的可用区。这是生产环境中最常见的故障域策略。OPA测试需要覆盖以下边界:
- 边界1: 副本数=2且分布在2个不同AZ → 合规。
- 边界2: 副本数=3且分布在2个不同AZ → 合规(允许部分AZ承载多个副本)。
- 边界3: 副本数=2且分布在1个AZ → 违规。
- 边界4: 副本数=1且分布在1个AZ → 策略应允许(单副本无法跨AZ)。
常见陷阱: 跨AZ冗余策略容易忽略“单副本”场景。如果策略强制要求副本数≥2且跨AZ,则单副本Deployment会被拒绝,导致开发环境无法部署。建议在策略中加入
count(replicas) < 2豁免条件。
# OPA策略片段:跨AZ冗余检查(含单副本豁免)
deny[msg] {
replicas := input.review.object.spec.replicas
replicas >= 2
zones := {zone | some i; input.review.object.spec.template.spec.nodeSelector["topology.kubernetes.io/zone"]}
count(zones) < 2
msg := sprintf("副本数=%d,但仅分布在%d个AZ,需要至少2个AZ", [replicas, count(zones)])
}
4.4 机架级故障模型与OPA验证
机架级故障模型关注物理机架的单点失效风险。在超大规模集群中,同一机架的网络交换机或电源故障可能导致大量Pod同时离线。OPA策略应限制同一机架上关键工作负载的Pod数量。
| 测试场景 | 机架标签分布 | 预期结果 |
|---|---|---|
| 单机架承载3个Pod | rack-01: 3个Pod | 违规(超过阈值2) |
| 双机架各承载2个Pod | rack-01: 2个, rack-02: 2个 | 合规 |
| 单机架承载2个Pod | rack-01: 2个 | 合规(等于阈值) |
| 单机架承载1个Pod | rack-01: 1个 | 合规 |
# OPA策略片段:机架级Pod数量限制(阈值=2)
deny[msg] {
rack_pods := {rack: count(pods) |
some pod in input.review.object.spec.template.spec.containers
rack := pod.nodeSelector["topology.kubernetes.io/rack"]
pods := [pod]
}
some rack, count
rack_pods[rack] == count
count > 2
msg := sprintf("机架 %v 承载 %d 个Pod,超过阈值2", [rack, count])
}
边界条件: 当集群中所有节点都属于同一个机架时(如小型开发集群),策略应允许调度,否则无法部署任何工作负载。建议在策略中增加
count(distinct_racks) < 2豁免。
4.5 物理区域隔离模型与OPA验证
物理区域隔离通常用于跨数据中心或跨地域部署场景。OPA策略需要验证工作负载是否被限制在指定的物理区域内,同时禁止跨区域的数据访问。测试边界包括:
- 边界1: Pod的
region标签必须匹配命名空间注解中声明的允许区域。 - 边界2: 跨区域Service的
externalName引用必须被拒绝。 - 边界3: 允许区域列表为空时,策略应拒绝所有Pod(安全默认)。
- 边界4: 允许区域列表包含通配符
*时,策略应允许所有区域。
# OPA策略片段:物理区域隔离检查
deny[msg] {
allowed_regions := data.namespaces[input.review.object.metadata.namespace].allowed_regions
pod_region := input.review.object.spec.template.spec.nodeSelector["topology.kubernetes.io/region"]
not allowed_regions[pod_region]
msg := sprintf("Pod区域 %v 不在命名空间允许区域 %v 中", [pod_region, allowed_regions])
}
测试数据构造: 创建两个命名空间
prod-cn(允许区域: cn-east, cn-west)和prod-eu(允许区域: eu-west)。分别测试Pod部署在允许区域和禁止区域时的策略响应。
4.6 故障域模型综合SVG架构图
下图展示了四种故障域模型在Kubernetes集群中的层级关系与OPA策略作用点:
4.7 故障域模型OPA测试用例设计
针对上述四种模型,设计以下OPA测试用例矩阵,确保边界条件全覆盖:
| 测试ID | 故障域模型 | 输入条件 | 期望结果 |
|---|---|---|---|
| FD-001 | 单AZ故障 | 副本数=3,所有Pod zone=cn-east-1 | 拒绝 |
| FD-002 | 单AZ故障 | 副本数=1,Pod zone=cn-east-1 | 允许(单副本豁免) |
| FD-003 | 跨AZ冗余 | 副本数=2,zone分布: cn-east-1, cn-east-2 | 允许 |
| FD-004 | 跨AZ冗余 | 副本数=2,zone分布: cn-east-1, cn-east-1 | 拒绝 |
| FD-005 | 机架级故障 | rack-01承载3个Pod,阈值=2 | 拒绝 |
| FD-006 | 机架级故障 | rack-01承载2个Pod,阈值=2 | 允许 |
| FD-007 | 物理区域隔离 | 命名空间允许区域: [cn-east],Pod region=cn-west | 拒绝 |
| FD-008 | 物理区域隔离 | 命名空间允许区域: [*],Pod region=eu-west | 允许 |
边界条件提醒: 测试用例FD-002和FD-006是容易被忽略的边界场景。单副本Pod无法跨AZ,单机架集群无法跨机架。OPA策略必须包含
count(replicas) < 2或count(distinct_racks) < 2的豁免逻辑,否则会导致小规模集群无法部署任何工作负载。
4.8 故障域模型OPA测试执行流程
以下SVG图展示了从策略定义到测试执行的完整流程:
测试执行建议: 使用
opa test --coverage命令生成测试覆盖率报告,确保每条策略规则都被至少一个正向用例和一个反向用例覆盖。对于故障域模型,特别关注count()聚合函数和some迭代的边界条件。