4. Rego 语言基础(一):语法结构、规则定义与数据类型

Rego 是 Open Policy Agent (OPA) 的策略语言,专为在云原生环境中表达策略逻辑而设计。理解 Rego 的语法结构、规则定义方式以及数据类型,是编写可测试、可维护策略代码的基石。本章将系统性地拆解 Rego 的核心语言要素,为后续的流水线回滚护栏编写打下坚实基础。

4.1 Rego 语法结构概览

Rego 的语法受 Prolog 和 Datalog 启发,采用声明式(Declarative)范式。与命令式语言不同,Rego 不描述“如何做”,而是描述“应该是什么”。其核心结构由 模块(Module)、包(Package)、导入(Import) 和 规则(Rule) 组成。

语法元素 说明 示例
Package 定义策略的命名空间,避免规则冲突。每个文件通常以 package 开头。 package deployment.rollback
Import 引入外部数据或另一个包中的规则,简化引用路径。 import data.kubernetes.pods
Rule 策略的核心逻辑单元,定义一组条件与结论。 deny[msg] { ... }
Comment 单行注释,以 # 开头。 # 这是注释
关键点: Rego 中的 data 是全局根命名空间,所有输入(input)和外部数据都挂载在此之下。理解 data 与 input 的区别是编写正确策略的第一步。

4.2 规则定义:完整规则与部分规则

规则是 Rego 策略的基本构建块。根据返回值的不同,规则分为 完整规则(Complete Rules) 和 部分规则(Partial Rules)。

4.2.1 完整规则

完整规则产生一个单一的布尔值或标量值。它类似于编程语言中的函数,只返回一个结果。如果规则体中的所有表达式都为真,则规则为真;否则为假。

# 完整规则:判断部署是否允许回滚
package deployment.rollback

default allow_rollback := false

allow_rollback {
    input.metadata.annotations["rollback-enabled"] == "true"
    input.spec.replicas > 0
}

4.2.2 部分规则

部分规则用于生成一组值(集合)或键值对(对象)。它们常用于收集所有违反策略的条目。在回滚护栏中,部分规则通常用于收集所有“拒绝”原因。

# 部分规则:收集所有拒绝回滚的原因(集合)
package deployment.rollback

deny[reason] {
    input.metadata.annotations["rollback-enabled"] != "true"
    reason := "回滚功能未在注解中启用"
}

deny[reason] {
    input.spec.replicas == 0
    reason := "副本数为0,无法执行回滚"
}
实践建议: 在流水线护栏中,优先使用部分规则(如 deny 集合)来聚合所有失败条件。这比使用多个完整规则更易于测试和调试,因为你可以一次性看到所有违反的策略点。

4.3 标量值与复合值

Rego 支持多种数据类型,分为标量值和复合值。掌握这些类型是进行数据查询和模式匹配的前提。

4.3.1 标量值

标量值是单一的值,不可再分。Rego 支持以下标量类型:

类型 描述 示例
字符串 双引号包裹的文本 "production"
数字 整数或浮点数 42, 3.14
布尔值 真或假 true, false
空值 表示缺失或未定义 null

4.3.2 复合值

复合值用于构建复杂的数据结构,是处理 Kubernetes 资源清单的核心工具。

  • 对象(Object): 无序的键值对集合,类似于 JSON 对象。键通常是字符串,值可以是任意类型。
  • 数组(Array): 有序的元素列表,索引从 0 开始。
  • 集合(Set): 无序的唯一值集合,没有重复元素。集合是 Rego 中非常强大的特性,常用于去重和成员关系检查。
# 复合值示例
package examples

# 对象
deployment_info := {
    "name": "nginx",
    "namespace": "default",
    "labels": {"app": "web", "env": "prod"}
}

# 数组
container_ports := [80, 443, 8080]

# 集合
allowed_namespaces := {"default", "kube-system", "production"}
常见陷阱: 在 Rego 中,集合 和 数组 的语法不同。集合使用空集符号 {} 但内部元素不能有重复;数组使用方括号 []。混淆两者会导致策略逻辑错误,尤其是在使用 == 进行精确匹配时。

4.4 Rego 规则与数据流关系图

下图展示了 Rego 规则如何与输入数据(input)和外部数据(data)交互,最终生成策略决策(deny/allow)。

Rego 规则执行与数据流 输入数据 (input) 外部数据 (data) Rego 引擎 规则评估 & 查询 策略规则 (Rules) 决策输出 (deny/allow) 说明: 1. input 包含请求数据(如 Kubernetes 资源清单)。 2. data 包含外部加载的配置或状态(如允许的命名空间列表)。

4.5 标量与复合值在回滚场景中的应用

在回滚护栏策略中,标量值和复合值各有其典型用途。下表总结了常见的使用模式:

数据类型 回滚场景示例 Rego 表达式
字符串 检查回滚目标版本标签 input.spec.template.metadata.labels.version == "v1.2.3"
数字 验证回滚后的副本数阈值 input.spec.replicas >= 3
布尔值 判断是否强制回滚 input.metadata.annotations["force-rollback"] == true
对象 提取并比对容器资源限制 input.spec.template.spec.containers[0].resources.limits.cpu
数组 遍历所有容器检查镜像来源 input.spec.template.spec.containers[_].image
集合 检查回滚目标命名空间是否在白名单内 allowed_ns := {"prod", "staging"}; input.metadata.namespace in allowed_ns
核心原则: 在编写回滚护栏时,优先使用 集合 来定义允许列表或拒绝列表。集合的成员关系检查(in 操作符)比数组的遍历更高效、更简洁,且天然去重,能有效减少策略中的冗余逻辑。

4.6 本章小结

本章建立了 Rego 语言的基础认知框架。你已掌握:

  • Rego 的模块化结构:package、import 和 rule 的协作方式。
  • 完整规则与部分规则的区别,以及部分规则在聚合拒绝原因中的优势。
  • 标量值(字符串、数字、布尔、null)与复合值(对象、数组、集合)的定义与操作。
  • 这些数据类型在回滚护栏场景中的具体映射关系。