准入控制器会在验证和授权请求之后,对象被持久化之前,拦截kube-apiserver的请求,拦截后的请求进入准入控制器中处理,对请求的资源对象执行自定义(校验、修改或拒绝等)操作。
准入控制器以插件的形式运行在kube-apiserver进程中,插件化的好处在于可扩展插件并单独启用/禁用指定插件,也可以将每个准入控制器称为准入控制器插件。kube-apiserver支持多种准入控制器机制,并支持同时开启多个准入控制器功能,如果开启了多个准入控制器,则按照顺序执行准入控制器。
K8S默认提供很多内置的admission controller,通过kube-apiserver启动命令参数可以 查看到支持的admission controller plugin有哪些。
# kube-apiserver --help |grep enable-admission-plugins# 支持的plugin有如下AlwaysAdmit, AlwaysDeny, AlwaysPullImages,DefaultStorageClass, DefaultTolerationSeconds, DenyEscalatingExec,DenyExecOnPrivileged, EventRateLimit, ExtendedResourceToleration,ImagePolicyWebhook, Initializers, LimitPodHardAntiAffinityTopology,LimitRanger, MutatingAdmissionWebhook, NamespaceAutoProvision,NamespaceExists, NamespaceLifecycle, NodeRestriction,OwnerReferencesPermissionEnforcement, PersistentVolumeClaimResize,PersistentVolumeLabel, PodNodeSelector, PodPreset, PodSecurityPolicy,PodTolerationRestriction, Priority, ResourceQuota, SecurityContextDeny,ServiceAccount, StorageObjectInUseProtection, ValidatingAdmissionWebhook.
这里enable的admission-plugins如下
--enable-admission-plugins=PersistentVolumeClaimResize,NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota,NodeRestriction,ValidatingAdmissionWebhook,MutatingAdmissionWebhook
客户端发起一个请求,在请求经过准入控制器列表时,只要有一个准入控制器拒绝了该请求,则整个请求被拒绝(HTTP 403 Forbidden)并返回一个错误给客户端。准入控制器流程如图7-33所示。
kube-apiserver目前支持如下两种准入控制器。
- 变更准入控制器(Mutating Admission Controller):用于变更信息,能够修改用户提交的资源对象信息。
- 验证准入控制器(Validating Admission Controller):用于身份验证,能够验证用户提交的资源对象信息。提示:变更准入控制器运行在验证准入控制器之前。变更准入控制器和验证准入控制器接口定义分别是MutationInterface和ValidationInterface,代码示例如下:
代码路径:vendor/k8s.io/apiserver/pkg/admission/interfaces.go
// Interface is an abstract, pluggable interface for Admission Control decisions.
type Interface interface {
// Handles returns true if this admission controller can handle the given operation
// where operation can be one of CREATE, UPDATE, DELETE, or CONNECT
Handles(operation Operation) bool
}
type MutationInterface interface {
Interface
// Admit makes an admission decision based on the request attributes.
// Context is used only for timeout/deadline/cancellation and tracing information.
Admit(ctx context.Context, a Attributes, o ObjectInterfaces) (err error)
}
// ValidationInterface is an abstract, pluggable interface for Admission Control decisions.
type ValidationInterface interface {
Interface
// Validate makes an admission decision based on the request attributes. It is NOT allowed to mutate
// Context is used only for timeout/deadline/cancellation and tracing information.
Validate(ctx context.Context, a Attributes, o ObjectInterfaces) (err error)
kube-apiserver中的所有已启用的准入控制器(Admit方法及Validate方法)由vendor/k8s.io/apiserver/pkg/admission/chain.go下的chainAdmissionHandler []Interface数据结构管理,chainAdmissionHandler数据结构如图所示。
在Admission Controller Handler中,会遍历已启用的准入控制器列表,按顺序尝试执行每个准入控制器,执行所有的变更操作。代码示例如下:
代码路径:vendor/k8s.io/apiserver/pkg/admission/chain.go
// Admit performs an admission control check using a chain of handlers, and returns immediately on first error
func (admissionHandler chainAdmissionHandler) Admit(ctx context.Context, a Attributes, o ObjectInterfaces) error {
for _, handler := range admissionHandler {
if !handler.Handles(a.GetOperation()) {
continue
}
if mutator, ok := handler.(MutationInterface); ok {
err := mutator.Admit(ctx, a, o)
if err != nil {
return err
}
}
}
return nil
}
同样的方式执行Validate函数,Validate函数会遍历已启用的准入控制器列表,并执行验证操作的准入控制器(即拥有Validate方法的准入控制器),代码示例如下:
// Validate performs an admission control check using a chain of handlers, and returns immediately on first error
func (admissionHandler chainAdmissionHandler) Validate(ctx context.Context, a Attributes, o ObjectInterfaces) error {
for _, handler := range admissionHandler {
if !handler.Handles(a.GetOperation()) {
continue
}
if validator, ok := handler.(ValidationInterface); ok {
err := validator.Validate(ctx, a, o)
if err != nil {
return err
}
}
}
return nil
}
应用场景:
- node资源超卖
- 自动打标签 比如启动一个应用,应用包括deployment、service、ingress; 怎么快速过滤出哪些资源属于应用? 在K8S中,pod、service、ingress 都是独立的资源,通过给这些资源打上label,是最快速的方式。
- 自动注入sidecar容器 应用启动后,应用的监控、日志如何处理?借助sidecar容器注入到其pod中
