istio注入sidecar源码解析

上文主要讲解了如何部署istio,有一项是自动注入sidecar,本文主要解析一下sidecar的自动注入源码

原理:istio通过kubernetes的MutatingAdmissionWebhook来实现自动注入,当启用了该准入控制器以后,会在符合配置条件的namespace下的pod创建之前访问对应的服务来将sidecar注入进去,接着继续部署pod。

先来解释一下istio官方给出的MutatingAdmissionWebhook配置的yaml文件:

 1 apiVersion: admissionregistration.k8s.io/v1beta1
 2 kind: MutatingWebhookConfiguration
 3 metadata:
 4   labels:
 5     app: sidecarInjectorWebhook
 6     chart: sidecarInjectorWebhook
 7     heritage: Tiller
 8     release: istio
 9   name: istio-sidecar-injector
10 webhooks:
11 - clientConfig:
12     caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMzVENDQWNXZ0F3SUJBZ0lRSzFyZGRWOFl3T2hORHFjOWZzL2tmREFOQmdrcWhraUc5dzBCQVFzRkFEQVkKTVJZd0ZBWURWUVFLRXcxamJIVnpkR1Z5TG14dlkyRnNNQjRYRFRFNU1EVXdPVEUxTXpFME5Gb1hEVEl3TURVdwpPREUxTXpFME5Gb3dHREVXTUJRR0ExVUVDaE1OWTJ4MWMzUmxjaTVzYjJOaGJEQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFMMTZYWFZROTQ5S0p1RVBkZS9wSyt2Ulp0eWlIbnZxNkhHYzk3L3YKVUI4TStsUks2d25rRmlyeGplb0ZWYXZWRHVVbjJudkc4RTRXV2RjcHN3VmpPUmZDYnJoWmZDdEQ1QmtUYmUyZQo5eSs4a1A3bTRUNDAzNFBWUTdDclFoOUt1eE03MktYOGhwS3lvSGVqOWRXTDljcUo4S3JabmhlMHhQa0hwT205CmNFN3UzRVIzcVV0L0ZiVENBbCt5eVJUYVpKRW9keGJ5STBKcnpoVTdpeTlSQklweWxnUTU5Z0loZng3UFVsU0IKR2ljVTRPMmV2Z3BPanJMMEd2SmZGdlVFaUtiVWtvSi9yckZUMEx4L2kvQlh4ZlRtZmNmUURjQm5SeWp4blJPYgpWSTNCWkp5VU52ZVpPbDVoVys0UFhLVE4wRHQ4ZGo5SHJSRDJpRzJSN01iNTg4RUNBd0VBQWFNak1DRXdEZ1lEClZSMFBBUUgvQkFRREFnSUVNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUIKQUF0bVdRY3RFZjlBK1pLUnVsdTQraDVEWnp3Z2xEeHA0SWM3ZkxBMCtyWkFkZzU4emJUNDk3b0RVMjh4a3o2cQoxY09kVXRzKzM2aDBNUG43aEEwQzJoa1BxTmswekxpTlpSbmVMWTBMMC8yQjF6V2FEbUlPdkk4VEFqNWM1UEIrCkxubmhGRm1aK01jVGdZNGJDVk8rcVdGVklsa3Vya2ZjMEVJZFZ5S0tsRVJUNUltMHl4RmQwVG5vSldzT1FGNlcKV3JQVTJxTEJBUllpcU00MjlUMXhDNStVaG1zMndwNTI2RDBGbHdLNVFDWExOYkRkSi9sZTZvbXMvNlBSR0EvUAo1dHF3VHFpUlpYN0JhZ0xOaVhRT0lDOVU1Mi96UFYrTDYrQnQydDc0Sml6cGoyWUhWRDdoYlNvNWVndHJuM2lrClZHblFrd1BYSjZWWXQyalpiL1EwQUdFPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
13     service:
14       name: istio-sidecar-injector
15       namespace: istio-system
16       path: /inject
17   failurePolicy: Fail
18   name: sidecar-injector.istio.io
19   namespaceSelector:
20     matchLabels:
21       istio-injection: enabled
22   rules:
23   - apiGroups:
24     - ""
25     apiVersions:
26     - v1
27     operations:
28     - CREATE
29     resources:
30     - pods

上述yaml文件中主要讲解几点。

caBundle:注意 API server 调用 Webhook 时一定是通过 TLS 认证的,所以 MutatingWebhookConfiguration 中一定要配置 caBundle。

failurePolicy :如果 Webhook Admission Server 无法连接时如何处理。有两个选项分别是 “Ignore”(故障时开放) 和 “Fail”(故障时关闭)。“故障时开放”可能会导致无法预测的行为。

service:是需要访问的服务地址,通常跟我们部署的服务绑定。然后让service指向该地址,可以配置集群内也可以配置集群外。path就是需要访问的path

namespaceSelector:即选择符合匹配规则的namespace。上述为label中有istio-injection: enabled的namespace

rules:apiGroups对应任意,apiVersions是v1,当对pod资源做创建操作时,触发该hook。

接下来讲解一下sidecar-injector的源码。源码入口在istio/pilot/cmd/sidecar-injector/main.go。

istio的命令行主要使用golang的cobra工具生成,如有不懂,可先行学习该工具的资料。

主要看下面代码,

该代码获取到命令行传入的参数,并调用NewWebhook方法创建一个webhook。

 1     wh := &Webhook{
 2         server: &http.Server{
 3             Addr: fmt.Sprintf(":%v", p.Port),
 4         },
 5         sidecarConfig:          sidecarConfig,
 6         sidecarTemplateVersion: sidecarTemplateVersionHash(sidecarConfig.Template),
 7         meshConfig:             meshConfig,
 8         configFile:             p.ConfigFile,
 9         valuesFile:             p.ValuesFile,
10         valuesConfig:           valuesConfig,
11         meshFile:               p.MeshFile,
12         watcher:                watcher,
13         healthCheckInterval:    p.HealthCheckInterval,
14         healthCheckFile:        p.HealthCheckFile,
15         certFile:               p.CertFile,
16         keyFile:                p.KeyFile,
17         cert:                   &pair,
18     }
19     
20     wh.server.TLSConfig = &tls.Config{GetCertificate: wh.getCert}
21     h := http.NewServeMux()
22     h.HandleFunc("/inject", wh.serveInject)
23     wh.server.Handler = h

上面的代码主要就是配置webhook然后创建了一个httpServer,来监听/inject

解析来就要看当访问/inject时发生了什么。查看wh.serveInject的代码:

1 ar := v1beta1.AdmissionReview{}
2 if _, _, err := deserializer.Decode(body, nil, &ar); err != nil {
3     log.Errorf("Could not decode body: %v", err)
4     reviewResponse = toAdmissionResponse(err)
5 } else {
6     reviewResponse = wh.inject(&ar)
7 }

上面代码主要就是进行判断hook传来的数据是否能够解析成AdmissionReview,然后进行注入。

接下来查看wh.inject(&ar)的代码:

 1  req := ar.Request
 2  var pod corev1.Pod
 3  //将hook传入的参数解析成pod
 4  if err := json.Unmarshal(req.Object.Raw, &pod); err != nil {
 5     log.Errorf("Could not unmarshal raw object: %v %s", err,
 6         string(req.Object.Raw))
 7     return toAdmissionResponse(err)
 8  }
 9 
10  //配置pod的SecurityContext使用1337的FSGroup。因为sidecar是使用RunAsUser: 1337,如果配置,则无法访问volume
11  if wh.meshConfig.EnableSdsTokenMount && wh.meshConfig.SdsUdsPath != "" {
12          var grp = int64(1337)
13          pod.Spec.SecurityContext = &corev1.PodSecurityContext{
14              FSGroup: &grp,
15          }
16      }
17  //返回需要注入的内容
18  spec, status, err := InjectionData(wh.sidecarConfig.Template, wh.valuesConfig, wh.sidecarTemplateVersion, &pod.ObjectMeta, &pod.Spec, &pod.ObjectMeta, wh.meshConfig.DefaultConfig, wh.meshConfig)
19  //创建jsonpatch,包含对pod的所有修改操作。
20  patchBytes, err := createPatch(&pod, injectionStatus(&pod), annotations, spec)
21  //返回给hook的数据。
22  reviewResponse := v1beta1.AdmissionResponse{
23    Allowed: true,
24    Patch:   patchBytes,
25    PatchType: func() *v1beta1.PatchType {
26       pt := v1beta1.PatchTypeJSONPatch
27       return &pt
28    }(),
29  }

上述代码主要涉及到kubernetes中的patch操作时使用的jsonpatch。可以自行查询资料,比较简单。

猜你喜欢

转载自www.cnblogs.com/cedarwood/p/10841946.html