一.系统环境

本文主要基于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镜像创建容器。

-vpwd/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请求。通过使用准入控制器,我们可以实现对集群资源的细粒度控制,从而提高集群的安全性和可靠性。

准入控制器(Admission Controller):ResourceQuota,ImagePolicyWebhook的更多相关文章

  1. 手把手教你在容器服务 TKE 中使用动态准入控制器

    在 TKE 中使用动态准入控制器 原理概述 动态准入控制器 Webhook 在访问鉴权过程中可以更改请求对象或完全拒绝该请求,其调用 Webhook 服务的方式使其独立于集群组件,具有非常大的灵活性, ...

  2. JMeter 逻辑控制之While循环控制器(While Controller)

    逻辑控制之While循环控制器(While Controller)   by:授客 QQ:1033553122 测试环境 apache-jmeter-2.13 1.   添加While Control ...

  3. 【Unity】11.1 角色控制器 (Character Controller)

    分类:Unity.C#.VS2015 创建日期:2016-05-02 一.简介 角色控制器(Character Controller)主要用于对第三人称或第一人称游戏主角的控制.如果要创建类人角色,可 ...

  4. Jmeter----逻辑控制器(Logic Controller)

    前言: 1. Jmeter官网对逻辑控制器的解释是:“Logic Controllers determine the order in which Samplers are processed.”.意 ...

  5. spring mvc: 多动作控制器(Controller下面实现多个访问的方法)MultiActionController / BeanNameUrlHandlerMapping

    spring mvc: 多动作控制器(Controller下面实现多个访问的方法) 比如我的控制器是UserController.java,下面有home, add, remove等多个方法 访问地址 ...

  6. C#编译器优化那点事 c# 如果一个对象的值为null,那么它调用扩展方法时为甚么不报错 webAPI 控制器(Controller)太多怎么办? .NET MVC项目设置包含Areas中的页面为默认启动页 (五)Net Core使用静态文件 学习ASP.NET Core Razor 编程系列八——并发处理

    C#编译器优化那点事   使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的.优化代码 ...

  7. 【JMeter_16】JMeter逻辑控制器__随机控制器<Random Controller>

    随机控制器<Random Controller> 业务逻辑: 当每次执行到该逻辑控制器时,随机挑选控制器下的任意一个子节点<取样器.逻辑控制器> Ignore sub-cont ...

  8. 【JMeter_22】JMeter逻辑控制器__录制控制器<Recording Controller>

    录制控制器<Recording Controller> 个人感觉录制的脚本缺陷太明显,没有研究过,暂不做介绍,等后续空了研究后再写

  9. 【JMeter_21】JMeter逻辑控制器__模块控制器<Module Controller>

    模块控制器<Module Controller> 业务逻辑: 可以理解为引用.调用的意思,执行内容为Module To Run种所选的内容,引用范围为当前测试计划内的测试片段.逻辑控制器& ...

  10. 【JMeter_20】JMeter逻辑控制器__事务控制器<Transaction Controller>

    事务控制器<Transaction Controller> 业务逻辑: 这个控制器在在业务控制上并没有什么特殊逻辑,可以理解为在简单控制器的基础上添加了统计的功能,当所有子节点全部成功则成 ...

随机推荐

  1. WPF 由于系统颜色配置 Mscms 组件损坏启动失败

    本文记录 WPF 应用程序,因为系统的颜色配置 Mscms.dll 组件损坏导致应用加载图片失败,从而启动失败的原因和解决方法 在 WPF 应用加载图片时,将会调用到系统的 Mscms.dll 组件. ...

  2. dotnet 对指针转换为结构体多个不同方法的性能分析

    在 dotnet 里面,拿到一个指针,可以有多个不同的方法转换为结构体,本文将来告诉大家这几个方法的性能的差别 特别感谢性能优化狂魔 Stephen Toub 大佬的指导 在 WPF 框架开发中,有小 ...

  3. 12.prometheus监控之Domain域名过期监控

    一.域名过期时间监控 域名的监控通过domain_exporter来完成 domain_exporter:https://github.com/caarlos0/domain_exporter/rel ...

  4. 羽夏壳世界—— PE 结构(下)

    写在前面   此系列是本人一个字一个字码出来的,包括代码实现和效果截图. 如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后 ...

  5. iptables命令详解

    安装iptables yum install iptables-services 编写允许访问的策略 vim /etc/sysconfig/iptables # sample configuratio ...

  6. chgrp chown

    chgrp 用来改变文件所属群组,如果要改变的群组不在/etc/group里面,将会报错. chown 用来改变文件的所有者,如果改变的所有者便在/etc/passwd里面,将会报错. 需要注意的是c ...

  7. three.js教程4-Group层级模型

    1.组对象Group.层级模型-形成树状结构 //创建两个网格模型mesh1.mesh2 const geometry = new THREE.BoxGeometry(20, 20, 20); con ...

  8. vue3组件封装

    1.父组件调用子组件属性和方法 父组件中template写法: <role-modal ref="myRoleModal" @OK="roleModalOK&quo ...

  9. VRRP 虚拟路由器冗余协议

    目录 文章目录 目录 为什么要使用 VRRP 技术? VRRP VRRP 的概念 VRRP 的工作原理 VRRP 的状态机 VRRP 的工作过程 VRRP 的选举机制 VRRP 的报文格式 VRRP ...

  10. 【HarmonyOS NEXT】获取卸载APP后不变的设备ID

    1. 背景 在HarmonyOS NEXT中,想要获取设备ID,有3种方式 UDID:deviceinfo.udid,仅限系统应用使用 AAID: aaid.getAAID(),然而卸载APP/恢复设 ...