k8s的Mutating webhook

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8s的Mutating webhook相关的知识,希望对你有一定的参考价值。

参考技术A Admission Webhook 是 api-server 对外提供的一个扩展能力,api-server 作为 kubernetes 的核心,几乎所有组件都需要跟他打交道,基本可以说掌控了 k8s 的 api-server,你就可以控制 k8s 的行为。

在早期的版本 api-server 并没有提供 admissionresgistration 的能力(v1.9之前),当我们要对 k8s 进行控制的时候,只能重新编译 api-server。比如你想阻止某个控制器的行为,或拦截某个控制器的资源修改。admission webhook 就是提供了这样的能力,比如你希望某个特定 label 标签的 pod 再创建的时候都注入 sidercar,或者阻止不合规的资源。

Admission Webhook 包涵两种 CRD: mutatingwebhookconfiguration 和 validatingwebhookconfiguration 。

下面是一个 mutatingwebhookconfiguration 的CRD文件:

Admission Webhook 本质是 api-server 的一个 webhook 调用,下面是 api-server 的处理流程:

api-server 通过读取 mutatingwebhookconfiguration 和 validatingwebhookconfiguration 的 CR 文件的目标地址,然后回调用户自定义的服务。

api-server 发起的请求是一串json数据格式,header需要设置 content-type 为 application/json , 我们看看请求的 body :

返回的结果:

这里的 patch 是用base64编码的一个json,我们解码看看,是一个 json patch:

处理函数:

主程序:

基于私钥生成一个证书签名请求(Certificate Signing Request,CSR),目标地址的域名为: mutating-test.testing-tools.svc , csr的配置:

创建命令:

基于csr创建 CertificateSigningRequest :

认证完成可以查看:

生成证书:

获取api-server的CA证书:

将这个证书填入 Webhook 的 caBundle。

MutatingAdmissionWebhook作为kubernetes的ApiServer中Admission Controller的一部分,提供了非常灵活的扩展机制,通过配置MutatingWebhookConfiguration对象,理论上可以监听并修改任何经过ApiServer处理的请求

MutatingWebhookConfiguration是kubernetes的一个官方的资源提供的对象,下面对该对象的字段做一些简单的说明:

结合rules.operations和rules.resources的属性,我们可以知道样例中的MutatingWebhookConfiguration监听了集群中nodes资源的status数据向apiServer提交的更新操作(就是我们前面提到的心跳信息),并且将所有的心跳信息发给了名为webhook-oversale-service的Service下的/mutate接口处理,这个接口就是我们自定义的webhook服务提供的。

上图中的Pod跑着的容器就是我们自定义的webhook服务,一个自定义webhook服务样例供参考

在生产环境中,kubernetes集群的计算节点上运行着许许多多的Pod,分别跑着各种业务容器,我们通常用Deployment、DeamonSet、StatefulSet等资源对象去控制Pod的增删改。因此,开发或运维往往需要配置这些资源对象的Containers字段中业务容器的CPU和内存的资源配额:requests和limit

requests:节点调度pod需要的资源,每次成功调度则将节点的Allocatable属性值(可分配资源)重新计算,
新的Allocatable值 = 旧的Allocatable值 - 设置的requests值
limit:节点中运行pod能够获得的最大资源,当cpu
我们不难发现,当requests字段设置太大的时候,pod实际使用的资源却很小,导致计算节点的Allocatable值很快就被消耗完,节点的资源利用率会变得很低。

上图中最大的蓝色框(allocatable)为计算节点可分配资源,橙色框(requests)为用户配置的requests属性,红色框(current)为业务容器实际使用的资源。因此节点的资源利用率为 current / allocatable。而由于requests设置太大,占满了allocatable,导致新的pod无法被调度到这个节点,就会出现节点实际资源占用很低,却因为allocatable太低导致pod无法调度到该节点的现象。
因此我们能否通过动态调整allocatable的值来让计算节点的可分配资源变得"虚高",骗过k8s的调度器,让它以为该节点可分配资源很大,让尽可能多的pod调度到该节点上呢?

上图通过将allocatable值扩大(fake allcatable),让更多的pod调度到了改节点,节点的资源利用率 current / allocatable 就变大了。

实现资源超卖的关键在于动态修改节点Node对象的allocatable字段值,而我们看到allocatable字段属于Status字段,显然不能直接通过kubectl edit命令来直接修改。因为Status字段和Spec字段不同,Spec是用户设置的期望数据,而Status是实际数据(Node节点通过不断向apiServer发送心跳来更新自己的实时状态,最终存在etcd中)。那么我们要怎么去修改Stauts字段呢?
首先,要修改k8s中任何资源对象的Status值,k8s官方提供了一套RESTful API: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13
可以通过patch或者put方法来调用k8s的RESTful API,实现Stauts字段的修改。(这里是通过ApiServer去修改etcd中保存的Status字段的值)

但是,Node资源对象比较特殊,计算节点会不断给ApiServer发送心跳(默认每隔10s发一次),将带有Status字段的真实信息发送给ApiServer,并更新到etcd中。也就是无论你怎么通过patch/put方法去修改Node的Status字段,计算节点都会定时通过发送心跳将真实的Status数据覆盖你修改的数据,也就是说我们无法通过直接调用RESTful API修改Node对象中的Status数据。

那我们是否可以直接监听这个计算节点的心跳数据,通过修改心跳数据中的Status字段中的allocatable值,从而实现资源超卖呢?

答案是肯定的,k8s在ApiServer中就提供了Admission Controller(准入控制器)的机制,其中包括了MutatingAdmissionWebhook,通过这个webhook,所有和集群中所有和ApiSever交互的请求都被发送到一个指定的接口中,我们只要提供一个这样的接口,就可以获取到Node往ApiServer发送心跳的Staus数据了。然后将这个数据进行我们的自定义修改,再往后传给etcd,就能让etcd以为我们修改过的Status数据就是节点的真实Status,最终实现资源的超卖。

我们都知道,Istio的流量管理、策略、遥测等功能无须应用程序做任何改动,这种无侵入式的方式全部依赖于Sidecar。应用程序发送或者接收的流量都被Sidecar拦截,并由Sidecar进行认证、鉴权、策略执行及遥测数据上报等众多治理功能。

如图所示,在Kubernetes中,Sidecar容器与应用容器共存于同一个Pod中,并且共享同一个Network Namespaces,因此Sidecar容器与应用容器共享同一个网络协议栈,这也是Sidecar能够通过iptables拦截应用进出口流量的根本原因。

Istio的Sidecar模式

在Istio中进行Sidecar注入有两种方式:一种是通过istioctl命令行工具手动注入;另一种是通Istio Sidecar Injector自动注入。

这两种方式的最终目的都是在应用Pod中注入init容器及istio-proxy容器这两个Sidecar容器。如下所示,通过部署Istio的sleep应用,Sidecar是通过sidecar-injector自动注入的,查看注入的Sidecar容器:

Sidecar Injector是Istio中实现自动注入Sidecar的组件,它是以Kubernetes准入控制器Admission Controller的形式运行的。Admission Controller的基本工作原理是拦截Kube-apiserver的请求,在对象持久化之前、认证鉴权之后进行拦截。Admission Controller有两种:一种是内置的,另一种是用户自定义的。Kubernetes允许用户以Webhook的方式自定义准入控制器,Sidecar Injector就是这样一种特殊的MutatingAdmissionWebhook。

如图所示,Sidecar Injector只在创建Pod时进行Sidecar容器注入,在Pod的创建请求到达Kube-apiserver后,首先进行认证鉴权,然后在准入控制阶段,Kube-apiserver以REST的方式同步调用Sidecar Injector Webhook服务进行init与istio-proxy容器的注入,最后将Pod对象持久化存储到etcd中。

Sidecar Injector可以通过MutatingWebhookConfiguration API动态配置生效,Istio中的MutatingWebhook配置如下:

从以上配置可知,Sidecar Injector只对标签匹配“istio-injection: enabled”的命名空间下的Pod资源对象的创建生效。Webhook服务的访问路径为“/inject”,地址及访问凭证等都在clientConfig字段下进行配置。

Istio Sidecar Injector组件是由sidecar-injector进程实现的,本书在之后将二者视为同一概念。Sidecar Injector的实现主要由两部分组成:

MutatingWebhookConfiguration对象的维护主要指监听本地证书的变化及Kubernetes MutatingWebhookConfiguration资源的变化,以检查CA证书或者CA数据是否有更新,并且在本地CA证书与MutatingWebhookConfiguration中的CA证书不一致时,自动更新MutatingWebhookConfiguration对象。

R假设检验之k-s检验(KOLMOGOROV AND SMIRNOV TEST)

R假设检验之k-s检验(KOLMOGOROV AND SMIRNOV TEST)

目录

R假设检验之k-s检验(KOLMOGOROV AND SMIRNOV TEST)

假设检验

假设检验的应用

以上是关于k8s的Mutating webhook的主要内容,如果未能解决你的问题,请参考以下文章

Swift 结构体何时使用 mutating 函数

iOS中 报错:mutating method sent to immutable object

SwiftUI:Cannot use mutating member on immutable value: ‘self‘ is immutable

JavaScript数组方法: 变异方法 (mutation method)和非变异 (non-mutating method)

使用 JDBC、spring 框架和 oracle 时出现 ORA04091-table is mutating 错误

SwiftUI:Cannot use mutating member on immutable value: ‘self‘ is immutable