sidecar 注入原理
func (s *Server) initSidecarInjector(args *PilotArgs) (*inject.Webhook, error) {
// 当前常量: "./var/lib/istio/inject"
injectPath := args.InjectionOptions.InjectionDirectory
if injectPath == "" || !injectionEnabled.Get() {
log.Infof("Skipping sidecar injector, injection path is missing or disabled.")
return nil, nil
}
// 本地或者远程配置存在将启动注入
var watcher inject.Watcher
// 查看本地是否有配置
if _, err := os.Stat(filepath.Join(injectPath, "config")); !os.IsNotExist(err) {
configFile := filepath.Join(injectPath, "config")
valuesFile := filepath.Join(injectPath, "values")
watcher, err = inject.NewFileWatcher(configFile, valuesFile)
if err != nil {
return nil, err
}
} else {
//访问configmap,常量istio-sidecar-injector
configMapName := getInjectorConfigMapName(args.Revision)
cms := s.kubeClient.CoreV1().ConfigMaps(args.Namespace)
if _, err := cms.Get(context.TODO(), configMapName, metav1.GetOptions{}); err != nil {
if errors.IsNotFound(err) {
log.Infof("Skipping sidecar injector, template not found")
return nil, nil
}
return nil, err
}
watcher = inject.NewConfigMapWatcher(s.kubeClient, args.Namespace, configMapName, "config", "values")
}
log.Info("initializing sidecar injector")
parameters := inject.WebhookParameters{
Watcher: watcher,
Env: s.environment,
// Disable monitoring. The injection metrics will be picked up by Pilots metrics exporter already
MonitoringPort: -1,
Mux: s.httpsMux,
Revision: args.Revision,
}
wh, err := inject.NewWebhook(parameters)
if err != nil {
return nil, fmt.Errorf("failed to create injection webhook: %v", err)
}
// Patch cert if a webhook config name is provided.
// This requires RBAC permissions - a low-priv Istiod should not attempt to patch but rely on
// operator or CI/CD
if features.InjectionWebhookConfigName.Get() != "" {
s.addStartFunc(func(stop <-chan struct{}) error {
// No leader election - different istiod revisions will patch their own cert.
caBundlePath := s.caBundlePath
if hasCustomTLSCerts(args.ServerOptions.TLSOptions) {
caBundlePath = args.ServerOptions.TLSOptions.CaCertFile
}
webhooks.PatchCertLoop(features.InjectionWebhookConfigName.Get(), webhookName, caBundlePath, s.kubeClient, stop)
return nil
})
}
s.addStartFunc(func(stop <-chan struct{}) error {
go wh.Run(stop)
return nil
})
return wh, nil
}
func NewWebhook(p WebhookParameters) (*Webhook, error) {
...
//具体的处理器
p.Mux.HandleFunc("/inject", wh.serveInject)
p.Mux.HandleFunc("/inject/", wh.serveInject)
p.Env.Watcher.AddMeshHandler(func() {
wh.mu.Lock()
wh.meshConfig = p.Env.Mesh()
wh.mu.Unlock()
})
...
}
func (wh *Webhook) serveInject(w http.ResponseWriter, r *http.Request) {
totalInjections.Increment()
...
var reviewResponse *kube.AdmissionResponse
var obj runtime.Object
var ar *kube.AdmissionReview
// webhook传入admissionreview,获取admissionrequest 写入admissionresponse
if out, _, err := deserializer.Decode(body, nil, obj); err != nil {
handleError(fmt.Sprintf("Could not decode body: %v", err))
//返回error信息
reviewResponse = toAdmissionResponse(err)
} else {
log.Debugf("AdmissionRequest for path=%s\n", path)
ar, err = kube.AdmissionReviewKubeToAdapter(out)
if err != nil {
handleError(fmt.Sprintf("Could not decode object: %v", err))
}
//注入
reviewResponse = wh.inject(ar, path)
}
response := kube.AdmissionReview{}
response.Response = reviewResponse
var responseKube runtime.Object
var apiVersion string
if ar != nil {
apiVersion = ar.APIVersion
response.TypeMeta = ar.TypeMeta
if response.Response != nil {
if ar.Request != nil {
response.Response.UID = ar.Request.UID
}
}
}
//根据版本返回信息
responseKube = kube.AdmissionReviewAdapterToKube(&response, apiVersion)
resp, err := json.Marshal(responseKube)
if err != nil {
log.Errorf("Could not encode response: %v", err)
http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
}
if _, err := w.Write(resp); err != nil {
log.Errorf("Could not write response: %v", err)
http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
}
}
```go func (wh Webhook) inject(ar kube.AdmissionReview, path string) *kube.AdmissionResponse { ... // 生成patch patchBytes, err := injectPod(params) if err != nil { handleError(fmt.Sprintf("Pod injection failed: %v", err)) return toAdmissionResponse(err) }
// 返回resp AdmissionResponse
reviewResponse := kube.AdmissionResponse{
Allowed: true,
Patch: patchBytes,
PatchType: func() *string {
pt := "JSONPatch"
return &pt
}(),
}
totalSuccessfulInjections.Increment()
return &reviewResponse
}
Last updated