Skywalking Swck Agent注入实现分析( 四 )

  1. 第四个执行的是OverlayAgent
// OverlayAgent overlays the agent by getting the pod's annotations// If the agent overlay option is not set, go directly to the next step// If set the wrong value in the annotation , inject the error info and returnfunc (oa *OverlayAgent) execute(ipd *InjectProcessData) admission.Response {log.Info("=============== OverlayAgent ================")if !ipd.injectFileds.OverlayAgent(*ipd.annotation, ipd.annotationOverlay, &ipd.pod.ObjectMeta.Annotations) {ipd.log.Info("overlay agent config error!please look the error annotation!")return PatchReq(ipd.pod, ipd.req)}return oa.next.execute(ipd)}// OverlayAgent overlays agentfunc (s *SidecarInjectField) OverlayAgent(a Annotations, ao *AnnotationOverlay, annotation *map[string]string) bool {// jvmAgentConfigStr inits.JvmAgentConfigStr = ""//遍历pod的注解,如果注解的名称存在于全量注解中,则将Pod注解及值保存到AnnotationOverlay map对象中anno := GetAnnotationsByPrefix(a, agentAnnotationPrefix)for k, v := range *annotation {if strings.HasPrefix(k, agentAnnotationPrefix) {for _, an := range anno.Annotations {if strings.EqualFold(k, an.Name) {if !s.AgentOverlayandGetValue(ao, annotation, an) {return false}}}// 将pod注解去掉agent前缀,追加到JvmAgentConfigStr字段中configName := strings.TrimPrefix(k, agentAnnotationPrefix)config := strings.Join([]string{configName, v}, "=")// add to jvmAgentConfigStrif s.JvmAgentConfigStr != "" {s.JvmAgentConfigStr = strings.Join([]string{s.JvmAgentConfigStr, config}, ",")} else {s.JvmAgentConfigStr = config}}}return true}
  1. 第五个执行的是OverlayPlugins,与OverlayAgent逻辑类似 。
  2. 第六个执行的是GetConfigmap,其作用是检查如果pod配置了agent configmap,则检查configmap配置的值是否正确.
func (s *SidecarInjectField) ValidateConfigmap(ctx context.Context, kubeclient client.Client, namespace string,annotation *map[string]string) bool {if len(s.ConfigmapVolume.Name) == 0 || len(s.ConfigmapVolume.ConfigMap.Name) == 0 {return true}configmap := &corev1.ConfigMap{}configmapName := s.ConfigmapVolume.VolumeSource.ConfigMap.LocalObjectReference.Name// check whether the configmap is existederr := kubeclient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: configmapName}, configmap)if err != nil && !errors.IsNotFound(err) {log.Error(err, "Get Configmap failed", "configmapName", configmapName, "namespace", namespace)return false}// if configmap exist , validate itif !errors.IsNotFound(err) {ok, errinfo := ValidateConfigmap(configmap)if ok {log.Info("the configmap validate true", "configmapName", configmapName)return true}log.Error(errinfo, "the configmap validate false", "configmapName", configmapName)}return true}
  1. 最后一步是PodInject,顾名思义,其作用是进行Pod注入
// PodInject will inject all fields to the podfunc (pi *PodInject) execute(ipd *InjectProcessData) admission.Response {log.Info("=============== PodInject ================")ipd.injectFileds.Inject(ipd.pod)// Pod注入完成后,添加sidecar.skywalking.apache.org/succeed=true注解ipd.injectFileds.injectSucceedAnnotation(&ipd.pod.Annotations)log.Info("inject successfully!")// 序列化Pod,返回给k8sreturn PatchReq(ipd.pod, ipd.req)}// Inject will do real injectionfunc (s *SidecarInjectField) Inject(pod *corev1.Pod) {log.Info(fmt.Sprintf("inject pod : %s", pod.GenerateName))// 将之前执行得到的InitContainer与pod配置的InitContainer合并在一起,也就是说pod initcontainer可以有多个if pod.Spec.InitContainers != nil {pod.Spec.InitContainers = append(pod.Spec.InitContainers, s.Initcontainer)} else {pod.Spec.InitContainers = []corev1.Container{s.Initcontainer}}// add volume to specif pod.Spec.Volumes == nil {pod.Spec.Volumes = []corev1.Volume{}}pod.Spec.Volumes = append(pod.Spec.Volumes, s.SidecarVolume)if len(s.ConfigmapVolume.Name) > 0 && len(s.ConfigmapVolume.ConfigMap.Name) > 0 {pod.Spec.Volumes = append(pod.Spec.Volumes, s.ConfigmapVolume)}//选择要注入的目标容器targetContainers := s.findInjectContainer(pod.Spec.Containers)//循环目标容器进行注入for i := range targetContainers {log.Info(fmt.Sprintf("inject container : %s", targetContainers[i].Name))if (*targetContainers[i]).VolumeMounts == nil {(*targetContainers[i]).VolumeMounts = []corev1.VolumeMount{}}// 注入voLume与configmap(*targetContainers[i]).VolumeMounts = append((*targetContainers[i]).VolumeMounts, s.SidecarVolumeMount)if len(s.ConfigmapVolumeMount.Name) > 0 && len(s.ConfigmapVolumeMount.MountPath) > 0 {(*targetContainers[i]).VolumeMounts = append((*targetContainers[i]).VolumeMounts, s.ConfigmapVolumeMount)}//java agent参数,其值为上面的JvmAgentConfigStrif (*targetContainers[i]).Env != nil {(*targetContainers[i]).Env = append((*targetContainers[i]).Env, s.Env)} else {(*targetContainers[i]).Env = []corev1.EnvVar{s.Env}}//注入环境变量,如果container本身存在,则忽略var envsTBA []corev1.EnvVarfor j, envInject := range s.Envs {isExists := falsefor _, envExists := range targetContainers[i].Env {if strings.EqualFold(envExists.Name, envInject.Name) {isExists = truebreak}}if !isExists {envsTBA = append(envsTBA, s.Envs[j])}}if len(s.Envs) > 0 {(*targetContainers[i]).Env = append((*targetContainers[i]).Env, envsTBA...)}}}

经验总结扩展阅读