3. Rego语言基础:Rego语法入门、规则、表达式、查询
Rego 是 OPA 的策略语言,专为在复杂云原生环境中表达可读、可组合的访问控制与合规规则而设计。本章从零开始,系统讲解 Rego 的核心语法、规则结构、表达式类型以及查询方式,为后续实现故障域划分的架构边界验证打下坚实基础。
3.1 Rego 语言核心设计理念
Rego 并非通用编程语言,而是一种声明式查询语言,其设计围绕三个核心理念:
| 理念 | 说明 | 与故障域验证的关系 |
|---|---|---|
| 声明式 | 描述“策略应该是什么”,而非“如何执行策略” | 直接声明“Pod 必须与 Node 在同一可用区”,无需编写遍历逻辑 |
| 不可变数据 | 输入数据只读,规则只产生新值,无副作用 | 保证多次评估结果一致,适合审计与合规场景 |
| 基于文档模型 | 所有数据(输入、输出、规则)都是嵌套的 JSON 文档 | 天然适配 Kubernetes 资源清单、云服务商元数据等 JSON 格式 |
学习提示: 如果你有 SQL 或 XPath 经验,会发现 Rego 的声明式风格非常相似——你描述“想要什么结果”,引擎自动推导出如何得到它。
3.2 Rego 语法入门:包、导入与注释
每个 Rego 文件以 package 声明开始,用于组织策略模块。导入语句用于引入其他包或数据源。
package example.availability_zones
import data.kubernetes.pods
import data.cloud.provider.zones
# 这是一个注释,用于说明规则意图
# 检查 Pod 是否部署在允许的可用区中
| 语法元素 | 示例 | 说明 |
|---|---|---|
package |
package boundary.zone |
定义当前模块的命名空间,用于规则引用 |
import |
import data.kubernetes |
引入外部数据或子包,简化后续引用路径 |
# |
# 这是一行注释 |
单行注释,用于解释规则逻辑 |
3.3 规则:Rego 的核心构建块
规则是 Rego 的基本单元,分为完整规则和部分规则。每条规则定义一组条件,当条件满足时产生一个值。
3.3.1 完整规则
完整规则返回一个布尔值或标量,常用于定义全局策略开关或常量。
# 完整规则:返回布尔值
default allowed_zones := ["us-east-1a", "us-east-1b"]
# 完整规则:返回字符串
zone_separator := "-"
3.3.2 部分规则
部分规则返回一个集合或对象,通常用于过滤数据或生成结构化结果。
# 部分规则:返回所有符合条件 Pod 的集合
valid_pods[pod] {
pod := input.pods[_]
pod.metadata.labels.tier == "frontend"
}
# 部分规则:返回对象,键为 Pod 名称,值为所在可用区
pod_zone_map[pod_name] = zone {
pod := input.pods[_]
pod_name := pod.metadata.name
zone := pod.spec.nodeSelector["topology.kubernetes.io/zone"]
}
关键区别: 完整规则使用
:= 赋值,部分规则使用 [变量] 或 [键] = 值 形式,且必须包含至少一个迭代条件。
3.4 表达式:构建规则逻辑的基石
Rego 表达式用于在规则体内进行条件判断、数据访问和计算。以下是故障域验证中最常用的表达式类型:
| 表达式类型 | 语法示例 | 用途 |
|---|---|---|
| 相等/不相等 | zone == "us-east-1a" / zone != "us-east-1c" |
检查可用区是否匹配或排除 |
| 比较 | count(replicas) > 2 |
验证副本数是否满足跨区要求 |
| 成员关系 | zone in allowed_zones |
检查可用区是否在允许列表中 |
| 迭代 | pod := input.pods[_] |
遍历 Pod 列表,逐项评估 |
| 聚合 | count(distinct_zones) >= 2 |
统计不同可用区数量,确保跨区部署 |
| 逻辑与/或 | zone == "a" ; zone == "b"(与) / zone == "a" | zone == "b"(或) |
组合多个条件 |
# 综合表达式示例:验证 Pod 是否跨至少两个可用区
cross_zone_deployment {
pods := input.pods
zones := {zone | pod := pods[_]; zone := pod.spec.nodeSelector["topology.kubernetes.io/zone"]}
count(zones) >= 2
}
3.5 查询:评估策略并获取结果
查询是 Rego 的执行入口,通过 opa eval 命令或 API 调用触发。查询可以针对完整规则、部分规则或任意表达式。
3.5.1 基本查询
# 查询完整规则
opa eval "data.example.availability_zones.allowed_zones"
# 查询部分规则,返回所有匹配 Pod
opa eval "data.example.availability_zones.valid_pods"
3.5.2 带输入数据的查询
# 使用 --input 传入 JSON 数据
opa eval --input deployment.json "data.boundary.zone.cross_zone_deployment"
# 查询结果示例
{
"result": [
{
"expressions": [
{
"value": true,
"text": "data.boundary.zone.cross_zone_deployment",
"location": {"row": 1, "col": 1}
}
]
}
]
}
3.5.3 部分查询与绑定
# 查询并绑定变量,获取具体值
opa eval --input deployment.json "zone := data.boundary.zone.pod_zone_map[\"web-app-0\"]"
# 返回 zone 的具体值,如 "us-east-1a"
常见错误: 查询时忘记使用
data. 前缀引用规则。Rego 中所有规则和数据都位于 data 命名空间下,必须通过 data.<package>.<rule> 访问。
3.6 Rego 规则执行流程可视化
下图展示了 Rego 从输入到输出的完整执行流程,以及规则、表达式、查询之间的协作关系:
3.7 故障域验证中的 Rego 模式
在故障域划分场景中,以下 Rego 模式会反复出现,建议提前掌握:
| 模式 | Rego 实现 | 故障域验证场景 |
|---|---|---|
| 集合去重 | zones := {zone | ...} |
统计 Pod 分布在不同可用区的数量 |
| 键值映射 | pod_zone[pod] = zone { ... } |
建立 Pod 到可用区的映射关系 |
| 否定检查 | not zone in forbidden_zones |
确保 Pod 不在禁止的故障域中 |
| 聚合计数 | count(zones) >= min_zones |
验证跨区副本数是否满足最低要求 |
| 全量匹配 | every pod in input.pods { condition } |
确保所有 Pod 都满足故障域约束 |
# 全量匹配示例:每个 Pod 都必须有可用区标签
every pod in input.pods {
pod.spec.nodeSelector["topology.kubernetes.io/zone"] != ""
}