k8s 基于MutatingWebhookConfiguration实现node超卖和sidecar注入

k8s 基于MutatingWebhookConfiguration实现node超卖和sidecar注入

源码在:https://github.com/Seaiii/MutatingWebhook我写了几个脚本,可以直接运行。

一、MutatingWebhookConfiguration原理

MutatingWebhookConfiguration 是 Kubernetes 中的一种资源对象,用于配置 Mutating Admission Webhook。Mutating Admission Webhook 是一种 Kubernetes 的扩展机制,用于在对象被持久化到 etcd 存储之前,对其进行动态修改或补充。

MutatingWebhookConfiguration 定义了一个或多个 Mutating Admission Webhook 的配置信息,包括 Webhook 的 URL、服务名称、路径等。当 Kubernetes API Server 接收到创建、更新或删除对象的请求时,它将触发适用于该对象类型的 Mutating Admission Webhook。

Mutating Admission Webhook 在对象持久化之前,对对象进行拦截并进行修改或补充。它可以在不改变原始请求的情况下,通过返回修改后的对象副本来实现动态的对象转换。这使得用户能够通过自定义的逻辑对 Kubernetes 对象进行自动化的修改,例如自动注入额外的标签、注解、容器、卷等。

MutatingWebhookConfiguration 的工作原理如下:

创建 MutatingWebhookConfiguration 对象并将其提交到 Kubernetes 集群。这个对象定义了一个或多个 Mutating Admission Webhook 的配置。

Kubernetes API Server 在接收到创建、更新或删除对象的请求时,会检查适用于该对象类型的 Mutating Admission Webhook 配置。

Kubernetes API Server 将请求发送到 Mutating Admission Webhook 的 Webhook URL。

Mutating Admission Webhook 接收到请求后,根据预定义的逻辑对请求中的对象进行修改或补充,并生成修改后的对象副本。

Mutating Admission Webhook 将修改后的对象副本作为响应返回给 Kubernetes API Server。

Kubernetes API Server 使用修改后的对象副本进行后续的持久化操作。

MutatingWebhookConfiguration 和 Mutating Admission Webhook 提供了一种可扩展的方式,允许用户根据自定义的业务需求对 Kubernetes 对象进行自动化修改。这在实践中被广泛应用于诸如自动注入 sidecar、自动配置密钥等场景中。
在这里插入图片描述

二、超卖/sidecar思路

1.场景
超卖的场景可以很容易避免。只要设置了resource最低和适当的limits,就可以避免超卖。但是有种场景就是用户不知道这个值,本来1M内存使用量,但是设置了resource为3M。这样就导致pod占用了3M的内存,然而有2M是闲置状态。这时候就可以使用动态超卖来把那浪费的2M内存使用出来
2.思路
节点Node的Status种有两个字段,分别是Allocatable(可分配)和Capacity(总量)结构体。实现资源超卖的关键在于动态修改节点Node对象的allocatable字段值。如果使用clinet-go动态的修改这个字段,是无法实现的。因为修改后只是短暂的,Node资源对象比较特殊,计算节点会不断给ApiServer发送心跳(默认每隔10s发一次),将带有Status字段的真实信息发送给ApiServer,并更新到etcd中。也就是无论你怎么通过patch/put方法去修改Node的Status字段,计算节点都会定时通过发送心跳将真实的Status数据覆盖你修改的数据,也就是说我们无法通过直接调用RESTful API修改Node对象中的Status数据。所以这时候需要引入MutatingWebhookConfiguration资源对象,在apiserver发送给etcd之前,会先发送给MutatingWebhookConfiguration。然后通过我们注册的回调函数,来修改status,在发送给etcd,骗过etcd。

三、实现MutatingWebhookConfiguration

可以简单介绍下MutatingWebhookConfiguration流程步骤
流程步骤介绍:我们需要创建service、MutatingWebhookConfiguration、deployment来实现流程。当apiserver发起心跳后,在MutatingWebhookConfiguration中rule注册的规则中会触发。然后通过MutatingWebhookConfiguration中的service触发到我们的service,通过service转发到deployment的pod,然后实现回调。

这三个yaml在github中都有存在。

1.需要修改api-server的配置。如果是kubeadm安装的,可以如下修改

vi /etc/kubernetes/manifests/kube-apiserver.yaml 

修改以下配置开启MutatingAdmissionWebhook。
- --enable-admission-plugins=NodeRestriction,MutatingAdmissionWebhook,ValidatingAdmissionWebhook

2.配置签名证书
github中的cfssl.sh已经帮助生产证书(要修改以下你的apiserver的ca位置)

#生成key,用k8s的ca证书进行签名,注意:-ca和-ca-key=的目录是你k8s的master主机存放CA文件的位置

cfssl gencert -ca=/etc/kubernetes/pki/ca.crt -ca-key=/etc/kubernetes/pki/ca.key -config=ca-config.json -hostname=webhook.default.svc -profile=server server-csr.json | cfssljson -bare server

生成证书后需要生成secret资源,后续deployment需要挂载这个secret

kubectl create secret tls admission-registry-tls  --key=server-key.pem --cert=server.pem

3.生成必要的三个yaml
github中的statr.sh脚本中可以快速运行pod并触发node更新操作。(要修改以下你本机的deployment位置)
MutatingWebhookConfiguration.yaml

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: demo-webhook
webhooks:
  - sideEffects: None
    admissionReviewVersions:
      - v1
      - v1beta1
    name: webhook.default.svc
    clientConfig:
      service:
        name: webhook#你的server服务的名字
        namespace: default
        path: "/webhook"
      caBundle: #这个是你的k8s集群的的ca证书base64加密后的值。可以使用“kubectl config view --raw --minify --flatten -o jsonpath='{.clusters[].cluster.certificate-authority-data}'”获取
    rules:
      - operations: [ "UPDATE" ]
        apiGroups: [ "*" ]
        apiVersions: [ "v1" ]
        resources: [ "nodes/status"]

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webhook-example-deployment
  labels:
    app: webhook-example
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webhook-example
  template:
    metadata:
      labels:
        app: webhook-example
    spec:
      nodeName: k8s-master
      containers:
        - name: webhook-example
          image: webhook-example:20230517-144113
          command: [ "/node" ]
          ports:
            - containerPort: 8443
              name: webhook-api
          args:
            - -v=4
            - -log_dir=log -alsologtostderr
          volumeMounts:
            - name: webhook-certs
              mountPath: /etc/webhook/certs
              readOnly: true
            - name: kubeconfig
              mountPath: /etc/
      volumes:
        - name: webhook-certs #这个是上面生成的secret
          secret:
            secretName: admission-registry-tls
        - name: kubeconfig
          hostPath:
              path: /root/.kube/ #这个要改成你本地的kubeconfig的位置,用于client-go的客户端连接
              type: Directory


service.yaml

apiVersion: v1
kind: Service
metadata:
  name: webhook
  labels:
    app: admission-webhook-example
spec:
  ports:
    - port: 443
      targetPort: webhook-api
  selector:
    app: webhook-example

执行github中的start.sh可以一步生成,或者你可以根据里面的步骤手动生成,我都做了注释。
**注:**我们需要获得node的实际使用量,所以需要Metrics,需要跑起来这个pod,后续的代码中才可以使用这个Metrics客户端。百度下载components.yaml执行即可了(可以百度获取很多)。
在这里插入图片描述

四、代码实现

1.代码的逻辑很简单,创建server接受https请求,需要tls校验证书。

cert, err := tls.LoadX509KeyPair("/etc/webhook/certs/tls.crt", "/etc/webhook/certs/tls.key")
	if err != nil {
		glog.Errorf("get cert fail.err is :", err)
		panic(err)
	}

	// Creating a TLS Configuration
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
	// Create an HTTP server
	server := &http.Server{
		Addr:      ":8443",
		TLSConfig: tlsConfig,
	}

	// start services
	http.Handle("/webhook", New(&applyNode{}))
	client.NewClientK8s()
	if err := server.ListenAndServeTLS("", ""); err != nil {
		glog.Errorf("server start fail,err is:", err)
		panic(err)
	}

2.证书校验成功后,将收到apiserver发过来的消息,对接受消息进行校验,并拿到Node.Status.Capacity的值和MetricsApi的值

	//...省略
	node := corev1.Node{}
	obj, _, err := Codecs.UniversalDecoder().Decode(admissionReviewReq.Request.Object.Raw, nil, &node)
	//...省略
    if _, ok := obj.(*corev1.Node); ok {
		bytes, err = nodePatch(admissionReviewReq, node)
	}

3.拿到我们该有的数据后,做校验和自己的业务就可以了。
全部代码在github中。感兴趣的可以给个stat

五、sidecar注入pod
代码中并没有介绍sidecar模式,其实看到这里相信也都明白原理了,只要在MutatingWebhookConfiguration.yaml中的resources中加入“pods”,operations加入“CREATE”即可。这样当pod有创建时候,就会调用MutatingWebhookConfiguration的回调。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值