前言
上一小节我们详细讨论了如何做流量劫持,并且使用initContainers来做自动劫持的配置。但是目前还有一个问题,如果我们的系统有好几百个微服务,那作为重要的代理envoy,是手动注入的,难道每个微服务都要手动编辑一次 ?这显然是不可承受的,所以这一节,我们来详细讨论一下自动注入的问题
环境准备
由于本节只讨论容器注入,所以只需要准备一个普通的deployment就行了- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: backend
- namespace: default
- spec:
- replicas: 1
- selector:
- matchLabels:
- app: backend
- template:
- metadata:
- labels:
- app: backend
- spec:
- containers:
- - image: backend-service:v1
- imagePullPolicy: Never
- name: backend
- ports:
- - containerPort: 10000
- protocol: TCP
- resources: {}
- restartPolicy: Always
复制代码 mutating admission webhooks
简单来说,就是当pod重启的时候,会发起一系列的过程,其中在mutating admission controller 这里,k8s提供了一个webhooks,可以回调到指定的地方去,所以我们需要创建一个server来处理该回调,添加一个容器进去,完成容器注入的工作
创建相关证书
创建openssl.cnf- [ req ]
- distinguished_name = req_distinguished_name
- req_extensions = v3_req
- prompt = no
- [ req_distinguished_name ]
- CN = sidecar-webhook.default.svc
- [ v3_req ]
- keyUsage = keyEncipherment, dataEncipherment
- extendedKeyUsage = serverAuth
- subjectAltName = @alt_names
- [ alt_names ]
- DNS.1 = sidecar-webhook
- DNS.2 = sidecar-webhook.default
- DNS.3 = sidecar-webhook.default.svc
复制代码 从k8s根证书中创建证书- sudo openssl req -x509 -newkey rsa:2048 \
- -keyout tls.key \
- -out tls.crt \
- -days 365 -nodes \
- -config openssl.cnf \
- -extensions v3_req
复制代码 创建MutatingWebhookConfiguration
- mytls=`cat tls.crt | base64 | tr -d '\n'`
- echo 'apiVersion: admissionregistration.k8s.io/v1
- kind: MutatingWebhookConfiguration
- metadata:
- name: sidecar-injector
- webhooks:
- - name: sidecar.demo.io
- clientConfig:
- service:
- name: sidecar-webhook
- namespace: default
- path: /mutate
- caBundle: '$mytls'
- rules:
- - apiGroups: [""]
- apiVersions: ["v1"]
- operations: ["CREATE"]
- resources: ["pods"]
- admissionReviewVersions: ["v1"]
- sideEffects: None' | kubectl apply -f -
复制代码 创建服务来接收webhook
自动注入服务
这没什么可说的,需要注意的就是注入pod的配置直接写在了代码里面,并且注入了2个部分,首先是sidecar container,其次是sidecar的volumes配置(pod级别的)- patch := []map[string]interface{}{
- {
- "op": "add",
- "path": "/spec/containers/-",
- "value": map[string]interface{}{
- "image": "registry.cn-beijing.aliyuncs.com/wilsonchai/envoy:v1.32-latest",
- "imagePullPolicy": "IfNotPresent",
- "name": "envoy",
- "args": []string{"-c", "/etc/envoy/envoy.yaml"},
- "volumeMounts": []map[string]interface{}{
- {
- "mountPath": "/etc/envoy",
- "name": "envoy-config",
- },
- },
- },
- },
- {
- "op": "add",
- "path": "/spec/volumes/-",
- "value": map[string]interface{}{
- "configMap": map[string]interface{}{
- "defaultMode": 420,
- "name": "envoy-config",
- },
- "name": "envoy-config",
- },
- },
- }
复制代码- ▶ go run inject.go
- 2025/12/29 14:58:19 Webhook listening on :8443
复制代码 打开8443端口以便接收请求
创建访问路径
我们的服务在集群外,所以创建一个endpoint指向集群之外- echo 'apiVersion: v1
- kind: Service
- metadata:
- name: sidecar-webhook
- spec:
- ports:
- - port: 443
- targetPort: 8443
- protocol: TCP
- type: ClusterIP
- ---
- apiVersion: v1
- kind: Endpoints
- metadata:
- name: sidecar-webhook
- namespace: default
- subsets:
- - addresses:
- - ip: 10.22.12.178
- ports:
- - port: 8443
- protocol: TCP' | kubectl apply -f -
复制代码 验证
重启backend服务,kubectl rollout restart deploy backend- cannot bind '0.0.0.0:10000': Address already in use
复制代码 出现了报错,这应该是由于envoy是监听10000端口,backend服务监听的也是10000端口,现在它们在一个net namespace,就肯定要报错了,所以改一下envoy的配置,监听另外一个端口吧,10000改成10001- listeners:
- - name: ingress_listener
- address:
- socket_address:
- address: 0.0.0.0
- port_value: 10001
复制代码 再次重启查看pod状态- ▶ kubectl get pod -owide -l app=backend
- NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
- backend-6bdf5d484b-5czgx 2/2 Running 0 100s 10.244.0.184 wilson <none> <none>
复制代码 查看详情
自动注入了envoy容器
至此,架构图如下:
精细化注入
按照目前的配置,只要有pod create,就立刻回调集群外的注入服务,如果k8s集群的服务很多,并且频繁的create/destroy,那就会对注入服务产生较大的压力。如果在这些服务中,只有一些服务是需要使用自动注入功能的,那 就需要更精细化的注入管理
namespace打标签
首先要调整一下MutatingWebhookConfiguration- apiVersion: admissionregistration.k8s.io/v1
- kind: MutatingWebhookConfiguration
- metadata:
- name: sidecar-injector
- webhooks:
- - name: sidecar.demo.io
- namespaceSelector:
- matchLabels:
- sidecar-inject: "true"
- ...
复制代码 加上标签 sidecar-inject: "true",只有满足这个标签,才会回调到外部的注入服务,这样就可以大大减轻注入服务的压力了
再给namespace打上标签- kubectl label ns default sidecar-inject=true
复制代码 default namespace里面所有的pod,都会回调至外部注入服务
pod 打标签
这次不在namespace下,而是基于某个pod label- apiVersion: admissionregistration.k8s.io/v1
- kind: MutatingWebhookConfiguration
- metadata:
- name: sidecar-injector
- webhooks:
- - name: sidecar.demo.io
- objectSelector:
- matchLabels:
- sidecar-inject-pod: "true"
- ...
复制代码 然后再给deployment打标签,这里要注意打的是pod的标签- kubectl patch deployment backend \
- --type='merge' \
- -p '{
- "spec": {
- "template": {
- "metadata": {
- "labels": {
- "sidecar-inject-pod": "true"
- }
- }
- }
- }
- }'
复制代码 小结
本文详细描述了怎么做自动注入:k8s配置修改+外部注入服务。其中需要注入的pod是写死在注入服务的,这部分可以抽出来,将配置写成configmap,或者在其他的配置中心中,这样就不用频繁的修改注入服务了
另外mutating webhooks可以拦截大部分k8s支持的资源,并且发送到所配置的外部服务中进行需要的配置,这就不单单是pod自动注入,而是资源拦截。比如我需要拦截configmap- echo 'apiVersion: admissionregistration.k8s.io/v1
- kind: MutatingWebhookConfiguration
- metadata:
- name: callback-configmap
- webhooks:
- - name: sidecar.demo.io
- clientConfig:
- service:
- name: sidecar-webhook
- namespace: default
- path: /mutate
- caBundle: '$mytls'
- rules:
- - apiGroups: [""]
- apiVersions: ["v1"]
- operations: ["CREATE", "UPDATE"]
- resources: ["configmaps"]
- admissionReviewVersions: ["v1"]
- sideEffects: None' | kubectl apply -f -
复制代码 resources变更为configmap之后,就可以直接回调到外部服务。本章由于篇幅有限,就不对这个话题展开了,这个以后有需要再来详细讨论
联系我
至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |