Admission Webhook
Admission Webhook 是 api-server 對外提供的一個(gè)擴(kuò)展能力揽思,api-server 作為 kubernetes 的核心耗绿,幾乎所有組件都需要跟他打交道荣赶,基本可以說掌控了 k8s 的 api-server,你就可以控制 k8s 的行為晨缴。
在早期的版本 api-server 并沒有提供 admissionresgistration 的能力(v1.9之前)稚晚,當(dāng)我們要對 k8s 進(jìn)行控制的時(shí)候做祝,只能重新編譯 api-server。比如你想阻止某個(gè)控制器的行為蠕啄,或攔截某個(gè)控制器的資源修改场勤。admission webhook 就是提供了這樣的能力,比如你希望某個(gè)特定 label 標(biāo)簽的 pod 再創(chuàng)建的時(shí)候都注入 sidercar歼跟,或者阻止不合規(guī)的資源和媳。
CRD解析
Admission Webhook 包涵兩種 CRD:mutatingwebhookconfiguration
和 validatingwebhookconfiguration
。
下面是一個(gè) mutatingwebhookconfiguration 的CRD文件:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: mutating-test.shikanon.com
webhooks:
- admissionReviewVersions: # admissionReviewVersions 請求的版本
- v1beta1
- v1
clientConfig: # 客戶端配置
caBundle: # ca證書
service: # 調(diào)用服務(wù)相關(guān)配置哈街,這里是一個(gè)k8s的service留瞳,訪問地址是<name>.<namespace>.svc:<port>/<path>
name: mutating-test
namespace: testing-tools
path: /mutation-deployment
port: 8000
failurePolicy: Ignore # 調(diào)用失敗策略,Ignore為忽略錯(cuò)誤, failed表示admission會處理錯(cuò)誤
matchPolicy: Exact
name: mutating-test.shikanon.com # webhook名稱
namespaceSelector: {} # 命名空間過濾條件
objectSelector: # 對象過濾條件
matchExpressions:
- key: mutating-test-webhook
operator: In
values:
- enabled
- "true"
# reinvocationPolicy表示再調(diào)度策略骚秦,因?yàn)閣ebhook本身沒有順序性她倘,因此每個(gè)修改后可能又被其他webhook修改,所以提供
# 一個(gè)策略表示是否需要被多次調(diào)用作箍,Never 表示只會調(diào)度一次硬梁,IfNeeded 表示資源被修改后會再調(diào)度這個(gè)webhook
reinvocationPolicy: Never
rules: # 規(guī)則
- apiGroups:
- apps
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- deployments
scope: '*' # 匹配范圍,"*" 匹配所有資源胞得,但不包括子資源荧止,"*/*" 匹配所有資源,包括子資源
sideEffects: None # 這個(gè)表示webhook是否存在副作用懒震,主要針對 dryRun 的請求
timeoutSeconds: 30
Webhook 的流程和格式
Admission Webhook 本質(zhì)是 api-server 的一個(gè) webhook 調(diào)用罩息,下面是 api-server 的處理流程:
api-server 通過讀取 mutatingwebhookconfiguration
和 validatingwebhookconfiguration
的 CR 文件的目標(biāo)地址,然后回調(diào)用戶自定義的服務(wù)个扰。
┌──────────────────────────────────┐
┌─────────────────┐ │ │
apply │ │ read │ validatingwebhookconfiguration │
────────────?│ api-server │?───────────┤ │
│ │ │ mutatingwebhookconfiguration │
└────────┬────────┘ │ │
│ └──────────────────────────────────┘
│
│ 回調(diào)
│
│
┌────────▼────────┐
│ │
│ webhookservice │
│ │
└─────────────────┘
api-server 發(fā)起的請求是一串json數(shù)據(jù)格式瓷炮,header需要設(shè)置content-type
為application/json
, 我們看看請求的 body :
curl -X POST \
http://webhook-url \
-H 'content-type: application/json' \
-d '{
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"request": {
...
}
}'
返回的結(jié)果:
{
"kind": "AdmissionReview",
"apiVersion": "admission.k8s.io/v1",
"response": {
"uid": "b955fb34-0135-4e78-908e-eeb2f874933f",
"allowed": true,
"status": {
"metadata": {},
"code": 200
},
"patch": "W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6Ii9zcGVjL3JlcGxpY2FzIiwidmFsdWUiOjJ9XQ==",
"patchType": "JSONPatch"
}
}
這里的 patch 是用base64編碼的一個(gè)json,我們解碼看看递宅,是一個(gè) json patch:
$ echo "W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6Ii9zcGVjL3JlcGxpY2FzIiwidmFsdWUiOjJ9XQ==" | base64 -d
[
{
"op": "replace",
"path": "/spec/replicas",
"value": 2
}
]
編寫Admission Webhook服務(wù)
處理函數(shù):
func (h *MutatingHandler) Handle(ctx context.Context, req kubeadmission.Request) kubeadmission.Response {
reqJson, err := json.Marshal(req.AdmissionRequest)
if err != nil {
return kubeadmission.Errored(http.StatusBadRequest, err)
}
fmt.Println(string(reqJson))
obj := &appsv1.Deployment{}
err = h.Decoder.Decode(req, obj)
if err != nil {
return kubeadmission.Errored(http.StatusBadRequest, err)
}
fmt.Println(obj.Name)
originObj, err := json.Marshal(obj)
if err != nil {
return kubeadmission.Errored(http.StatusBadRequest, err)
}
// 將新的資源副本數(shù)量改為1
newobj := obj.DeepCopy()
replicas := int32(1)
newobj.Spec.Replicas = &replicas
currentObj, err := json.Marshal(newobj)
if err != nil {
return kubeadmission.Errored(http.StatusBadRequest, err)
}
// 對比之前的資源類型和之后的資源類型的差異生成返回?cái)?shù)據(jù)
resp := kubeadmission.PatchResponseFromRaw(originObj, currentObj)
respJson, err := json.Marshal(resp.AdmissionResponse)
if err != nil {
return kubeadmission.Errored(http.StatusBadRequest, err)
}
return resp
}
主程序:
func main() {
scheme := kuberuntime.NewScheme()
decoder, err := kubeadmission.NewDecoder(scheme)
if err != nil {
log.Fatalln(err)
}
mutation := MutatingHandler{
Decoder: decoder,
}
var logger = klogr.New()
webhook := kubeadmission.Webhook{
Handler: &mutation,
}
logger.Info("test", "unable to decode the request")
_, err = inject.LoggerInto(logger, &webhook)
if err != nil {
log.Fatalln(err)
}
http.HandleFunc("/mutation-deployment", webhook.ServeHTTP)
// 這里需要用到TLS證書和密鑰
err = http.ListenAndServeTLS(":8000", "cert.pem", "private.key", nil)
if err != nil {
log.Fatalln(err)
}
}
基于私鑰生成一個(gè)證書簽名請求(Certificate Signing Request娘香,CSR)苍狰,目標(biāo)地址的域名為:mutating-test.testing-tools.svc
, csr的配置:
openssl genrsa -out private.key 2048
創(chuàng)建命令:
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = mutating-test
DNS.2 = mutating-test.testing-tools
DNS.3 = mutating-test.testing-tools.svc
DNS.4 = mutating-test.testing-tools.svc.cluster.local
用api-server的CA進(jìn)行簽發(fā)
基于csr創(chuàng)建 CertificateSigningRequest
:
cat <<EOF | kubectl create -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: mutating-test
spec:
groups:
- system:authenticated
request: $(cat server.csr | base64 | tr -d '\n')
usages:
- digital signature
- key encipherment
- server auth
EOF
認(rèn)證完成可以查看:
kubectl certificate approve mutating-test
生成證書:
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION
mutating-test 1m kubernetes.io/legacy-unknown user-f9mr4 Approved,Issued
獲取api-server的CA證書:
kubectl get csr mutating-test -o jsonpath='{.status.certificate}' | openssl base64 -d -A -out cert.pem
將這個(gè)證書填入 Webhook 的 caBundle。
MutatingAdmissionWebhook特性
MutatingAdmissionWebhook作為kubernetes的ApiServer中Admission Controller的一部分烘绽,提供了非常靈活的擴(kuò)展機(jī)制淋昭,通過配置MutatingWebhookConfiguration對象,理論上可以監(jiān)聽并修改任何經(jīng)過ApiServer處理的請求
MutatingWebhookConfiguration對象簡介
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
creationTimestamp: null
name: mutating-webhook-oversale
webhooks:
- clientConfig:
caBundle: ...
service:
name: webhook-oversale-service
namespace: oversale
path: /mutate
failurePolicy: Ignore
name: oversale
rules:
- apiGroups:
- *
apiVersions:
- v1
operations:
- UPDATE
resources:
- nodes/status
MutatingWebhookConfiguration是kubernetes的一個(gè)官方的資源提供的對象安接,下面對該對象的字段做一些簡單的說明:
- clientConfig.caBundle:apiServer訪問我們自定義的webhook服務(wù)時(shí)需要的加密認(rèn)證數(shù)據(jù)
- clientConfig.service:apiServer訪問我們自定義的webhook服務(wù)的Service相關(guān)信息(包括具體接口信息)
- failurePolicy:當(dāng)apiServer調(diào)用我們自定義的webhook服務(wù)異常時(shí)翔忽,采取的策略(Ignore:忽略異常繼續(xù)處理,F(xiàn)ail:直接失敗退出不繼續(xù)處理)
- rules.operations:監(jiān)聽apiServer的操作類型盏檐,樣例中歇式,只有符合UPDATE類型的apiServer調(diào)用才會交給我們自定義的webhook服務(wù)處理。
- rules.resources:監(jiān)聽apiServer的資源和子資源類型胡野,樣例中材失,只有符合nodes的status字段資源類型的apiServer調(diào)用才會交給我們自定義的webhook服務(wù)處理。
結(jié)合rules.operations和rules.resources的屬性硫豆,我們可以知道樣例中的MutatingWebhookConfiguration監(jiān)聽了集群中nodes資源的status數(shù)據(jù)向apiServer提交的更新操作(就是我們前面提到的心跳信息)龙巨,并且將所有的心跳信息發(fā)給了名為webhook-oversale-service的Service下的/mutate接口處理,這個(gè)接口就是我們自定義的webhook服務(wù)提供的熊响。
上圖中的Pod跑著的容器就是我們自定義的webhook服務(wù)旨别,一個(gè)自定義webhook服務(wù)樣例供參考
例子
資源超賣問題分析
在生產(chǎn)環(huán)境中,kubernetes集群的計(jì)算節(jié)點(diǎn)上運(yùn)行著許許多多的Pod耘眨,分別跑著各種業(yè)務(wù)容器昼榛,我們通常用Deployment、DeamonSet剔难、StatefulSet等資源對象去控制Pod的增刪改胆屿。因此,開發(fā)或運(yùn)維往往需要配置這些資源對象的Containers字段中業(yè)務(wù)容器的CPU和內(nèi)存的資源配額:requests和limit
requests:節(jié)點(diǎn)調(diào)度pod需要的資源偶宫,每次成功調(diào)度則將節(jié)點(diǎn)的Allocatable屬性值(可分配資源)重新計(jì)算非迹,
新的Allocatable值 = 舊的Allocatable值 - 設(shè)置的requests值
limit:節(jié)點(diǎn)中運(yùn)行pod能夠獲得的最大資源,當(dāng)cpu
我們不難發(fā)現(xiàn)纯趋,當(dāng)requests字段設(shè)置太大的時(shí)候憎兽,pod實(shí)際使用的資源卻很小,導(dǎo)致計(jì)算節(jié)點(diǎn)的Allocatable值很快就被消耗完吵冒,節(jié)點(diǎn)的資源利用率會變得很低纯命。
上圖中最大的藍(lán)色框(allocatable)為計(jì)算節(jié)點(diǎn)可分配資源,橙色框(requests)為用戶配置的requests屬性痹栖,紅色框(current)為業(yè)務(wù)容器實(shí)際使用的資源亿汞。因此節(jié)點(diǎn)的資源利用率為 current / allocatable。而由于requests設(shè)置太大揪阿,占滿了allocatable疗我,導(dǎo)致新的pod無法被調(diào)度到這個(gè)節(jié)點(diǎn)咆畏,就會出現(xiàn)節(jié)點(diǎn)實(shí)際資源占用很低,卻因?yàn)閍llocatable太低導(dǎo)致pod無法調(diào)度到該節(jié)點(diǎn)的現(xiàn)象吴裤。
因此我們能否通過動(dòng)態(tài)調(diào)整allocatable的值來讓計(jì)算節(jié)點(diǎn)的可分配資源變得"虛高"旧找,騙過k8s的調(diào)度器,讓它以為該節(jié)點(diǎn)可分配資源很大麦牺,讓盡可能多的pod調(diào)度到該節(jié)點(diǎn)上呢钮蛛?
上圖通過將allocatable值擴(kuò)大(fake allcatable),讓更多的pod調(diào)度到了改節(jié)點(diǎn)剖膳,節(jié)點(diǎn)的資源利用率 current / allocatable 就變大了愿卒。
apiVersion: v1
kind: Node
metadata:
annotations:
...
creationTimestamp: ...
labels:
...
name: k8s-master.com
resourceVersion: "7564956"
selfLink: /api/v1/nodes/k8s-master.com
uid: ...
spec:
podCIDR: 10.244.0.0/24
status:
addresses:
- address: 172.16.0.2
type: InternalIP
- address: k8s-master.com
type: Hostname
allocatable: ## 這就是需要?jiǎng)討B(tài)修改的字段!3泵亍!
cpu: "1"
ephemeral-storage: "47438335103"
hugepages-2Mi: "0"
memory: 3778260Ki
pods: "110"
capacity:
cpu: "1"
ephemeral-storage: 51473888Ki
hugepages-2Mi: "0"
memory: 3880660Ki
pods: "110"
conditions:
...
daemonEndpoints:
...
images:
...
實(shí)現(xiàn)資源超賣的思路
實(shí)現(xiàn)資源超賣的關(guān)鍵在于動(dòng)態(tài)修改節(jié)點(diǎn)Node對象的allocatable字段值易结,而我們看到allocatable字段屬于Status字段枕荞,顯然不能直接通過kubectl edit命令來直接修改。因?yàn)镾tatus字段和Spec字段不同搞动,Spec是用戶設(shè)置的期望數(shù)據(jù)躏精,而Status是實(shí)際數(shù)據(jù)(Node節(jié)點(diǎn)通過不斷向apiServer發(fā)送心跳來更新自己的實(shí)時(shí)狀態(tài),最終存在etcd中)鹦肿。那么我們要怎么去修改Stauts字段呢矗烛?
首先,要修改k8s中任何資源對象的Status值箩溃,k8s官方提供了一套RESTful API:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13
可以通過patch或者put方法來調(diào)用k8s的RESTful API瞭吃,實(shí)現(xiàn)Stauts字段的修改。(這里是通過ApiServer去修改etcd中保存的Status字段的值)
但是涣旨,Node資源對象比較特殊歪架,計(jì)算節(jié)點(diǎn)會不斷給ApiServer發(fā)送心跳(默認(rèn)每隔10s發(fā)一次),將帶有Status字段的真實(shí)信息發(fā)送給ApiServer霹陡,并更新到etcd中和蚪。也就是無論你怎么通過patch/put方法去修改Node的Status字段,計(jì)算節(jié)點(diǎn)都會定時(shí)通過發(fā)送心跳將真實(shí)的Status數(shù)據(jù)覆蓋你修改的數(shù)據(jù)烹棉,也就是說我們無法通過直接調(diào)用RESTful API修改Node對象中的Status數(shù)據(jù)攒霹。
那我們是否可以直接監(jiān)聽這個(gè)計(jì)算節(jié)點(diǎn)的心跳數(shù)據(jù),通過修改心跳數(shù)據(jù)中的Status字段中的allocatable值浆洗,從而實(shí)現(xiàn)資源超賣呢催束?
答案是肯定的,k8s在ApiServer中就提供了Admission Controller(準(zhǔn)入控制器)的機(jī)制辅髓,其中包括了MutatingAdmissionWebhook泣崩,通過這個(gè)webhook少梁,所有和集群中所有和ApiSever交互的請求都被發(fā)送到一個(gè)指定的接口中,我們只要提供一個(gè)這樣的接口矫付,就可以獲取到Node往ApiServer發(fā)送心跳的Staus數(shù)據(jù)了凯沪。然后將這個(gè)數(shù)據(jù)進(jìn)行我們的自定義修改,再往后傳給etcd买优,就能讓etcd以為我們修改過的Status數(shù)據(jù)就是節(jié)點(diǎn)的真實(shí)Status妨马,最終實(shí)現(xiàn)資源的超賣。
Sidecar Injector自動(dòng)注入
Sidecar注入
我們都知道杀赢,Istio的流量管理烘跺、策略、遙測等功能無須應(yīng)用程序做任何改動(dòng)脂崔,這種無侵入式的方式全部依賴于Sidecar滤淳。應(yīng)用程序發(fā)送或者接收的流量都被Sidecar攔截,并由Sidecar進(jìn)行認(rèn)證砌左、鑒權(quán)脖咐、策略執(zhí)行及遙測數(shù)據(jù)上報(bào)等眾多治理功能。
如圖所示汇歹,在Kubernetes中屁擅,Sidecar容器與應(yīng)用容器共存于同一個(gè)Pod中,并且共享同一個(gè)Network Namespaces产弹,因此Sidecar容器與應(yīng)用容器共享同一個(gè)網(wǎng)絡(luò)協(xié)議棧派歌,這也是Sidecar能夠通過iptables攔截應(yīng)用進(jìn)出口流量的根本原因。
Istio的Sidecar模式
在Istio中進(jìn)行Sidecar注入有兩種方式:一種是通過istioctl命令行工具手動(dòng)注入;另一種是通Istio Sidecar Injector自動(dòng)注入痰哨。
這兩種方式的最終目的都是在應(yīng)用Pod中注入init容器及istio-proxy容器這兩個(gè)Sidecar容器胶果。如下所示,通過部署Istio的sleep應(yīng)用作谭,Sidecar是通過sidecar-injector自動(dòng)注入的稽物,查看注入的Sidecar容器:
istio-proxy 容器:
- args: # istio-proxy 容器命令行參數(shù)
- proxy
- sidecar
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --configPath
- /etc/istio/proxy
- --binaryPath
- /usr/local/bin/envoy
- --serviceCluster
- sleep.default
- --drainDuration
- 45s
- --parentShutdownDuration
- 1m0s
- --discoveryAddress
- istio-pilot.istio-system:15011
- --zipkinAddress
- zipkin.istio-system:9411
- --connectTimeout
- 10s
- --proxyAdminPort
- "15000"
- --controlPlaneAuthPolicy
- MUTUAL_TLS
- --statusPort
- "15020"
- --applicationPorts
- ""
env: # istio-proxy 容器環(huán)境變量
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: ISTIO_META_POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: ISTIO_META_CONFIG_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: ISTIO_META_INTERCEPTION_MODE
value: REDIRECT
- name: ISTIO_METAJSON_LABELS
value: |
{"app":"sleep","pod-template-hash":"7f59fddf5f"}
image: gcr.io/istio-release/proxyv2:release-1.1-20190124-15-51
imagePullPolicy: IfNotPresent
name: istio-proxy
……
volumeMounts: # istio-proxy掛載的證書及配置文件
- mountPath: /etc/istio/proxy
name: istio-envoy
- mountPath: /etc/certs/
name: istio-certs
readOnly: true
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: sleep-token-266l9
readOnly: true
istio-init容器:
initContainers: # istio-init容器,用于初始化Pod網(wǎng)絡(luò)
- args:
- -p
- "15001"
- -u
- "1337"
- -m
- REDIRECT
- -i
- '*'
- -x
- ""
- -b
- ""
- -d
- "15020"
image: gcr.io/istio-release/proxy_init:release-1.1-20190124-15-51
imagePullPolicy: IfNotPresent
name: istio-init
……
securityContext:
capabilities:
add:
- NET_ADMIN
procMount: Default
Sidecar Injector自動(dòng)注入的原理
Sidecar Injector是Istio中實(shí)現(xiàn)自動(dòng)注入Sidecar的組件折欠,它是以Kubernetes準(zhǔn)入控制器Admission Controller的形式運(yùn)行的贝或。Admission Controller的基本工作原理是攔截Kube-apiserver的請求,在對象持久化之前锐秦、認(rèn)證鑒權(quán)之后進(jìn)行攔截咪奖。Admission Controller有兩種:一種是內(nèi)置的,另一種是用戶自定義的酱床。Kubernetes允許用戶以Webhook的方式自定義準(zhǔn)入控制器羊赵,Sidecar Injector就是這樣一種特殊的MutatingAdmissionWebhook。
如圖所示,Sidecar Injector只在創(chuàng)建Pod時(shí)進(jìn)行Sidecar容器注入昧捷,在Pod的創(chuàng)建請求到達(dá)Kube-apiserver后闲昭,首先進(jìn)行認(rèn)證鑒權(quán),然后在準(zhǔn)入控制階段靡挥,Kube-apiserver以REST的方式同步調(diào)用Sidecar Injector Webhook服務(wù)進(jìn)行init與istio-proxy容器的注入序矩,最后將Pod對象持久化存儲到etcd中。
Sidecar Injector可以通過MutatingWebhookConfiguration API動(dòng)態(tài)配置生效跋破,Istio中的MutatingWebhook配置如下:
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
creationTimestamp: "2019-02-12T06:00:51Z"
generation: 4
labels:
app: sidecarInjectorWebhook
chart: sidecarInjectorWebhook
heritage: Tiller
release: istio
name: istio-sidecar-injector
resourceVersion: "2974010"
selfLink: /apis/admissionregistration.k8s.io/v1beta1/mutatingwebhookconfigurations/istio-sidecar-injector
uid: 8d62addb-2e8b-11e9-b464-fa163ed0737f
webhooks:
- clientConfig:
caBundle: ……
service:
name: istio-sidecar-injector
namespace: istio-system
path: /inject
failurePolicy: Fail
name: sidecar-injector.istio.io
namespaceSelector:
matchLabels:
istio-injection: enabled
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
sideEffects: Unknown
從以上配置可知簸淀,Sidecar Injector只對標(biāo)簽匹配“istio-injection: enabled”的命名空間下的Pod資源對象的創(chuàng)建生效。Webhook服務(wù)的訪問路徑為“/inject”毒返,地址及訪問憑證等都在clientConfig字段下進(jìn)行配置租幕。
Istio Sidecar Injector組件是由sidecar-injector進(jìn)程實(shí)現(xiàn)的,本書在之后將二者視為同一概念拧簸。Sidecar Injector的實(shí)現(xiàn)主要由兩部分組成:
維護(hù)MutatingWebhookConfiguration劲绪;
啟動(dòng)Webhook Server,為應(yīng)用工作負(fù)載自動(dòng)注入Sidecar容器盆赤。
MutatingWebhookConfiguration對象的維護(hù)主要指監(jiān)聽本地證書的變化及Kubernetes MutatingWebhookConfiguration資源的變化珠叔,以檢查CA證書或者CA數(shù)據(jù)是否有更新,并且在本地CA證書與MutatingWebhookConfiguration中的CA證書不一致時(shí)弟劲,自動(dòng)更新MutatingWebhookConfiguration對象。