找回密码
 立即注册
首页 业界区 业界 从手动到自动:基于 Mutating Admission Webhook 实现 E ...

从手动到自动:基于 Mutating Admission Webhook 实现 Envoy Sidecar 自动注入

命煦砌 3 天前
前言

上一小节我们详细讨论了如何做流量劫持,并且使用initContainers来做自动劫持的配置。但是目前还有一个问题,如果我们的系统有好几百个微服务,那作为重要的代理envoy,是手动注入的,难道每个微服务都要手动编辑一次 ?这显然是不可承受的,所以这一节,我们来详细讨论一下自动注入的问题
环境准备

由于本节只讨论容器注入,所以只需要准备一个普通的deployment就行了
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4.   name: backend
  5.   namespace: default
  6. spec:
  7.   replicas: 1
  8.   selector:
  9.     matchLabels:
  10.       app: backend
  11.   template:
  12.     metadata:
  13.       labels:
  14.         app: backend
  15.     spec:
  16.       containers:
  17.       - image: backend-service:v1
  18.         imagePullPolicy: Never
  19.         name: backend
  20.         ports:
  21.         - containerPort: 10000
  22.           protocol: TCP
  23.         resources: {}
  24.       restartPolicy: Always
复制代码
mutating admission webhooks

1.png

简单来说,就是当pod重启的时候,会发起一系列的过程,其中在mutating admission controller 这里,k8s提供了一个webhooks,可以回调到指定的地方去,所以我们需要创建一个server来处理该回调,添加一个容器进去,完成容器注入的工作
创建相关证书
  1. cd /etc/kubernetes/pki
复制代码
创建openssl.cnf
  1. [ req ]
  2. distinguished_name = req_distinguished_name
  3. req_extensions = v3_req
  4. prompt = no
  5. [ req_distinguished_name ]
  6. CN = sidecar-webhook.default.svc
  7. [ v3_req ]
  8. keyUsage = keyEncipherment, dataEncipherment
  9. extendedKeyUsage = serverAuth
  10. subjectAltName = @alt_names
  11. [ alt_names ]
  12. DNS.1 = sidecar-webhook
  13. DNS.2 = sidecar-webhook.default
  14. DNS.3 = sidecar-webhook.default.svc
复制代码
从k8s根证书中创建证书
  1. sudo openssl req -x509 -newkey rsa:2048 \
  2.   -keyout tls.key \
  3.   -out tls.crt \
  4.   -days 365 -nodes \
  5.   -config openssl.cnf \
  6.   -extensions v3_req
复制代码
创建MutatingWebhookConfiguration
  1. mytls=`cat tls.crt | base64 | tr -d '\n'`
  2. echo 'apiVersion: admissionregistration.k8s.io/v1
  3. kind: MutatingWebhookConfiguration
  4. metadata:
  5.   name: sidecar-injector
  6. webhooks:
  7. - name: sidecar.demo.io
  8.   clientConfig:
  9.     service:
  10.       name: sidecar-webhook
  11.       namespace: default
  12.       path: /mutate
  13.     caBundle: '$mytls'
  14.   rules:
  15.   - apiGroups: [""]
  16.     apiVersions: ["v1"]
  17.     operations: ["CREATE"]
  18.     resources: ["pods"]
  19.   admissionReviewVersions: ["v1"]
  20.   sideEffects: None' | kubectl apply -f -
复制代码
创建服务来接收webhook

自动注入服务
这没什么可说的,需要注意的就是注入pod的配置直接写在了代码里面,并且注入了2个部分,首先是sidecar container,其次是sidecar的volumes配置(pod级别的)
  1.         patch := []map[string]interface{}{
  2.                 {
  3.                         "op":   "add",
  4.                         "path": "/spec/containers/-",
  5.                         "value": map[string]interface{}{
  6.                                 "image":           "registry.cn-beijing.aliyuncs.com/wilsonchai/envoy:v1.32-latest",
  7.                                 "imagePullPolicy": "IfNotPresent",
  8.                                 "name":            "envoy",
  9.                                 "args":            []string{"-c", "/etc/envoy/envoy.yaml"},
  10.                                 "volumeMounts": []map[string]interface{}{
  11.                                         {
  12.                                                 "mountPath": "/etc/envoy",
  13.                                                 "name":      "envoy-config",
  14.                                         },
  15.                                 },
  16.                         },
  17.                 },
  18.                 {
  19.                         "op":   "add",
  20.                         "path": "/spec/volumes/-",
  21.                         "value": map[string]interface{}{
  22.                                 "configMap": map[string]interface{}{
  23.                                         "defaultMode": 420,
  24.                                         "name":        "envoy-config",
  25.                                 },
  26.                                 "name": "envoy-config",
  27.                         },
  28.                 },
  29.         }
复制代码
  1. ▶ go run inject.go
  2. 2025/12/29 14:58:19 Webhook listening on :8443
复制代码
打开8443端口以便接收请求
创建访问路径

我们的服务在集群外,所以创建一个endpoint指向集群之外
  1. echo 'apiVersion: v1
  2. kind: Service
  3. metadata:
  4.   name: sidecar-webhook
  5. spec:
  6.   ports:
  7.   - port: 443
  8.     targetPort: 8443
  9.     protocol: TCP
  10.   type: ClusterIP
  11. ---
  12. apiVersion: v1
  13. kind: Endpoints
  14. metadata:
  15.   name: sidecar-webhook
  16.   namespace: default
  17. subsets:
  18. - addresses:
  19.   - ip: 10.22.12.178
  20.   ports:
  21.   - port: 8443
  22.     protocol: TCP' | kubectl apply -f -
复制代码
验证

重启backend服务,kubectl rollout restart deploy backend
  1. cannot bind '0.0.0.0:10000': Address already in use
复制代码
出现了报错,这应该是由于envoy是监听10000端口,backend服务监听的也是10000端口,现在它们在一个net namespace,就肯定要报错了,所以改一下envoy的配置,监听另外一个端口吧,10000改成10001
  1.       listeners:
  2.         - name: ingress_listener
  3.           address:
  4.             socket_address:
  5.               address: 0.0.0.0
  6.               port_value: 10001
复制代码
再次重启查看pod状态
  1. ▶ kubectl get pod -owide -l app=backend
  2. NAME                       READY   STATUS    RESTARTS   AGE    IP             NODE     NOMINATED NODE   READINESS GATES
  3. backend-6bdf5d484b-5czgx   2/2     Running   0          100s   10.244.0.184   wilson   <none>           <none>
复制代码
查看详情
2.png

自动注入了envoy容器
至此,架构图如下:
3.png

精细化注入

按照目前的配置,只要有pod create,就立刻回调集群外的注入服务,如果k8s集群的服务很多,并且频繁的create/destroy,那就会对注入服务产生较大的压力。如果在这些服务中,只有一些服务是需要使用自动注入功能的,那 就需要更精细化的注入管理
namespace打标签

首先要调整一下MutatingWebhookConfiguration
  1. apiVersion: admissionregistration.k8s.io/v1
  2. kind: MutatingWebhookConfiguration
  3. metadata:
  4.   name: sidecar-injector
  5. webhooks:
  6. - name: sidecar.demo.io
  7.   namespaceSelector:
  8.     matchLabels:
  9.       sidecar-inject: "true"
  10. ...
复制代码
加上标签 sidecar-inject: "true",只有满足这个标签,才会回调到外部的注入服务,这样就可以大大减轻注入服务的压力了
再给namespace打上标签
  1. kubectl label ns default sidecar-inject=true
复制代码
default namespace里面所有的pod,都会回调至外部注入服务
pod 打标签

这次不在namespace下,而是基于某个pod label
  1. apiVersion: admissionregistration.k8s.io/v1
  2. kind: MutatingWebhookConfiguration
  3. metadata:
  4.   name: sidecar-injector
  5. webhooks:
  6. - name: sidecar.demo.io
  7.   objectSelector:
  8.     matchLabels:
  9.       sidecar-inject-pod: "true"
  10. ...
复制代码
然后再给deployment打标签,这里要注意打的是pod的标签
  1. kubectl patch deployment backend \
  2.   --type='merge' \
  3.   -p '{
  4.     "spec": {
  5.       "template": {
  6.         "metadata": {
  7.           "labels": {
  8.             "sidecar-inject-pod": "true"
  9.           }
  10.         }
  11.       }
  12.     }
  13.   }'
复制代码
小结

本文详细描述了怎么做自动注入:k8s配置修改+外部注入服务。其中需要注入的pod是写死在注入服务的,这部分可以抽出来,将配置写成configmap,或者在其他的配置中心中,这样就不用频繁的修改注入服务了
另外mutating webhooks可以拦截大部分k8s支持的资源,并且发送到所配置的外部服务中进行需要的配置,这就不单单是pod自动注入,而是资源拦截。比如我需要拦截configmap
  1. echo 'apiVersion: admissionregistration.k8s.io/v1
  2. kind: MutatingWebhookConfiguration
  3. metadata:
  4.   name: callback-configmap
  5. webhooks:
  6. - name: sidecar.demo.io
  7.   clientConfig:
  8.     service:
  9.       name: sidecar-webhook
  10.       namespace: default
  11.       path: /mutate
  12.     caBundle: '$mytls'
  13.   rules:
  14.   - apiGroups: [""]
  15.     apiVersions: ["v1"]
  16.     operations: ["CREATE", "UPDATE"]
  17.     resources: ["configmaps"]
  18.   admissionReviewVersions: ["v1"]
  19.   sideEffects: None' | kubectl apply -f -
复制代码
resources变更为configmap之后,就可以直接回调到外部服务。本章由于篇幅有限,就不对这个话题展开了,这个以后有需要再来详细讨论
联系我


  • 联系我,做深入的交流
4.bmp

至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册