4. Rego 策略执行流程:输入解析、规则匹配、数据查询、结果聚合
理解 Rego 策略的完整执行流程,是优化缓存策略和降低 K8s API 延迟的前提。OPA 在每次策略评估时,都会经历四个核心阶段:输入解析、规则匹配、数据查询和结果聚合。每个阶段都可能成为性能瓶颈,尤其是在大规模集群中。
核心认知: Rego 并非逐行解释执行,而是先将策略编译为内部表示(IR),再基于输入和数据执行增量或全量评估。缓存策略主要作用于“数据查询”阶段,但其他阶段的优化同样关键。
4.1 执行流程全景图
下图展示了 Rego 策略从接收到返回结果的完整流水线。注意,数据查询阶段是 OPA 与 K8s API Server 交互的唯一入口,也是延迟的主要来源。
4.2 阶段一:输入解析(Input Parsing)
输入解析是策略执行的起点。OPA 将外部传入的 input 对象(通常是来自 K8s Admission Review 请求的 JSON)解析为内部可操作的文档树。
| 步骤 | 操作 | 性能影响 |
|---|---|---|
| 1 | JSON 反序列化与 Schema 校验 | 大体积 input(如包含完整 Pod Spec)会增加解析耗时 |
| 2 | 类型转换与默认值填充 | Rego 的 object.get() 等内置函数在此阶段预计算 |
| 3 | 构建 input 文档树 | 树深度影响后续规则匹配的遍历效率 |
优化建议: 在 K8s 准入控制场景中,尽量精简 Admission Review 请求体。只传递策略需要的字段,避免传递完整的 Pod/Deployment 清单。使用
object.filter() 在策略入口处裁剪 input。
4.3 阶段二:规则匹配(Rule Matching)
规则匹配阶段负责根据 input 内容,从策略包中选择需要评估的规则,并进行变量绑定。OPA 使用规则索引来加速匹配过程。
- 规则索引: OPA 会为每个包中的规则建立哈希索引,基于规则头(head)中的变量快速定位候选规则。
- 变量统一: 将 input 中的实际值与规则中的变量进行绑定,生成一组可能的赋值组合。
- 部分求值(Partial Evaluation, PE): 在规则匹配阶段,OPA 会尝试将不依赖外部数据的子表达式提前求值,减少后续数据查询的负担。
# 示例:规则索引如何工作
# 假设有以下规则
allow {
input.role == "admin" # 索引键:role
input.operation == "delete" # 索引键:operation
data.cluster.admins[_] == input.user # 数据查询
}
# OPA 会为 role 和 operation 建立复合索引
# 当 input.role = "admin" 且 input.operation = "delete" 时
# 直接命中索引,跳过其他不相关规则
4.4 阶段三:数据查询(Data Query)—— 性能核心
数据查询阶段是 OPA 策略执行中最耗时的环节,也是缓存策略的主要作用对象。此阶段 OPA 需要访问 data 文档,其中包含从 K8s API Server 拉取的集群实时状态。
关键瓶颈: 每次数据查询都可能触发 K8s API 调用。在大型集群中,一次策略评估可能涉及数百次 API 调用(如遍历所有 Pod、Service、Namespace)。未经优化的数据查询是延迟的主要来源。
数据查询的三种模式:
| 模式 | 触发条件 | 延迟特征 | 缓存适用性 |
|---|---|---|---|
| 全量查询 | data.cluster.pods[_] 无过滤条件 |
高(拉取所有资源) | 适合全量缓存 |
| 带标签查询 | data.cluster.pods[{"app": "nginx"}] |
中(服务端过滤) | 适合按标签缓存 |
| 单资源查询 | data.cluster.pods["default"]["my-pod"] |
低(直接索引) | 适合短 TTL 缓存 |
4.5 阶段四:结果聚合(Result Aggregation)
结果聚合是策略执行的最后阶段。OPA 将所有匹配规则的输出合并,处理默认值和冲突,最终生成决策文档(Decision Document)。
- 规则输出合并: 所有
allow、deny、violation等规则的结果被收集。 - 默认值处理: 使用
default allow = false等声明填充未匹配规则的默认值。 - 冲突解决: 当多条规则对同一变量赋值时,OPA 遵循“最后赋值胜出”或“完全集合”语义。
- 决策文档生成: 最终输出一个 JSON 对象,包含
allowed、denied、warnings等字段。
# 结果聚合示例
# 策略定义
package example
default allow = false
allow {
input.role == "admin"
}
deny["用户没有管理员权限"] {
not allow
}
# 当 input.role = "admin" 时,聚合结果为:
# {
# "allow": true,
# "deny": {}
# }
#
# 当 input.role = "viewer" 时,聚合结果为:
# {
# "allow": false,
# "deny": {"用户没有管理员权限"}
# }
4.6 各阶段延迟分布与优化方向
以下表格展示了典型场景下各阶段的延迟占比,以及对应的优化策略:
| 阶段 | 典型延迟占比 | 主要优化方向 |
|---|---|---|
| 输入解析 | 5% - 10% | 精简 input 结构、使用 Schema 预校验 |
| 规则匹配 | 10% - 20% | 优化规则索引、减少冗余规则、使用部分求值 |
| 数据查询 | 60% - 80% | 引入缓存、减少 API 调用、使用标签过滤 |
| 结果聚合 | 5% - 10% | 减少规则数量、使用默认值避免空查询 |