- 一.系統環境
- 二.前言
- 三.准入控制器簡介
- 四.為什麼需要准入控制器
- 五.啟用/禁用ResourceQuota資源配額
- 5.1 檢視預設啟用/禁用的准入控制器外掛
- 5.2 ResourceQuota資源配額示例
- 5.3 禁用ResourceQuota
- 六.配置ImagePolicyWebhook准入控制器禁止使用字尾為latest的映象
- 6.1 搭建Webhook伺服器
- 6.2 配置kubernetes連線後端webhook伺服器
- 6.3 驗證
- 七.總結
一.系統環境
本文主要基於Kubernetes1.22.2和Linux作業系統Ubuntu 18.04。
伺服器版本 | docker軟體版本 | Kubernetes(k8s)叢集版本 | CPU架構 |
---|---|---|---|
Ubuntu 18.04.5 LTS | Docker version 20.10.14 | v1.22.2 | x86_64 |
Kubernetes叢集架構:k8scludes1作為master節點,k8scludes2,k8scludes3作為worker節點。
伺服器 | 作業系統版本 | CPU架構 | 程序 | 功能描述 |
---|---|---|---|---|
k8scludes1/192.168.110.128 | Ubuntu 18.04.5 LTS | x86_64 | docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico | k8s master節點 |
k8scludes2/192.168.110.129 | Ubuntu 18.04.5 LTS | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker節點 |
k8scludes3/192.168.110.130 | Ubuntu 18.04.5 LTS | x86_64 | docker,kubelet,kube-proxy,calico | k8s worker節點 |
二.前言
在本文中,我們將探討Kubernetes中的准入控制器(Admission Controller)。准入控制器是Kubernetes API server的一部分,負責處理來自外部的API請求。它們確保只有滿足特定條件的請求才能訪問叢集資源。透過使用准入控制器,我們可以實現對叢集資源的細粒度控制,從而提高叢集的安全性和可靠性。
使用准入控制器(Admission Controller)的前提是已經有一套可以正常執行的Kubernetes叢集,關於Kubernetes(k8s)叢集的安裝部署,可以檢視部落格《Ubuntu 安裝部署Kubernetes(k8s)叢集》https://www.cnblogs.com/renshengdezheli/p/17632858.html。
三.准入控制器簡介
當使用者賬戶或者service account要執行一些操作的時候,首先要進行賬號認證,認證透過之後,如果賬號已經被授權相關資源,就可以進行相關操作了。有時授權之後也會有Admission control准入控制器(可以理解為一系列規則,可以啟用或者關閉某個功能,准入控制器也支援一系列的webhook,在webhook裡可以定義一系列規則),滿足Admission control准入控制器的規則就可以建立相關資源了。OPA Gatekeeper也是利用的准入控制器功能,詳情請檢視部落格《OPA Gatekeeper:Kubernetes的策略和管理》。
准入控制器 是一段程式碼,它會在請求透過認證和鑑權之後、物件被持久化之前攔截到達 API 伺服器的請求。
准入控制器可以執行驗證(Validating) 和/或變更(Mutating) 操作。 變更(mutating)控制器可以根據被其接受的請求更改相關物件;驗證(validating)控制器則不行。
准入控制器限制建立、刪除、修改物件的請求。 准入控制器也可以阻止自定義動作,例如透過 API 伺服器代理連線到 Pod 的請求。 准入控制器不會 (也不能)阻止讀取(get、watch 或 list)物件的請求。
Kubernetes 1.30 中的准入控制器編譯進 kube-apiserver 可執行檔案,並且只能由叢集管理員配置。 在該列表中,有兩個特殊的控制器:MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook。 它們根據 API 中的配置, 分別執行變更和驗證准入控制 Webhook。
准入控制過程分為兩個階段。第一階段,執行變更准入控制器。第二階段,執行驗證准入控制器。 再次提醒,某些控制器既是變更准入控制器又是驗證准入控制器。
如果兩個階段之一的任何一個控制器拒絕了某請求,則整個請求將立即被拒絕,並向終端使用者返回錯誤。
最後,除了對物件進行變更外,准入控制器還可能有其它副作用:將相關資源作為請求處理的一部分進行變更。 增加配額用量就是一個典型的示例,說明了這樣做的必要性。 此類用法都需要相應的回收或回撥過程,因為任一準入控制器都無法確定某個請求能否透過所有其它准入控制器。
四.為什麼需要准入控制器
Kubernetes 的若干重要功能都要求啟用一個准入控制器,以便正確地支援該特性。 因此,沒有正確配置准入控制器的 Kubernetes API 伺服器是不完整的,它無法支援你所期望的所有特性。
五.啟用/禁用ResourceQuota資源配額
5.1 檢視預設啟用/禁用的准入控制器外掛
本文中的kube-apiserver是以pod的方式執行的,名字為:kube-apiserver-k8scludes1。
root@k8scludes1:~# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-65898446b5-qd9q6 1/1 Running 21 (2d8h ago) 28d
calico-node-d6564 1/1 Running 58 (2d8h ago) 59d
calico-node-jgvjb 1/1 Running 67 (10h ago) 59d
calico-node-snkxp 1/1 Running 58 (2d8h ago) 59d
coredns-7f6cbbb7b8-5gpjt 1/1 Running 20 (2d8h ago) 28d
coredns-7f6cbbb7b8-xm6pl 1/1 Running 20 (2d8h ago) 28d
etcd-k8scludes1 1/1 Running 54 (2d8h ago) 58d
kube-apiserver-k8scludes1 1/1 Running 15 (10h ago) 19d
kube-controller-manager-k8scludes1 1/1 Running 249 (10h ago) 59d
kube-proxy-464tx 1/1 Running 52 (2d8h ago) 59d
kube-proxy-mkwpx 1/1 Running 52 (2d8h ago) 59d
kube-proxy-vsc9q 1/1 Running 53 (2d8h ago) 59d
kube-scheduler-k8scludes1 1/1 Running 247 (10h ago) 59d
檢視kube-apiserver的幫助資訊。
root@k8scludes1:~# kubectl exec -it kube-apiserver-k8scludes1 -n kube-system -- kube-apiserver -h
The Kubernetes API server validates and configures data
for the api objects which include pods, services, replicationcontrollers, and
others. The API Server services REST operations and provides the frontend to the
......
--goaway-chance float
To prevent HTTP/2 clients from getting stuck on a single apiserver, randomly close a connection (GOAWAY). The client's other in-flight requests won't be affected, and the client will
reconnect, likely landing on a different apiserver after going through the load balancer again. This argument sets the fraction of requests that will be sent a GOAWAY. Clusters with single
apiservers, or which don't use a load balancer, should NOT enable this. Min is 0 (off), Max is .02 (1/50 requests); .001 (1/1000) is a recommended starting point.
--livez-grace-period duration
This option represents the maximum amount of time it should take for apiserver to complete its startup sequence and become live. From apiserver's start time to when this amount of time has
elapsed, /livez will assume that unfinished post-start hooks will complete successfully and therefore return true.
--vmodule moduleSpec
comma-separated list of pattern=N settings for file-filtered logging
檢視預設啟用/禁止的准入控制器外掛有哪些?可以看到預設啟用的准入控制器外掛有:CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, LimitRanger, MutatingAdmissionWebhook, NamespaceLifecycle, PersistentVolumeClaimResize, PodSecurity, Priority, ResourceQuota, RuntimeClass, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionPolicy, ValidatingAdmissionWebhook。
root@k8scludes1:~# kubectl exec -it kube-apiserver-k8scludes1 -n kube-system -- kube-apiserver -h | grep admission-plugins
--admission-control strings Admission is divided into two phases. In the first phase, only mutating admission plugins run. In the second phase, only validating admission plugins run. The names in the below list may represent a validating plugin, a mutating plugin, or both. The order of plugins in which they are passed to this flag does not matter. Comma-delimited list of: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyServiceExternalIPs, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurity, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. (DEPRECATED: Use --enable-admission-plugins or --disable-admission-plugins instead. Will be removed in a future version.)
--disable-admission-plugins strings admission plugins that should be disabled although they are in the default enabled plugins list (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyServiceExternalIPs, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurity, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
--enable-admission-plugins strings admission plugins that should be enabled in addition to default enabled ones (NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, PodSecurity, Priority, DefaultTolerationSeconds, DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, RuntimeClass, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota). Comma-delimited list of admission plugins: AlwaysAdmit, AlwaysDeny, AlwaysPullImages, CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, DenyServiceExternalIPs, EventRateLimit, ExtendedResourceToleration, ImagePolicyWebhook, LimitPodHardAntiAffinityTopology, LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision, NamespaceExists, NamespaceLifecycle, NodeRestriction, OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize, PersistentVolumeLabel, PodNodeSelector, PodSecurity, PodSecurityPolicy, PodTolerationRestriction, Priority, ResourceQuota, RuntimeClass, SecurityContextDeny, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionWebhook. The order of plugins in this flag does not matter.
5.2 ResourceQuota資源配額示例
建立目錄存放yaml檔案。
root@k8scludes1:~# mkdir admissioncontr
root@k8scludes1:~# cd admissioncontr/
建立名稱空間。
root@k8scludes1:~/admissioncontr# kubectl create ns admissioncontr
namespace/admissioncontr created
切換名稱空間到admissioncontr。
root@k8scludes1:~/admissioncontr# kubens admissioncontr
Context "kubernetes-admin@kubernetes" modified.
Active namespace is "admissioncontr".
編輯pod配置檔案,使用nginx映象生成pod。
root@k8scludes1:~/admissioncontr# vim pod.yaml
root@k8scludes1:~/admissioncontr# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: podtest
name: podtest
spec:
#當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
terminationGracePeriodSeconds: 0
containers:
- image: hub.c.163.com/library/nginx:latest
#imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
imagePullPolicy: IfNotPresent
name: podtest
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
建立pod。
root@k8scludes1:~/admissioncontr# kubectl apply -f pod.yaml
pod/podtest created
使用相同的yaml檔案,生成另外兩個pod。
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest1/' pod.yaml | kubectl apply -f -
pod/podtest1 created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest2/' pod.yaml | kubectl apply -f -
pod/podtest2 created
現在沒有任何限制,可以正常建立多個pod。
root@k8scludes1:~/admissioncontr# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
podtest 1/1 Running 0 61s 10.244.218.179 k8scludes2 <none> <none>
podtest1 1/1 Running 0 15s 10.244.218.133 k8scludes2 <none> <none>
podtest2 1/1 Running 0 9s 10.244.1.84 k8scludes3 <none> <none>
刪除pod。
root@k8scludes1:~/admissioncontr# kubectl delete pod podtest podtest1 podtest2
pod "podtest" deleted
pod "podtest1" deleted
pod "podtest2" deleted
現在沒有設定resourcequota資源配額。
root@k8scludes1:~/admissioncontr# kubectl get quota
No resources found in admissioncontr namespace.
root@k8scludes1:~/admissioncontr# kubectl get resourcequota
No resources found in admissioncontr namespace.
編輯ResourceQuota配置檔案,表示建立一個resourcequota資源配額,當前名稱空間只能建立2個pod。
resourcequota 資源配額用來設定一個名稱空間最多能建立多少個資源物件,比如能建立多少svc,能建立多少pod或者deploy,詳細資訊請檢視部落格《Kubernetes(k8s) 資源限制:resources,LimitRange,ResourceQuota》。
root@k8scludes1:~/admissioncontr# vim resourcequota.yaml
root@k8scludes1:~/admissioncontr# cat resourcequota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: myresourcequota
spec:
#hard:指定資源的硬性限制,即最大允許使用的資源數量。
hard:
pods: "2"
建立ResourceQuota。
root@k8scludes1:~/admissioncontr# kubectl apply -f resourcequota.yaml
resourcequota/myresourcequota created
檢視resourcequota資源配額,可以看到pod資源限額是2,現在有0個pod。
root@k8scludes1:~/admissioncontr# kubectl get resourcequota
NAME AGE REQUEST LIMIT
myresourcequota 11s pods: 0/2
再次建立pod。
root@k8scludes1:~/admissioncontr# kubectl apply -f pod.yaml
pod/podtest created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest1/' pod.yaml | kubectl apply -f -
pod/podtest1 created
建立第三個pod的時候報錯了,pod資源配額是2,超過2個pod就建立失敗了。
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest2/' pod.yaml | kubectl apply -f -
Error from server (Forbidden): error when creating "STDIN": pods "podtest2" is forbidden: exceeded quota: myresourcequota, requested: pods=1, used: pods=2, limited: pods=2
檢視resourcequota,可以看到pods: 2/2,資源配額滿了。
root@k8scludes1:~/admissioncontr# kubectl get resourcequota
NAME AGE REQUEST LIMIT
myresourcequota 5m48s pods: 2/2
刪除pod。
root@k8scludes1:~/admissioncontr# kubectl delete pod podtest podtest1
pod "podtest" deleted
pod "podtest1" deleted
5.3 禁用ResourceQuota
resourcequota 資源配額是一種准入控制器外掛,預設是啟用的。我們可以把resourcequota禁用了。
修改kube-apiserver.yaml檔案,禁用resourcequota 資源配額。
disable-admission-plugins=ResourceQuota表示禁用准入控制器外掛ResourceQuota。
root@k8scludes1:~/admissioncontr# vim /etc/kubernetes/manifests/kube-apiserver.yaml
root@k8scludes1:~/admissioncontr# grep disable-admission-plugins /etc/kubernetes/manifests/kube-apiserver.yaml
- --disable-admission-plugins=ResourceQuota
重啟kubelet使配置生效。
root@k8scludes1:~/admissioncontr# systemctl restart kubelet
現在resourcequota 資源配額還在,還是要求當前名稱空間只能建立2個pod。
root@k8scludes1:~/admissioncontr# kubectl get resourcequota
NAME AGE REQUEST LIMIT
myresourcequota 16m pods: 0/2
一口氣建立了5個pod還是沒有報錯。
root@k8scludes1:~/admissioncontr# kubectl apply -f pod.yaml
pod/podtest created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest1/' pod.yaml | kubectl apply -f -
pod/podtest1 created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest2/' pod.yaml | kubectl apply -f -
pod/podtest2 created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest3/' pod.yaml | kubectl apply -f -
pod/podtest3 created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest4/' pod.yaml | kubectl apply -f -
pod/podtest4 created
root@k8scludes1:~/admissioncontr# kubectl get pod
NAME READY STATUS RESTARTS AGE
podtest 1/1 Running 0 30s
podtest1 1/1 Running 0 21s
podtest2 1/1 Running 0 16s
podtest3 1/1 Running 0 11s
podtest4 1/1 Running 0 6s
可以發現,禁用resourcequota功能之後,就算有resourcequota物件存在,資源配額也不生效。
root@k8scludes1:~/admissioncontr# kubectl get resourcequota
NAME AGE REQUEST LIMIT
myresourcequota 3m59s pods: 5/2
刪除pod。
root@k8scludes1:~# kubectl delete pod podtest podtest1 podtest2 podtest3 podtest4
pod "podtest" deleted
pod "podtest1" deleted
pod "podtest2" deleted
pod "podtest3" deleted
pod "podtest4" deleted
root@k8scludes1:~# kubectl get pod
No resources found in admissioncontr namespace.
編輯kube-apiserver.yaml,去掉disable-admission-plugins=ResourceQuota,讓ResourceQuota預設啟用。
root@k8scludes1:~# vim /etc/kubernetes/manifests/kube-apiserver.yaml
root@k8scludes1:~# grep disable-admission-plugins /etc/kubernetes/manifests/kube-apiserver.yaml
#- --disable-admission-plugins=ResourceQuota
重啟kubelet使配置生效。
root@k8scludes1:~# systemctl restart kubelet
現在resourcequota 資源配額還是要求當前名稱空間只能建立2個pod。
root@k8scludes1:~# kubectl get resourcequota
NAME AGE REQUEST LIMIT
myresourcequota 5h31m pods: 0/2
現在ResourceQuota資源配額又生效了,只能建立2個pod。
root@k8scludes1:~/admissioncontr# kubectl apply -f pod.yaml
pod/podtest created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest1/' pod.yaml | kubectl apply -f -
pod/podtest1 created
root@k8scludes1:~/admissioncontr# sed 's/podtest/podtest2/' pod.yaml | kubectl apply -f -
Error from server (Forbidden): error when creating "STDIN": pods "podtest2" is forbidden: exceeded quota: myresourcequota, requested: pods=1, used: pods=2, limited: pods=2
刪除pod。
root@k8scludes1:~/admissioncontr# kubectl delete pod podtest podtest1
pod "podtest" deleted
pod "podtest1" deleted
刪除ResourceQuota資源配額。
root@k8scludes1:~/admissioncontr# kubectl delete resourcequota myresourcequota
resourcequota "myresourcequota" deleted
root@k8scludes1:~/admissioncontr# kubectl get resourcequotas
No resources found in admissioncontr namespace.
六.配置ImagePolicyWebhook准入控制器禁止使用字尾為latest的映象
6.1 搭建Webhook伺服器
ImagePolicyWebhook的類別為驗證。ImagePolicyWebhook 准入控制器允許使用後端 Webhook 做出准入決策。此准入控制器預設被禁用。
准入 Webhook 是一種用於接收准入請求並對其進行處理的 HTTP 回撥機制。 可以定義兩種型別的准入 webhook,即驗證性質的准入 Webhook 和 修改性質的准入 Webhook。 修改性質的准入 Webhook 會先被呼叫。它們可以更改傳送到 API 伺服器的物件,以執行自定義的設定預設值操作。在完成了所有物件修改並且 API 伺服器也驗證了所傳入的物件之後, 驗證性質的 Webhook 會被呼叫,並透過拒絕請求的方式來強制實施自定義的策略。
說明: 如果准入 Webhook 需要保證它們所看到的是物件的最終狀態以實施某種策略。 則應使用驗證性質的准入 Webhook,因為物件被修改性質 Webhook 看到之後仍然可能被修改。
首先需要找一臺機器搭建Webhook伺服器,我們使用etcd2機器當Webhook伺服器。
首先需要安裝docker。
[root@etcd2 ~]# yum -y install docker-ce
檢視docker版本。
[root@etcd2 ~]# docker -v
Docker version 20.10.12, build e91ed57
配置docker映象加速器。
[root@etcd2 ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": [
"https://frz7i079.mirror.aliyuncs.com"
]
}
拉取flavio/kube-image-bouncer映象,flavio/kube-image-bouncer這個映象的功能為:不允許使用字尾為latest的映象。
[root@etcd2 ~]# docker pull flavio/kube-image-bouncer
Using default tag: latest
latest: Pulling from flavio/kube-image-bouncer
ff3a5c916c92: Pull complete
4947cf5a98cf: Pull complete
37ff781c0e4d: Pull complete
1545c1d26daf: Pull complete
dd581c9cf10b: Pull complete
Digest: sha256:01e1e0873d20cee1ffefb45421c798cb26250b7a9384978d34ffb1f57403d501
Status: Downloaded newer image for flavio/kube-image-bouncer:latest
docker.io/flavio/kube-image-bouncer:latest
檢視flavio/kube-image-bouncer映象歷史資訊,可以發現開放埠為1323(EXPOSE 1323),使用的是web賬號登入(USER web)。關於映象Dockerfile的詳細資訊,請檢視部落格《構建自定義映象並最佳化dockerfile檔案》。
[root@etcd2 ~]# docker history flavio/kube-image-bouncer
IMAGE CREATED CREATED BY SIZE COMMENT
3974e07cc0c8 3 years ago /bin/sh -c #(nop) EXPOSE 1323 0B
<missing> 3 years ago /bin/sh -c #(nop) ENTRYPOINT ["./kube-image… 0B
<missing> 3 years ago /bin/sh -c #(nop) USER web 0B
<missing> 3 years ago /bin/sh -c chown -R web:web * 19.9MB
<missing> 3 years ago /bin/sh -c #(nop) COPY file:de99d16a3731b75b… 19.9MB
<missing> 3 years ago /bin/sh -c adduser -h /app -D web 4.79kB
<missing> 3 years ago /bin/sh -c #(nop) WORKDIR /app 0B
<missing> 4 years ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 4 years ago /bin/sh -c #(nop) ADD file:093f0723fa46f6cdb… 4.15MB
使用flavio/kube-image-bouncer映象建立容器。
-v
pwd/webhook-key.pem:/certs/webhook-key.pem:ro -v
pwd/webhook.pem:/certs/webhook.pem:ro
表示做目錄對映(-v 本地目錄:容器目錄),webhook-key.pem公鑰和webhook.pem私鑰不存在也沒問題,ro表示容器只有只讀許可權。
-p 1323:1323表示做埠對映(物理機埠1323:容器埠1323)。關於容器更多詳細資訊,請檢視部落格《一文搞懂docker容器基礎:docker映象管理,docker容器管理》。
[root@etcd2 ~]# docker run -dit --name=c1 --restart=always -v `pwd`/webhook-key.pem:/certs/webhook-key.pem:ro -v `pwd`/webhook.pem:/certs/webhook.pem:ro -p 1323:1323 flavio/kube-image-bouncer
7c677fb67522073932617f07ad72cd1a17e60eddc6a68dd25ffe0b8c4f80aaae
容器建立成功了,這時候訪問192.168.110.131:1323 就訪問到該webhook伺服器了。
[root@etcd2 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7c677fb67522 flavio/kube-image-bouncer "./kube-image-bouncer" 10 seconds ago Up 8 seconds 0.0.0.0:1323->1323/tcp, :::1323->1323/tcp c1
6.2 配置kubernetes連線後端webhook伺服器
回到kubernetes叢集。
root@k8scludes1:~/admissioncontr# cd /etc/kubernetes/
root@k8scludes1:/etc/kubernetes# ls
admin.conf admission-control-config-file controller-manager.conf kubelet.conf manifests pki scheduler.conf
root@k8scludes1:/etc/kubernetes# cd admission-control-config-file/
root@k8scludes1:/etc/kubernetes/admission-control-config-file# ls
admission_configuration.json apiserver-client-key.pem apiserver-client.pem kubeconfig.yaml webhook-key.pem webhook.pem
root@k8scludes1:/etc/kubernetes/admission-control-config-file# pwd
/etc/kubernetes/admission-control-config-file
ImagePolicyWebhook 使用配置檔案來為後端行為設定選項。該檔案可以是 JSON 或 YAML。
admission_configuration.json是ImagePolicyWebhook 的配置檔案,引數解釋如下:
- allowTTL以秒計的時長,控制批准請求的快取時間;
- denyTTL以秒計的時長,控制拒絕請求的快取時間;
- retryBackoff以毫秒計的時長,控制重試間隔;
- defaultAllow確定 Webhook 後端失效時的行為;
- kubeConfigFile指定kubeconfig檔案的路徑。
root@k8scludes1:/etc/kubernetes/admission-control-config-file# vim admission_configuration.json
root@k8scludes1:/etc/kubernetes/admission-control-config-file# cat admission_configuration.json
{
"imagePolicy": {
"kubeConfigFile": "/etc/kubernetes/admission-control-config-file/kubeconfig.yaml",
"allowTTL": 50,
"denyTTL": 50,
"retryBackoff": 500,
"defaultAllow": true
}
}
root@k8scludes1:/etc/kubernetes/admission-control-config-file# ls /etc/kubernetes/admission-control-config-file/admission_configuration.json
/etc/kubernetes/admission-control-config-file/admission_configuration.json
kubeconfig.yaml用來設定與後端Webhook伺服器的連線,要求後端使用 TLS 進行通訊。
kubeconfig.yaml檔案的 clusters 欄位需要指向遠端Webhook服務,server指定webhook伺服器進行連線。
users 欄位需要包含已返回的授權者。關於kubeconfig檔案的詳細資訊,請檢視部落格《Kubernetes(k8s)訪問控制:身份認證》。
root@k8scludes1:/etc/kubernetes/admission-control-config-file# vim kubeconfig.yaml
#指定各種證書
root@k8scludes1:/etc/kubernetes/admission-control-config-file# cat kubeconfig.yaml
apiVersion: v1
kind: Config
clusters:
- cluster:
# CA 用於驗證遠端服務
certificate-authority: /etc/kubernetes/admission-control-config-file/webhook.pem
# 要查詢的遠端服務的 URL
server: http://192.168.110.131:1323/image_policy
name: bouncer_webhook
contexts:
- context:
cluster: bouncer_webhook
user: api-server
name: bouncer_validator
current-context: bouncer_validator
preferences: {}
users:
- name: api-server
user:
# Webhook 准入控制器使用的證書
client-certificate: /etc/kubernetes/admission-control-config-file/apiserver-client.pem
# 證書匹配的金鑰
client-key: /etc/kubernetes/admission-control-config-file/apiserver-client-key.pem
ImagePolicyWebhook預設是沒有開啟的,現在啟用ImagePolicyWebhook。
enable-admission-plugins=NodeRestriction,ImagePolicyWebhook表示啟用ImagePolicyWebhook准入控制器。
透過 --admission-control-config-file 引數指定準入控制器ImagePolicyWebhook配置檔案的位置。
root@k8scludes1:/etc/kubernetes/admission-control-config-file# vim /etc/kubernetes/manifests/kube-apiserver.yaml
root@k8scludes1:/etc/kubernetes/admission-control-config-file# grep admission /etc/kubernetes/manifests/kube-apiserver.yaml
- --enable-admission-plugins=NodeRestriction,ImagePolicyWebhook
- --admission-control-config-file=/etc/kubernetes/admission-control-config-file/admission_configuration.json
重啟kubelet使配置生效。
root@k8scludes1:/etc/kubernetes/admission-control-config-file# systemctl restart kubelet
可以發現kube-apiserver.yaml新增引數之後,連線不上叢集了。
root@k8scludes1:/etc/kubernetes/admission-control-config-file# kubectl get node
The connection to the server 192.168.110.128:6443 was refused - did you specify the right host or port?
下面開始排查問題,kubectl使用不了,那就只能使用docker排查問題了,使用docker檢視容器,可以發現k8s_kube-apiserver容器處於退出狀態。
root@k8scludes1:/etc/kubernetes/admission-control-config-file# cd
root@k8scludes1:~# docker ps -a | grep api
2aacfa2bdbc4 e64579b7d886 "kube-apiserver --ad…" 19 seconds ago Exited (1) 18 seconds ago k8s_kube-apiserver_kube-apiserver-k8scludes1_kube-system_054ae2c0df7fd5edd4ebb3b7057a0462_8
cb0e2e181dda registry.aliyuncs.com/google_containers/pause:3.5 "/pause" 4 minutes ago Up 4 minutes k8s_POD_kube-apiserver-k8scludes1_kube-system_054ae2c0df7fd5edd4ebb3b7057a0462_0
ac234a8ee92b e64579b7d886 "kube-apiserver --ad…" 4 minutes ago Exited (1) 4 minutes ago k8s_kube-apiserver_kube-apiserver-k8scludes1_kube-system_f38197908cec7cb32a42e0862e367c1c_0
49e9b9c1b389 registry.aliyuncs.com/google_containers/pause:3.5 "/pause" 4 minutes ago Up 4 minutes k8s_POD_kube-apiserver-k8scludes1_kube-system_f38197908cec7cb32a42e0862e367c1c_0
5d4985a8833c e64579b7d886 "kube-apiserver --ad…" 5 minutes ago Exited (1) 5 minutes ago k8s_kube-apiserver_kube-apiserver-k8scludes1_kube-system_3dc64835bcbf5bdf937660d07f41b90b_87
c674a6a6c794 registry.aliyuncs.com/google_containers/pause:3.5 "/pause" About an hour ago Up About an hour k8s_POD_kube-apiserver-k8scludes1_kube-system_3dc64835bcbf5bdf937660d07f41b90b_2
檢視k8s_kube-apiserver容器日誌,報錯為:“open /etc/kubernetes/admission-control-config-file/admission_configuration.json: no such file or directory“,發現admission_configuration.json檔案找不到。
root@k8scludes1:~# docker logs 2aacfa2bdbc4
I0616 01:39:59.927352 1 server.go:553] external host was not specified, using 192.168.110.128
I0616 01:39:59.927965 1 server.go:161] Version: v1.22.2
Error: failed to initialize admission: failed to read plugin config: unable to read admission control configuration from "/etc/kubernetes/admission-control-config-file/admission_configuration.json" [open /etc/kubernetes/admission-control-config-file/admission_configuration.json: no such file or directory]
/etc/kubernetes/admission-control-config-file/admission_configuration.json檔案是存在的,但是報錯。
原因為:/etc/kubernetes/admission-control-config-file/admission_configuration.json這個檔案是在宿主機裡的,並不在容器裡。
解決方法:做一個資料卷,把宿主機裡的檔案對映到容器裡。
root@k8scludes1:~# ls /etc/kubernetes/admission-control-config-file/admission_configuration.json
/etc/kubernetes/admission-control-config-file/admission_configuration.json
注意:生產環境裡可以先備份下kube-apiserver.yaml 檔案再修改,以免改不回來。
定義一個資料卷把宿主機的/etc/kubernetes/admission-control-config-file目錄掛載到容器/etc/kubernetes/admission-control-config-file目錄。
root@k8scludes1:~# vim /etc/kubernetes/manifests/kube-apiserver.yaml
root@k8scludes1:~# grep -A3 admission-control-config-file /etc/kubernetes/manifests/kube-apiserver.yaml
- --admission-control-config-file=/etc/kubernetes/admission-control-config-file/admission_configuration.json
#- --disable-admission-plugins=ResourceQuota
#- --enable-admission-plugins=NodeRestriction,PodSecurityPolicy
- --token-auth-file=/etc/kubernetes/pki/mytok.csv
--
- mountPath: /etc/kubernetes/admission-control-config-file
name: admissionconfile
readOnly: true
hostNetwork: true
--
path: /etc/kubernetes/admission-control-config-file
type: DirectoryOrCreate
name: admissionconfile
- hostPath:
直接上截圖可能更直觀:
重啟kubelet使配置生效。
root@k8scludes1:~# systemctl restart kubelet
現在k8s正常了。
root@k8scludes1:~# kubectl get pod
No resources found in admissioncontr namespace.
6.3 驗證
編輯pod配置檔案,表示使用hub.c.163.com/library/nginx:latest映象建立pod。
root@k8scludes1:~# cd admissioncontr/
root@k8scludes1:~/admissioncontr# vim pod.yaml
root@k8scludes1:~/admissioncontr# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: podtest
name: podtest
spec:
#當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
terminationGracePeriodSeconds: 0
containers:
- image: hub.c.163.com/library/nginx:latest
#imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
imagePullPolicy: IfNotPresent
name: podtest
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
建立pod,可以發現:使用tag為latest的映象不能建立pod。
root@k8scludes1:~/admissioncontr# kubectl apply -f pod.yaml
Error from server (Forbidden): error when creating "pod.yaml": pods "podtest" is forbidden: image policy webhook backend denied one or more images: Images using latest tag are not allowed
修改pod配置檔案,表示使用hub.c.163.com/library/nginx:test映象建立pod。
root@k8scludes1:~/admissioncontr# vim pod.yaml
root@k8scludes1:~/admissioncontr# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: podtest
name: podtest
spec:
#當需要關閉容器時,立即殺死容器而不等待預設的30秒優雅停機時長。
terminationGracePeriodSeconds: 0
containers:
- image: hub.c.163.com/library/nginx:test
#- image: hub.c.163.com/library/nginx:latest
#imagePullPolicy: IfNotPresent:表示如果本地已經存在該映象,則不重新下載;否則從遠端 Docker Hub 下載該映象
imagePullPolicy: IfNotPresent
name: podtest
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
映象tag為test,pod建立成功。
root@k8scludes1:~/admissioncontr# kubectl apply -f pod.yaml
pod/podtest created
root@k8scludes1:~/admissioncontr# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
podtest 1/1 Running 0 6s 10.244.218.145 k8scludes2 <none> <none>
刪除pod。
root@k8scludes1:~/admissioncontr# kubectl delete pod podtest
pod "podtest" deleted
七.總結
准入控制器是Kubernetes中一個非常重要的元件,它負責攔截和處理來自使用者或其他應用程式的API請求。透過使用准入控制器,我們可以實現對叢集資源的細粒度控制,從而提高叢集的安全性和可靠性。