Kubernetes 的准入控制器(Admission Controllers)是控制集群变更的关键组件。其中,MutatingAdmissionWebhook 允许我们在资源对象被持久化到 etcd 之前对其进行修改(突变)。这使得我们可以实现强大的自动化功能,例如自动注入 Sidecar 容器、设置默认标签或环境变量,从而确保所有 Pod 都符合组织定义的合规性。
本文将聚焦如何使用 MutatingWebhook 实现 Pod 配置的自动注入,并提供核心的 JSON Patch 逻辑。
1. MutatingWebhook 工作原理
当用户提交一个 Pod 定义时,API Server 会经历以下步骤:
- 认证/授权。
- 执行 Mutating Webhooks: Webhook Server 接收一个 AdmissionReview 请求,该请求包含待创建的 Pod 定义。Webhook Server 返回一个包含 patch(使用 JSON Patch 格式)的 AdmissionReview 响应。
- 应用修改: API Server 应用 JSON Patch。
- 执行 Validating Webhooks (合规性检查)。
- 持久化到 etcd。
2. 核心步骤:定义 JSON Patch 注入逻辑
我们的 Webhook Server 必须能够解析传入的 Pod 定义,判断是否需要注入,然后生成 JSON Patch。
假设我们要实现以下目标:对于带有标签 injector.example.com/sidecar: “true” 的 Pod,自动注入一个名为 monitoring-agent 的 Sidecar 容器。
Python/Flask 伪代码示例(处理逻辑)
import json
import base64
def generate_patch(admission_request):
# 提取待创建的 Pod 定义
pod = admission_request['request']['object']
# 检查是否需要注入
labels = pod.get('metadata', {}).get('labels', {})
if labels.get('injector.example.com/sidecar') != 'true':
return [] # 不注入,返回空 Patch
# 定义要注入的 Sidecar 容器
sidecar_container = {
"name": "monitoring-agent",
"image": "prom/node-exporter:latest",
"resources": {
"limits": {"cpu": "100m", "memory": "128Mi"}
},
"ports": [{"containerPort": 9100}]
}
# 生成 JSON Patch 数组
# 使用 'add' 操作,路径 '/spec/containers/-' 表示将其附加到容器列表末尾
patch = [
{
"op": "add",
"path": "/spec/containers/-",
"value": sidecar_container
},
{
"op": "add",
"path": "/metadata/annotations",
"value": {"injector.example.com/status": "injected"}
}
]
return patch
def handle_webhook_request(data):
# ... (处理 AdmissionReview 请求并调用 generate_patch)
patch = generate_patch(data)
# 将 Patch 编码为 Base64
patch_bytes = json.dumps(patch).encode('utf-8')
encoded_patch = base64.b64encode(patch_bytes).decode('utf-8')
# 构建 AdmissionReview 响应
response = {
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": data['request']['uid'],
"allowed": True,
"patchType": "JSONPatch",
"patch": encoded_patch
}
}
return response
3. Kubernetes 配置定义
Webhook 服务器通常部署为一个 Service 和 Deployment,并且必须使用 TLS 证书(K8s API Server 必须信任该证书)。
3.1 定义 MutatingWebhookConfiguration
此配置告诉 Kubernetes API Server 何时将请求发送给我们的 Webhook 服务。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: sidecar-injector-webhook-config
webhooks:
- name: injector.example.com
clientConfig:
service:
name: sidecar-injector-service # Webhook Server 对应的 Service 名称
namespace: default
path: "/mutate"
caBundle: | # 必须是 Webhook Server 证书颁发机构的 PEM 编码 CA 证书
# 示例:base64 编码的 CA 证书内容
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCg==
rules:
- operations: [ "CREATE" ]
apiGroups: [ "" ]
apiVersions: [ "v1" ]
resources: [ "pods" ]
failurePolicy: Ignore # 如果 Webhook 失败,是忽略还是拒绝资源创建
sideEffects: None # 确保 Webhook 不会影响其他资源的副作用
admissionReviewVersions: ["v1"]
scope: Namespaced
3.2 部署测试 Pod
一旦 Webhook Server 运行且配置生效,任何带有特定标签的 Pod 创建请求都会被拦截并修改。
apiVersion: v1
kind: Pod
metadata:
name: my-app-with-sidecar
labels:
app: my-app
injector.example.com/sidecar: "true" # 触发注入
spec:
containers:
- name: main-app
image: nginx:latest
ports:
- containerPort: 80
当这个 Pod 被创建时,如果查看其定义 (kubectl get pod my-app-with-sidecar -o yaml),你会发现 monitoring-agent 容器已经被自动添加到 spec.containers 列表中。
汤不热吧