4. Kyverno 策略语言入门:YAML 策略结构、资源描述符、操作符、变量与 JMESPath 表达式

Kyverno 策略使用标准的 Kubernetes YAML 清单编写,其核心设计理念是“策略即代码”。理解策略语言的构成要素——从顶层结构到字段匹配、条件判断与数据变换——是编写可靠策略的基础。本章将系统拆解一个 Kyverno 策略的完整骨架,并深入每个关键组件。

4.1 策略 YAML 顶层结构

一个 Kyverno 策略资源(ClusterPolicy 或 Policy)遵循 Kubernetes 资源模型,其顶层字段如下表所示:

字段 类型 说明
apiVersion string 固定为 kyverno.io/v1
kind string ClusterPolicy(集群范围)或 Policy(命名空间范围)
metadata ObjectMeta 包含 name 和可选的 annotations
spec Spec 策略核心定义,包含 rules 数组

以下是一个最小化的策略骨架示例:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-required-labels
      match:
        resources:
          kinds:
            - Pod
      validate:
        message: "标签 'app.kubernetes.io/name' 是必需的。"
        pattern:
          metadata:
            labels:
              app.kubernetes.io/name: "?*"
提示: validationFailureAction 字段控制策略的生效模式:Enforce 直接拒绝违规请求;Audit 仅生成报告,不阻塞操作。在开发阶段建议先使用 Audit 模式。

4.2 资源描述符:match 与 exclude

每个规则通过 match 和 exclude 字段定义其作用范围。资源描述符支持按 kinds、names、namespaces、selector(标签选择器)以及 annotations 进行筛选。

资源描述符的核心匹配维度:

  • kinds:匹配资源类型,支持核心 API 组(如 Pod)和自定义资源(如 Deployment)。
  • names:精确匹配资源名称。
  • namespaces:匹配资源所在的命名空间。
  • selector:使用标签选择器(matchLabels / matchExpressions)进行语义匹配。
  • annotations:匹配注解键值对。
rules:
  - name: match-example
    match:
      resources:
        kinds:
          - Deployment
          - StatefulSet
        namespaces:
          - production
        selector:
          matchLabels:
            environment: prod
    exclude:
      resources:
        names:
          - system-critical-deploy

4.3 操作符:条件判断的基石

Kyverno 在 validate 和 mutate 中支持多种操作符,用于定义字段值与预期条件的比较关系。操作符分为标量比较和集合比较两类。

操作符 类型 示例 说明
= 标量 replicas: 3 精确相等(默认操作符)
!= 标量 hostPID: false 不等于
> 标量 spec.replicas > 1 大于(数值比较)
< 标量 spec.replicas < 10 小于(数值比较)
>= 标量 spec.replicas >= 2 大于等于
<= 标量 spec.replicas <= 5 小于等于
in 集合 tier in ["frontend","backend"] 值在给定集合中
not in 集合 tier not in ["cache","queue"] 值不在给定集合中
实战要点: 在 pattern 中使用操作符时,= 可以省略不写。例如 replicas: 3 等价于 replicas: =3。集合操作符 in 和 not in 常用于枚举值校验,如环境标签、安全上下文字段。

4.4 变量与 JMESPath 表达式

Kyverno 支持在策略中使用变量来引用请求对象(request.object)、旧对象(request.oldObject)、用户信息(request.userInfo)以及服务账号等上下文数据。变量通过 $() 语法嵌入,并可以结合 JMESPath 表达式进行数据提取与变换。

变量引用路径示例:

  • $(request.object.metadata.name) —— 获取被处理资源的名称。
  • $(request.object.spec.containers[?name=="main"].image | [0]) —— 获取名为 "main" 的容器镜像。
  • $(request.object.metadata.labels."app.kubernetes.io/name") —— 获取包含特殊字符的标签值。

JMESPath 是 Kyverno 内置的查询语言,用于对 JSON/YAML 数据进行过滤、投影和变换。常用函数包括:

函数 说明 示例
contains() 检查数组或字符串是否包含某元素 contains(containers[*].name, "sidecar")
length() 返回数组或字符串长度 length(containers) > 1
split() 按分隔符拆分字符串 split(image, ":")[1]
to_string() 将数值或布尔值转为字符串 to_string(replicas)
join() 将数组元素拼接为字符串 join(", ", volumes[*].name)

以下是一个使用变量和 JMESPath 的 mutate 策略示例,自动为 Pod 添加基于命名空间的标签:

rules:
  - name: auto-label-namespace
    match:
      resources:
        kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
            namespace: "{{ request.namespace }}"
            environment: "{{ request.object.metadata.labels.\"env\" || 'unknown' }}"
注意: 变量路径中的特殊字符(如 /、-、.)需要使用双引号包裹,并在 JMESPath 中转义。例如 labels."app.kubernetes.io/name"。在 deny 规则中使用变量时,务必确保变量在运行时能被正确解析,否则可能导致策略评估失败。

4.5 策略语言组件关系图

下图展示了 Kyverno 策略语言各组件之间的层级关系与数据流向:

Kyverno 策略语言组件关系图 ClusterPolicy / Policy spec.rules[] match / exclude validate / mutate 变量 & JMESPath kinds / names / namespaces pattern / deny / patch $() 引用 / 函数链 操作符在 pattern / deny 条件中使用 = != > < >= <= in not in 标量比较:replicas > 1 | 集合比较:tier in ["web","api"] 变量与 JMESPath 可嵌入操作数:$(request.object.spec.replicas) > 3

4.6 综合示例:准入控制策略

以下是一个完整的 ClusterPolicy,综合运用了资源描述符、操作符、变量和 JMESPath,用于强制要求所有 Deployment 必须设置资源限制,且副本数不能为 0:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: deployment-resource-guard
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-resource-limits
      match:
        resources:
          kinds:
            - Deployment
      validate:
        message: "Deployment 必须设置 CPU 和内存的 limits。"
        pattern:
          spec:
            template:
              spec:
                containers:
                  - resources:
                      limits:
                        memory: "?*"
                        cpu: "?*"
    - name: reject-zero-replicas
      match:
        resources:
          kinds:
            - Deployment
      validate:
        message: "Deployment 的 replicas 不能为 0。"
        deny:
          conditions:
            any:
              - key: "{{ request.object.spec.replicas }}"
                operator: Equals
                value: 0
    - name: enforce-min-replicas
      match:
        resources:
          kinds:
            - Deployment
        selector:
          matchLabels:
            critical: "true"
      validate:
        message: "关键 Deployment 的 replicas 必须大于等于 2。"
        deny:
          conditions:
            any:
              - key: "{{ request.object.spec.replicas }}"
                operator: LessThan
                value: 2
关键解读: 第一个规则使用 pattern 和通配符 ?* 确保资源限制字段存在且非空;第二个规则使用 deny 条件和 Equals 操作符拒绝副本数为 0 的请求;第三个规则结合标签选择器与 LessThan 操作符,对标记为 critical: "true" 的 Deployment 实施更严格的副本数下限。