上文主要讲解了如何部署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。可以自行查询资料,比较简单。
来源:https://www.cnblogs.com/cedarwood/p/10841946.html