bigywater.tech
Kubernetes · 93

ValidatingAdmissionPolicy:用 CEL 写准入规则

不写 webhook,怎么在 API Server 里拦住不合规的对象?策略和绑定各管什么?参数怎么传?scale 为什么没被拦?这篇用一条最简单的“Deployment 副本数不超过 3”,把 VAP 的核心概念和几个容易漏的点验证一遍。

0.9 秒
创建绑定后策略开始生效的用时
scale 没被拦
策略只匹配 deployments,kubectl scale 走的 deployments/scale 子资源没有命中
0.1 秒
把参数 ConfigMap 里的阈值从 5 改成 8 后,放行 replicas=6 所用的时间

策略 + 绑定

实测 · 本机执行输出
  只有策略、没有绑定,创建 replicas=10 的 Deployment:退出码 0;['deployment.apps/d1 created'](策略没有生效)
  创建绑定(validationActions: [Deny],只作用在命名空间 k87)后 0.9 秒开始生效
  replicas=10:退出码 1;['The deployments "d2" is invalid: : ValidatingAdmissionPolicy \'k87-max-replicas\' with binding \'k87-bind\' denied request: 副本数 10 超过上限 3']
  replicas=3:退出码 0;['deployment.apps/d3 created']
  patch 把 d3 改成 replicas=8(UPDATE 也被拦):退出码 1;['The deployments "d3" is invalid: : ValidatingAdmissionPolicy \'k87-max-replicas\' with binding \'k87-bind\' denied request: 副本数 8 超过上限 3']
  kubectl scale deploy/d3 --replicas=8:退出码 0;['deployment.apps/d3 scaled'](scale 走的是 deployments/scale 子资源,策略里只写了 deployments,没有匹配上)
  同样的 Deployment 放到 default 命名空间(绑定的 namespaceSelector 没选中它):退出码 0;['deployment.apps/d4 created']

策略 k87-max-replicas 匹配 apps/v1 的 deployments(CREATE、UPDATE),CEL 表达式是 object.spec.replicas <= 3,messageExpression 拼出提示。只有策略没有绑定时,创建 replicas=10 的 Deployment 照样成功。创建绑定(validationActions: [Deny],namespaceSelector 只选 k87)0.9 秒后生效:replicas=10 被拒——ValidatingAdmissionPolicy 'k87-max-replicas' with binding 'k87-bind' denied request: 副本数 10 超过上限 3;replicas=3 通过;patch 把 d3 改成 8 也被拒(UPDATE 同样检查);default 命名空间里的同样对象没被拦。但 kubectl scale 成功了:它走的是 deployments/scale 子资源,策略里只写了 deployments,没有匹配上——子资源要单独列在 resourceRules 里。

参数化

实测 · 本机执行输出
  创建参数化策略和绑定之后 0.9 秒开始生效(阈值来自 ConfigMap limits)
  参数 maxReplicas=5,创建 replicas=4:退出码 0;['deployment.apps/p1 created']
  replicas=6:退出码 1;['The deployments "p2" is invalid: : ValidatingAdmissionPolicy \'k87-param-limit\' with binding \'k87-bind-param\' denied request: 副本数 6 超过参数 maxReplicas=5']
  把参数改成 8:0.1 秒后 replicas=6 通过了(改的是 ConfigMap,策略本身没动)

策略声明 paramKind: ConfigMap,表达式 object.spec.replicas <= int(params.data.maxReplicas);绑定的 paramRef 指向 ConfigMap limits(maxReplicas: "5")。创建后 0.9 秒生效:replicas=4 通过,replicas=6 被拒——副本数 6 超过参数 maxReplicas=5。把 ConfigMap 里的 maxReplicas 改成 8,0.1 秒后 replicas=6 就通过了:改的是参数,策略本身没动。同一个策略可以配多个绑定、各用不同的参数,适合按环境区分阈值。

动作与类型检查

实测 · 本机执行输出
  validationActions: [Warn]:退出码 0;['deployment.apps/w1 created', "Warning: Validation failed for ValidatingAdmissionPolicy 'k87-max-replicas' with binding 'k87-bind': 副本数 10 超过上限 3"](创建成功,只返回 Warning)
  把 validationActions 改成 [Warn, Deny]:退出码 1;['The ValidatingAdmissionPolicyBinding "k87-bind" is invalid: spec.validationActions: Invalid value: ["Warn","Deny"]: must not contain both Deny and Warn (repeating the same validation failure information in the API response and headers serves no purpose)']
  改回 [Deny]:退出码 1;['The deployments "w2" is invalid: : ValidatingAdmissionPolicy \'k87-max-replicas\' with binding \'k87-bind\' denied request: 副本数 10 超过上限 3']
  表达式里写错字段名(object.spec.replica):0.0 秒后策略的 status.typeChecking.expressionWarnings=[('spec.validations[0].expression', "apps/v1, Kind=Deployment: ERROR: <input>:1:12: undefined field 'replica'  | object.spec.replica <= 3  | ...........^ ")]

validationActions: [Warn] 时创建 replicas=10 的 Deployment 成功,返回 Warning: Validation failed for ValidatingAdmissionPolicy … 副本数 10 超过上限 3——适合上线前观察;改成 [Warn, Deny] 绑定本身被拒(spec.validationActions: must not contain both Deny and Warn);改回 [Deny] 才拒绝创建。表达式里写错字段名 object.spec.replica,策略的 status.typeChecking.expressionWarnings 立刻出现 undefined field 'replica' 的警告,能在上线前发现。

分步演示

ValidatingAdmissionPolicy
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,ValidatingAdmissionPolicy 已 GA 默认可用);对象用 kubectl apply / patch / scale 创建或修改,生效时间用 --dry-run=server 每 0.2 秒探测;第二、三节分别在新的命名空间里做(同一个命名空间里先删一个绑定再建参数化策略时,曾有一次三十多秒没有生效,原因没查清);每种情形各一次
    • 没有验证:matchConditions、variables 与 auditAnnotations;failurePolicy: Ignore 时表达式运行时报错的行为;audit 动作写入的审计注解;CEL 表达式的成本限制;matchPolicy: Equivalent 与不同 API 版本;对 CRD 的校验(见下面 CEL 校验一篇);MutatingAdmissionPolicy
    京ICP备2026067502号-1京公网安备11010502063487号