上文主要讲解了如何部署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