如何在 Go 中本地评估 Kubernetes CEL 表达式?
数据小许
结论
在 Go 程序中,可以使用 k8s.io/apiserver/pkg/cel/environment 的 EnvSet 创建 Kubernetes 基础 CEL 环境。它会配置 Kubernetes 共用的 CEL 函数库、语言设置和运行时选项,但不会声明 object 等变量,也不会确定这些变量对应的资源类型。因此,表达式不能像调用 regexp.Compile 那样,只传入一个字符串就获得完整的 admission policy 上下文。Kubernetes CEL environment 文档 Kubernetes CEL 函数库
下面的示例将 object 声明为动态类型,可用于评估基于 unstructured.Unstructured.Object 一类 map 数据的简单表达式:
package main
import (
"fmt"
"log"
"github.com/google/cel-go/cel"
"k8s.io/apiserver/pkg/cel/environment"
)
func main() {
compat := environment.DefaultCompatibilityVersion()
base := environment.MustBaseEnvSet(compat)
// 基础环境提供 Kubernetes CEL 库;object 变量仍需由应用声明。
envSet, err := base.Extend(environment.VersionedOptions{
IntroducedVersion: compat,
EnvOptions: []cel.EnvOption{
cel.Variable("object", cel.DynType),
},
})
if err != nil {
log.Fatal(err)
}
env := envSet.NewExpressionsEnv()
// 配置加载时编译一次,处理资源时重复使用 program。
ast, issues := env.Compile(
`!object.spec.initContainers.exists(ic, ic.name == "mesh-proxy")`,
)
if issues != nil && issues.Err() != nil {
log.Fatal(issues.Err())
}
program, err := env.Program(ast)
if err != nil {
log.Fatal(err)
}
object := map[string]any{
"spec": map[string]any{
"initContainers": []any{
map[string]any{"name": "app-init"},
},
},
}
result, _, err := program.Eval(map[string]any{"object": object})
if err != nil {
log.Fatal(err)
}
fmt.Println(result) // true
}
变量和资源类型
示例将 object 声明为 cel.DynType,适合处理动态 map,但静态类型检查能力有限。若要更接近 Kubernetes admission policy 的类型检查,可以根据资源的 OpenAPI schema 创建 DeclType,再将类型和变量声明加入 EnvSet.Extend。表达式也可能需要 oldObject、request、params 等上下文变量;评估时,传给 Eval 的 map 中也要提供相应的值。MustBaseEnvSet 只设置基础环境,不会自动构建这些 admission 上下文。EnvSet 类型与扩展选项说明
使用时注意
- 在应用启动时初始化环境,并缓存编译后的
program以便复用。每处理一个资源都重新创建环境、编译表达式会增加开销;cel-go 也建议在配置不变时复用环境。cel-go 编译与评估说明 k8s.io/apiserver、k8s.io/apimachinery等 Kubernetes 模块应使用相互匹配的版本,CEL 环境版本也应与目标集群兼容。StoredExpressionsEnv用于已存储的表达式;新配置表达式通常使用适用的NewExpressionsEnv。- Kubernetes CEL 函数库提供
quantity函数和 Quantity 方法。表达式中的object字段路径仍由你提供的数据和声明决定。示例配置中的 CPU 表达式末尾多了一个];indexOf则需要以列表作为接收者,不能单独写成indexOf('my-container')。Kubernetes Quantity CEL 函数说明 - 在本地使用相同的基础库,不会自动复现 API server 的全部行为。要获得一致结果,变量、资源 schema、兼容版本和求值输入都需要符合目标场景。
备注:内容仅供参考。
