此文档中的信息可能已过时
此文档的更新日期比原文晚,因此其中的信息可能已过时。如果能阅读英文,请查看英文版本以获取最新信息: Mutating Admission Policy
变更性准入策略
Kubernetes v1.32 [alpha]
本页概要介绍 MutatingAdmissionPolicy(变更性准入策略)。
什么是 MutatingAdmissionPolicy?
变更性准入策略(Mutating Admission Policy)提供了一种声明式的、进程内的方案, 可以用来替代变更性准入 Webhook。
变更性准入策略使用通用表达语言(Common Expression Language,CEL)来声明对资源的变更。 变更操作可以通过使用服务器端应用合并策略所合并的应用配置来定义, 也可以使用 JSON 补丁来定义。
变更性准入策略的可配置能力很强,策略的编写者可以根据集群管理员的需要,定义参数化的策略以及限定到某类资源的策略。
策略包含哪些资源
策略通常由三种资源组成:
- MutatingAdmissionPolicy 描述策略的抽象逻辑(可以理解为:“此策略将特定标签设置为特定值”)。
为 MutatingAdmissionPolicy 提供信息的一个参数资源(parameter resource), 有了参数之后,策略成为一条具体的语句 (假想:“将
owner
标签设置为类似company.example.com
的值”)。 参数资源引用 Kubernetes API 中可用的 Kubernetes 某种资源。被引用的资源可以是内置类别或类似 CustomResourceDefinition(CRD)这种扩展资源。 例如,你可以使用 ConfigMap 作为参数。MutatingAdmissionPolicyBinding 将上述两种资源(MutatingAdmissionPolicy 和参数)关联在一起, 并提供作用域限定。如果你只想为
Pods
设置owner
标签,而不想为其他 API 类别设置标签, 则绑定就是你用来限定此变更的地方。
你必须定义至少一个 MutatingAdmissionPolicy 和一个相应的 MutatingAdmissionPolicyBinding, 才能使策略生效。
如果 MutatingAdmissionPolicy 不需要通过参数进行配置,在
MutatingAdmissionPolicy 中不指定 spec.paramKind
即可。
开始使用 MutatingAdmissionPolicy
变更性准入策略是集群控制平面的一部分。你在编写和部署这些策略时要非常谨慎。 下文描述如何快速试用变更性准入策略。
创建 MutatingAdmissionPolicy
以下是一个 MutatingAdmissionPolicy 的示例。 此策略会将变更新建的 Pod,为其添加一个边车容器(如果以前没有边车容器的话)。
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: MutatingAdmissionPolicy
metadata:
name: "sidecar-policy.example.com"
spec:
paramKind:
kind: Sidecar
apiVersion: mutations.example.com/v1
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
matchConditions:
- name: does-not-already-have-sidecar
expression: "!object.spec.initContainers.exists(ic, ic.name == \"mesh-proxy\")"
failurePolicy: Fail
reinvocationPolicy: IfNeeded
mutations:
- patchType: "ApplyConfiguration"
applyConfiguration:
expression: >
Object{
spec: Object.spec{
initContainers: [
Object.spec.initContainers{
name: "mesh-proxy",
image: "mesh/proxy:v1.0.0",
args: ["proxy", "sidecar"],
restartPolicy: "Always"
}
]
}
}
.spec.mutations
字段由一系列表达式组成,这些表达式求值后将形成资源补丁。
所生成的补丁可以是应用配置或 JSON 补丁。
你不能将 mutations 设置为空列表。在对所有表达式求值后,API 服务器将所得到的变更应用到正在通过准入阶段的资源。
要配置变更准入策略以便用于某个集群中,需要先创建绑定。
只有存在 spec.policyName
字段值与某策略的 spec.name
相匹配的绑定时,该策略才会生效。
一旦创建了绑定和策略,策略的 spec.matchConditions
相匹配的所有资源请求都会触发已定义的所有变更集合。
在上面的示例中,创建 Pod 将触发添加 mesh-proxy
initContainer 这一变更:
apiVersion: v1
kind: Pod
metadata:
name: myapp
namespace: default
spec:
...
initContainers:
- name: mesh-proxy
image: mesh/proxy:v1.0.0
args: ["proxy", "sidecar"]
restartPolicy: Always
- name: myapp-initializer
image: example/initializer:v1.0.0
...
参数资源
使用参数资源,我们可以将策略配置与其定义分隔开。策略可以定义 paramKind
,划定参数资源的 GVK,
随后的策略绑定操作会通过 paramRef
按名称(通过 policyName
)将某个策略绑定到特定参数资源。
有关细节参阅参数资源。
ApplyConfiguration
MutatingAdmissionPolicy 表达式始终是 CEL 格式的。
每个应用配置 expression
必须求值为(使用 Object()
初始化声明的)CEL 对象。
这些应用配置不能修改原子结构、映射或数组,因为这类修改可能导致意外删除未包含在应用配置中的值。
CEL 表达式可以访问以 CEL 变量组织起来的 API 请求内容及一些其他有用变量:
Object
- 资源对象的 CEL 类型。Object.<fieldName>
- 对象字段的 CEL 类型(例如Object.spec
)Object.<fieldName1>.<fieldName2>...<fieldNameN>
- 嵌套字段的 CEL 类型(例如Object.spec.containers
)
CEL 表达式可以访问以 CEL 变量组织起来的 API 请求内容及一些其他有用变量:
object
- 来自传入请求的对象。对于 DELETE 请求,取值为 null。oldObject
- 现有对象。对于 CREATE 请求,取值为 null。request
- API 请求的属性。params
- 正被评估的策略绑定所引用到的参数资源。仅在策略设置了paramKind
时填充。
namespaceObject
- 传入对象所属的命名空间对象。对于集群范围的资源,取值为 null。variables
- 组合变量的映射,包含从变量名称到其惰性评估值的映射。 例如,名为foo
的变量可以以variables.foo
的方式访问。authorizer
- 一个 CEL 鉴权器。可用于对请求的主体(用户或服务账户)进行鉴权检查。 参阅 https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authzauthorizer.requestResource
- 从authorizer
构建并使用请求资源配置的 CEL ResourceCheck。
apiVersion
、kind
、metadata.name
、metadata.generateName
和 metadata.labels
始终可以从对象的根进行访问。其他元数据属性不可访问。
JSONPatch
相同的变更可以被写成以下的 JSON 补丁:
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: MutatingAdmissionPolicy
metadata:
name: "sidecar-policy.example.com"
spec:
paramKind:
kind: Sidecar
apiVersion: mutations.example.com/v1
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
matchConditions:
- name: does-not-already-have-sidecar
expression: "!object.spec.initContainers.exists(ic, ic.name == \"mesh-proxy\")"
failurePolicy: Fail
reinvocationPolicy: IfNeeded
mutations:
- patchType: "JSONPatch"
jsonPatch:
expression: >
[
JSONPatch{
op: "add", path: "/spec/initContainers/-",
value: Object.spec.initContainers{
name: "mesh-proxy",
image: "mesh-proxy/v1.0.0",
restartPolicy: "Always"
}
}
]
表达式将通过 CEL 求值,以创建 JSON 补丁。 参阅 https://github.com/google/cel-spec
每个被求值的 expression
必须返回 JSONPatch
值形成的数组。
JSONPatch
类型表示 JSON 补丁中的一个操作。
例如,下面的 CEL 表达式返回 JSON 补丁,用于有条件地修改某个值:
[
JSONPatch{op: "test", path: "/spec/example", value: "Red"},
JSONPatch{op: "replace", path: "/spec/example", value: "Green"}
]
要为补丁操作 value
定义 JSON 对象,可以使用 CEL Object
类型。例如:
[
JSONPatch{
op: "add",
path: "/spec/selector",
value: Object.spec.selector{matchLabels: {"environment": "test"}}
}
]
要使用包含 '/' 和 '~' 的字符串作为 JSONPatch 路径键,可以使用 jsonpatch.escapeKey()
。例如:
[
JSONPatch{
op: "add",
path: "/metadata/labels/" + jsonpatch.escapeKey("example.com/environment"),
value: "test"
},
]
CEL 表达式可以访问创建 JSON 补丁和对象所需的类型:
JSONPatch
- JSON 补丁操作的 CEL 类型。JSONPatch 具有op
、from
、path
和value
字段。 有关细节参阅 JSON 补丁。value
字段可以设置为字符串、整数、数组、映射或对象。 如果设置,path
和from
字段的值必须为 JSON 指针字符串, 可以在指针中使用jsonpatch.escapeKey()
CEL 函数来转义包含/
和~
的路径键。
Object
- 资源对象的 CEL 类型。Object.<fieldName>
- 对象字段的 CEL 类型(例如Object.spec
)Object.<fieldName1>.<fieldName2>...<fieldNameN>
- 嵌套字段的 CEL 类型(例如Object.spec.containers
)
CEL 表达式可以访问以 CEL 变量组织的 API 请求的内容及一些其他有用变量:
object
- 来自传入请求的对象。对于 DELETE 请求,取值为 null。oldObject
- 现有对象。对于 CREATE 请求,取值为 null。request
- API 请求的属性。params
- 正被评估的策略绑定所引用的参数资源。仅在策略具有paramKind
时填充。
namespaceObject
- 传入对象所属的命名空间对象。对于集群范围的资源,取值为 null。variables
- 组合变量的映射,包含从变量名称到其惰性评估值的映射。 例如,名为foo
的变量可以以variables.foo
的形式访问。authorizer
- 一个 CEL 鉴权组件。可用于对请求的主体(用户或服务账户)执行鉴权检查。 参阅 https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authzauthorizer.requestResource
- 从authorizer
构建并以请求资源配置的 CEL ResourceCheck。
CEL 表达式可以访问 Kubernetes CEL 函数库以及:
jsonpatch.escapeKey
- 执行 JSONPatch 键转义。~
和/
分别被转义为~0
和~1
。
只有格式为 [a-zA-Z_.-/][a-zA-Z0-9_.-/]*
的属性名称是可访问的。