项目地址:

GitHub - apache/skywalking-swck: Apache SkyWalking Cloud on Kubernetes

项目简介:

A bridge project between Apache SkyWalking and Kubernetes.

SWCK is a platform for the SkyWalking user that provisions, upgrades, maintains SkyWalking relevant components, and makes them work natively on Kubernetes.

skywalking-swck是一个在skywalking和kubernetes之间架起一座桥梁性质的项目。可以给用户提供skywalking相关组件及后期升级、维护。让他们使用起来更加云原生。

项目特性

  • Java Agent Injector: Inject the java agent into the application pod natively.

    • Inject the java agent into the application pod.
    • Leverage a global configuration to simplify the agent and injector setup.
    • Use the annotation to customize specific workloads.
    • Synchronize injecting status to JavaAgent CR for monitoring purposes.
  • Operator: Provision and maintain SkyWalking backend components.
  • Custom Metrics Adapter: Provides custom metrics coming from SkyWalking OAP cluster for autoscaling by Kubernetes HPA
  • 注入Java Agent: 以更加云原生的试注入java agent
    • 将java agent注入到应用pod
    • 可以全局化配置,简化agent注入操作
    • 使用annotation自定义一些配置
    • 将注入的状态同步到JavaAgent这个CR对象,便于监控
  • Operator: 提供和维护SkyWalking后端的组件
  • 自定义指标适配: 能够提供来自于SkyWalking OAP的自定义指标给kubernetes HPA,以便自动扩缩容

使用

skywalking-swck/java-agent-injector.md at master · apache/skywalking-swck

  1. 下载并安装Operator
  2. 创建ConfigMap/SwAgent等全局配置

    Annotations > SwAgent > Configmap (Deprecated) > Default Configmap (Deprecated)
  3. 接入应用配置label/annotations

    skywalking agent inject on kubernetes

原理

概述

当kubectl apply 一个 deployment资源后,k8s会创建pod,此时k8s根据mutatingwebhookconfigurations资源配置(配置了监控的资源以及webhook server信息),调用相应的webhook server,webhook server会进行处理,在pod yaml中注入initContainer配置,使业务容器与initContainer容器共享skywalking agent目录,并且配置JAVA_TOOL_OPTIONS环境变量值为"-javaagent:/sky/agent/skywalking-agent.jar=agent.service_name=xxxx",这样JVM启动时,会附加上javaagent,以达到目的。

详述

  1. 首先我们来看一下MutatingWebhookConfiguration和 ValidatingWebhookConfiguration资源

    查看kubectl explain 对这两个资源的描述
  1. MutatingWebhookConfiguration describes the configuration of and admission
  2. webhook that accept or reject and may change the object.
  3. ValidatingWebhookConfiguration describes the configuration of and admission
  4. webhook that accept or reject and object without changing it.

简而言之,这两种资源都是准入控制器(Admission Controller)的两种实现,都能控制是否接受还是拒绝对资源对象的变化,但不同的是,MutatingWebhookConfiguration可以改变资源对象,而ValidatingWebhookConfiguration不可以,可以参看搞懂 Kubernetes 准入控制(Admission Controller)详细了解。

2. swck就是利用MutatingWebhookConfiguration实现了对pod的修改,我们来看下swck中的定义

  1. apiVersion: admissionregistration.k8s.io/v1
  2. kind: MutatingWebhookConfiguration
  3. metadata:
  4. annotations:
  5. cert-manager.io/inject-ca-from: skywalking-swck-system/skywalking-swck-serving-cert
  6. name: skywalking-swck-mutating-webhook-configuration
  7. webhooks:
  8. - admissionReviewVersions:
  9. - v1
  10. clientConfig:
  11. service:
  12. name: skywalking-swck-webhook-service
  13. namespace: skywalking-swck-system
  14. path: /mutate-v1-pod
  15. failurePolicy: Fail
  16. name: mpod.kb.io
  17. namespaceSelector:
  18. matchLabels:
  19. swck-injection: enabled
  20. rules:
  21. - apiGroups:
  22. - ""
  23. apiVersions:
  24. - v1
  25. operations:
  26. - CREATE
  27. - UPDATE
  28. resources:
  29. - pods
  30. sideEffects: None

从这段定义中可以看出,当带有标签swck-injection: enabled的Namespace下的POD资源有CREATE或者UPDATE操作时,将会调用path: /mutate-v1-pod。

3. 在swck项目中的operator/man.go中找到此URL

  1. // register a webhook to enable the java agent injector
  2. setupLog.Info("registering /mutate-v1-pod webhook")
  3. mgr.GetWebhookServer().Register("/mutate-v1-pod",
  4. &webhook.Admission{
  5. Handler: &injector.JavaagentInjector{Client: mgr.GetClient()}})
  6. setupLog.Info("/mutate-v1-pod webhook is registered")

swck向k8s注册了/mutate-v1-pod以及对应的handler。我们可以想到,当create或update pod时,k8s将会调用path对应的handler处理。

4. 查看Handler: injector.JavaagentInjector

  1. // Handle will process every coming pod under the
  2. // specified namespace which labeled "swck-injection=enabled"
  3. func (r *JavaagentInjector) Handle(ctx context.Context, req admission.Request) admission.Response {
  4. pod := &corev1.Pod{}
  5. if err := r.decoder.Decode(req, pod); err != nil {
  6. return admission.Errored(http.StatusBadRequest, err)
  7. }
  8. // set Annotations to avoid repeated judgments
  9. if pod.Annotations == nil {
  10. pod.Annotations = map[string]string{}
  11. }
  12. // 查找所有匹配的swAgent
  13. swAgentL := r.findMatchedSwAgentL(ctx, req, pod)
  14. //初始化所有annotations(加载所有annotations)
  15. anno, err := NewAnnotations()
  16. if err != nil {
  17. javaagentInjectorLog.Error(err, "get NewAnnotations error")
  18. }
  19. //创建AnnotationOverlay对象,它是一个map,用于保存被overlaied的annotation
  20. ao := NewAnnotationOverlay()
  21. //创建SidecarInjectField对象
  22. s := NewSidecarInjectField()
  23. //构建inject链对象
  24. ip := NewInjectProcess(ctx, s, anno, ao, swAgentL, pod, req, javaagentInjectorLog, r.Client)
  25. //开始inject
  26. return ip.Run()
  27. }
  1. 创建inject chain对象

    Inject chain对象集合了此次有变更的Pod, webhook request, k8s client以及注解、swagent等对象
  1. // NewInjectProcess create a new InjectProcess
  2. func NewInjectProcess(ctx context.Context, injectFileds *SidecarInjectField, annotation *Annotations,
  3. annotationOverlay *AnnotationOverlay, swAgentL *v1alpha1.SwAgentList, pod *corev1.Pod, req admission.Request, log logr.Logger,
  4. kubeclient client.Client) *InjectProcessData {
  5. return &InjectProcessData{
  6. ctx: ctx,
  7. injectFileds: injectFileds,
  8. annotation: annotation,
  9. annotationOverlay: annotationOverlay,
  10. swAgentL: swAgentL,
  11. pod: pod,
  12. req: req,
  13. log: log,
  14. kubeclient: kubeclient,
  15. }
  16. }
  1. 看下ip.Run()方法

    经过了前面铺垫,终于到了主题了,run方法首先按照执行顺序倒序构造了一个执行链,然后执行。
  1. // Run will connect the above six steps into a chain and start to execute the first step
  2. func (ipd *InjectProcessData) Run() admission.Response {
  3. // set final step
  4. podInject := &PodInject{}
  5. // set next step is PodInject
  6. getConfigmap := &GetConfigmap{}
  7. getConfigmap.setNext(podInject)
  8. // set next step is GetConfigmap
  9. overlayPlugins := &OverlayPlugins{}
  10. overlayPlugins.setNext(getConfigmap)
  11. // set next step is OverlayPlugins
  12. overlayAgent := &OverlayAgent{}
  13. overlayAgent.setNext(overlayPlugins)
  14. // set next step is OverlayAgent
  15. overlaysidecar := &OverlaySidecar{}
  16. overlaysidecar.setNext(overlayAgent)
  17. // set next step is OverlaySwAgentCR
  18. overlaySwAgentCR := &OverlaySwAgentCR{}
  19. overlaySwAgentCR.setNext(overlaysidecar)
  20. // set next step is OverlaySidecar
  21. getStrategy := &GetStrategy{}
  22. getStrategy.setNext(overlaySwAgentCR)
  23. // this is first step and do real injection
  24. return getStrategy.execute(ipd)
  25. }
  1. 首先执行的是GetStrategy
  1. func (gs *GetStrategy) execute(ipd *InjectProcessData) admission.Response {
  2. log.Info("=============== GetStrategy ================")
  3. ipd.injectFileds.GetInjectStrategy(*ipd.annotation, &ipd.pod.ObjectMeta.Labels, &ipd.pod.ObjectMeta.Annotations)
  4. if !ipd.injectFileds.NeedInject {
  5. log.Info("don't inject agent")
  6. return admission.Allowed("ok")
  7. }
  8. return gs.next.execute(ipd)
  9. }
  10. // GetInjectStrategy gets user's injection strategy
  11. func (s *SidecarInjectField) GetInjectStrategy(a Annotations, labels,
  12. annotation *map[string]string) {
  13. // set default value
  14. s.NeedInject = false
  15. // set NeedInject's value , if the pod has the label "swck-java-agent-injected=true", means need inject
  16. if *labels == nil {
  17. return
  18. }
  19. if strings.EqualFold((*labels)[ActiveInjectorLabel], "true") {
  20. s.NeedInject = true
  21. }
  22. if *annotation == nil {
  23. return
  24. }
  25. // set injectContainer's value
  26. if v, ok := (*annotation)[sidecarInjectContainerAnno]; ok {
  27. s.InjectContainer = v
  28. }
  29. }

逻辑比较简单,判断当前pod需不需要inject,以及获取inject的container名字的正则表达式。

8. 第二个执行的是OverlaySwAgentCR

  1. // get configs from SwAgent CR
  2. func (gs *OverlaySwAgentCR) execute(ipd *InjectProcessData) admission.Response {
  3. log.Info(fmt.Sprintf("=============== OverlaySwAgentCR(%d) ================ ", len(ipd.swAgentL.Items)))
  4. if !ipd.injectFileds.OverlaySwAgentCR(ipd.swAgentL, ipd.pod) {
  5. log.Info("overlay SwAgent cr config error.")
  6. return PatchReq(ipd.pod, ipd.req)
  7. }
  8. return gs.next.execute(ipd)
  9. }
  10. func (s *SidecarInjectField) OverlaySwAgentCR(swAgentL *v1alpha1.SwAgentList, pod *corev1.Pod) bool {
  11. s.ConfigmapVolume.ConfigMap = new(corev1.ConfigMapVolumeSource)
  12. // 如果找到多个匹配的SwAgent,则应用最后一个,其它几个忽略
  13. if len(swAgentL.Items) > 0 {
  14. swAgent := swAgentL.Items[len(swAgentL.Items)-1]
  15. log.Info(fmt.Sprintf("agent %s loaded.", swAgent.Name))
  16. // 首先配置了shared volume, mount path。默认sharedVolumeName是sky-agent,mount path是/sky/agent
  17. // volume name可以更改, mountPath无法更改, mount path是业务容器上的path
  18. s.SidecarVolume.Name = swAgent.Spec.SharedVolumeName
  19. s.SidecarVolume.VolumeSource.EmptyDir = &corev1.EmptyDirVolumeSource{}
  20. s.SidecarVolumeMount.Name = swAgent.Spec.SharedVolumeName
  21. s.SidecarVolumeMount.MountPath = mountPath
  22. // 如果swagent配置了configmap,则设置业务容器mount path,实际是由configmap中的agent配置
  23. // 覆盖agent镜像中的配置
  24. if swAgent.Spec.SwConfigMapVolume != nil {
  25. if len(swAgent.Spec.SwConfigMapVolume.Name) > 0 &&
  26. len(swAgent.Spec.SwConfigMapVolume.ConfigMapName) > 0 &&
  27. len(swAgent.Spec.SwConfigMapVolume.ConfigMapMountFile) > 0 {
  28. //s.ConfigmapVolume = corev1.Volume{}
  29. s.ConfigmapVolume.Name = swAgent.Spec.SwConfigMapVolume.Name
  30. s.ConfigmapVolume.ConfigMap = new(corev1.ConfigMapVolumeSource)
  31. s.ConfigmapVolume.ConfigMap.Name = swAgent.Spec.SwConfigMapVolume.ConfigMapName
  32. //s.ConfigmapVolumeMount = corev1.VolumeMount{}
  33. s.ConfigmapVolumeMount.Name = swAgent.Spec.SwConfigMapVolume.Name
  34. s.ConfigmapVolumeMount.MountPath = "/sky/agent/config/" + swAgent.Spec.SwConfigMapVolume.ConfigMapMountFile
  35. s.ConfigmapVolumeMount.SubPath = swAgent.Spec.SwConfigMapVolume.ConfigMapMountFile
  36. }
  37. }
  38. // init container
  39. s.Initcontainer.Name = swAgent.Spec.JavaSidecar.Name
  40. s.Initcontainer.Image = swAgent.Spec.JavaSidecar.Image
  41. s.Initcontainer.Args = swAgent.Spec.JavaSidecar.Args
  42. s.Initcontainer.Command = swAgent.Spec.JavaSidecar.Command
  43. s.Initcontainer.VolumeMounts = append(s.Initcontainer.VolumeMounts, corev1.VolumeMount{
  44. Name: swAgent.Spec.SharedVolumeName,
  45. MountPath: mountPath,
  46. })
  47. // 将swagent配置的环境变量设置为业务容器的环境变量
  48. s.Envs = swAgent.Spec.JavaSidecar.Env
  49. s.InjectContainer = swAgent.Spec.ContainerMatcher
  50. }
  51. return true
  52. }
  1. 第三个执行的是OverlaySidecar
  1. func (os *OverlaySidecar) execute(ipd *InjectProcessData) admission.Response {
  2. log.Info("=============== OverlaySidecar ================")
  3. if !ipd.injectFileds.OverlaySidecar(*ipd.annotation, ipd.annotationOverlay, &ipd.pod.ObjectMeta.Annotations) {
  4. return PatchReq(ipd.pod, ipd.req)
  5. }
  6. return os.next.execute(ipd)
  7. }
  8. // OverlaySidecar overlays default config
  9. func (s *SidecarInjectField) OverlaySidecar(a Annotations, ao *AnnotationOverlay, annotation *map[string]string) bool {
  10. s.Initcontainer.Command = make([]string, 1)
  11. s.Initcontainer.Args = make([]string, 2)
  12. if nil == s.ConfigmapVolume.ConfigMap {
  13. s.ConfigmapVolume.ConfigMap = new(corev1.ConfigMapVolumeSource)
  14. }
  15. limitsStr := ""
  16. requestStr := ""
  17. // 创建sidercar注解map对象,其初始值从上一步执行结果中获取.map中的key为sidecar注解去掉前缀后的名称
  18. annoField := map[string]*string{
  19. "initcontainer.Name": &s.Initcontainer.Name,
  20. "initcontainer.Image": &s.Initcontainer.Image,
  21. "initcontainer.Command": &s.Initcontainer.Command[0],
  22. "initcontainer.args.Option": &s.Initcontainer.Args[0],
  23. "initcontainer.args.Command": &s.Initcontainer.Args[1],
  24. "initcontainer.resources.limits": &limitsStr,
  25. "initcontainer.resources.requests": &requestStr,
  26. "sidecarVolume.Name": &s.SidecarVolume.Name,
  27. "sidecarVolumeMount.MountPath": &s.SidecarVolumeMount.MountPath,
  28. "configmapVolume.ConfigMap.Name": &s.ConfigmapVolume.ConfigMap.Name,
  29. "configmapVolume.Name": &s.ConfigmapVolume.Name,
  30. "configmapVolumeMount.MountPath": &s.ConfigmapVolumeMount.MountPath,
  31. "env.Name": &s.Env.Name,
  32. "env.Value": &s.Env.Value,
  33. }
  34. // 从全量注解中获取sidercar前缀的注解,遍历,检查Pod有没有设置相应sidercar注解,如果设置了,则覆盖map中对应key原来的值
  35. anno := GetAnnotationsByPrefix(a, sidecarAnnotationPrefix)
  36. for _, v := range anno.Annotations {
  37. fieldName := strings.TrimPrefix(v.Name, sidecarAnnotationPrefix)
  38. if pointer, ok := annoField[fieldName]; ok {
  39. if !s.setValue(pointer, ao, annotation, v) {
  40. return false
  41. }
  42. }
  43. }
  44. s.SidecarVolumeMount.Name = s.SidecarVolume.Name
  45. s.ConfigmapVolumeMount.Name = s.ConfigmapVolume.Name
  46. s.Initcontainer.VolumeMounts = []corev1.VolumeMount{s.SidecarVolumeMount}
  47. // 设置init container的资源限制
  48. if limitsStr != "nil" {
  49. limits := make(corev1.ResourceList)
  50. err := json.Unmarshal([]byte(limitsStr), &limits)
  51. if err != nil {
  52. log.Error(err, "unmarshal limitsStr error")
  53. return false
  54. }
  55. s.Initcontainer.Resources.Limits = limits
  56. }
  57. // 设置init container需要申请的资源
  58. if requestStr != "nil" {
  59. requests := make(corev1.ResourceList)
  60. err := json.Unmarshal([]byte(requestStr), &requests)
  61. if err != nil {
  62. log.Error(err, "unmarshal requestStr error")
  63. return false
  64. }
  65. s.Initcontainer.Resources.Requests = requests
  66. }
  67. // the sidecar volume's type is determined
  68. s.SidecarVolume.VolumeSource.EmptyDir = nil
  69. return true
  70. }
  1. 第四个执行的是OverlayAgent
  1. // OverlayAgent overlays the agent by getting the pod's annotations
  2. // If the agent overlay option is not set, go directly to the next step
  3. // If set the wrong value in the annotation , inject the error info and return
  4. func (oa *OverlayAgent) execute(ipd *InjectProcessData) admission.Response {
  5. log.Info("=============== OverlayAgent ================")
  6. if !ipd.injectFileds.OverlayAgent(*ipd.annotation, ipd.annotationOverlay, &ipd.pod.ObjectMeta.Annotations) {
  7. ipd.log.Info("overlay agent config error!please look the error annotation!")
  8. return PatchReq(ipd.pod, ipd.req)
  9. }
  10. return oa.next.execute(ipd)
  11. }
  12. // OverlayAgent overlays agent
  13. func (s *SidecarInjectField) OverlayAgent(a Annotations, ao *AnnotationOverlay, annotation *map[string]string) bool {
  14. // jvmAgentConfigStr init
  15. s.JvmAgentConfigStr = ""
  16. //遍历pod的注解,如果注解的名称存在于全量注解中,则将Pod注解及值保存到AnnotationOverlay map对象中
  17. anno := GetAnnotationsByPrefix(a, agentAnnotationPrefix)
  18. for k, v := range *annotation {
  19. if strings.HasPrefix(k, agentAnnotationPrefix) {
  20. for _, an := range anno.Annotations {
  21. if strings.EqualFold(k, an.Name) {
  22. if !s.AgentOverlayandGetValue(ao, annotation, an) {
  23. return false
  24. }
  25. }
  26. }
  27. // 将pod注解去掉agent前缀,追加到JvmAgentConfigStr字段中
  28. configName := strings.TrimPrefix(k, agentAnnotationPrefix)
  29. config := strings.Join([]string{configName, v}, "=")
  30. // add to jvmAgentConfigStr
  31. if s.JvmAgentConfigStr != "" {
  32. s.JvmAgentConfigStr = strings.Join([]string{s.JvmAgentConfigStr, config}, ",")
  33. } else {
  34. s.JvmAgentConfigStr = config
  35. }
  36. }
  37. }
  38. return true
  39. }
  1. 第五个执行的是OverlayPlugins,与OverlayAgent逻辑类似。
  2. 第六个执行的是GetConfigmap,其作用是检查如果pod配置了agent configmap,则检查configmap配置的值是否正确.
  1. func (s *SidecarInjectField) ValidateConfigmap(ctx context.Context, kubeclient client.Client, namespace string,
  2. annotation *map[string]string) bool {
  3. if len(s.ConfigmapVolume.Name) == 0 || len(s.ConfigmapVolume.ConfigMap.Name) == 0 {
  4. return true
  5. }
  6. configmap := &corev1.ConfigMap{}
  7. configmapName := s.ConfigmapVolume.VolumeSource.ConfigMap.LocalObjectReference.Name
  8. // check whether the configmap is existed
  9. err := kubeclient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: configmapName}, configmap)
  10. if err != nil && !errors.IsNotFound(err) {
  11. log.Error(err, "Get Configmap failed", "configmapName", configmapName, "namespace", namespace)
  12. return false
  13. }
  14. // if configmap exist , validate it
  15. if !errors.IsNotFound(err) {
  16. ok, errinfo := ValidateConfigmap(configmap)
  17. if ok {
  18. log.Info("the configmap validate true", "configmapName", configmapName)
  19. return true
  20. }
  21. log.Error(errinfo, "the configmap validate false", "configmapName", configmapName)
  22. }
  23. return true
  24. }
  1. 最后一步是PodInject,顾名思义,其作用是进行Pod注入
  1. // PodInject will inject all fields to the pod
  2. func (pi *PodInject) execute(ipd *InjectProcessData) admission.Response {
  3. log.Info("=============== PodInject ================")
  4. ipd.injectFileds.Inject(ipd.pod)
  5. // Pod注入完成后,添加sidecar.skywalking.apache.org/succeed=true注解
  6. ipd.injectFileds.injectSucceedAnnotation(&ipd.pod.Annotations)
  7. log.Info("inject successfully!")
  8. // 序列化Pod,返回给k8s
  9. return PatchReq(ipd.pod, ipd.req)
  10. }
  11. // Inject will do real injection
  12. func (s *SidecarInjectField) Inject(pod *corev1.Pod) {
  13. log.Info(fmt.Sprintf("inject pod : %s", pod.GenerateName))
  14. // 将之前执行得到的InitContainer与pod配置的InitContainer合并在一起,也就是说pod initcontainer可以有多个
  15. if pod.Spec.InitContainers != nil {
  16. pod.Spec.InitContainers = append(pod.Spec.InitContainers, s.Initcontainer)
  17. } else {
  18. pod.Spec.InitContainers = []corev1.Container{s.Initcontainer}
  19. }
  20. // add volume to spec
  21. if pod.Spec.Volumes == nil {
  22. pod.Spec.Volumes = []corev1.Volume{}
  23. }
  24. pod.Spec.Volumes = append(pod.Spec.Volumes, s.SidecarVolume)
  25. if len(s.ConfigmapVolume.Name) > 0 && len(s.ConfigmapVolume.ConfigMap.Name) > 0 {
  26. pod.Spec.Volumes = append(pod.Spec.Volumes, s.ConfigmapVolume)
  27. }
  28. //选择要注入的目标容器
  29. targetContainers := s.findInjectContainer(pod.Spec.Containers)
  30. //循环目标容器进行注入
  31. for i := range targetContainers {
  32. log.Info(fmt.Sprintf("inject container : %s", targetContainers[i].Name))
  33. if (*targetContainers[i]).VolumeMounts == nil {
  34. (*targetContainers[i]).VolumeMounts = []corev1.VolumeMount{}
  35. }
  36. // 注入voLume与configmap
  37. (*targetContainers[i]).VolumeMounts = append((*targetContainers[i]).VolumeMounts, s.SidecarVolumeMount)
  38. if len(s.ConfigmapVolumeMount.Name) > 0 && len(s.ConfigmapVolumeMount.MountPath) > 0 {
  39. (*targetContainers[i]).VolumeMounts = append((*targetContainers[i]).VolumeMounts, s.ConfigmapVolumeMount)
  40. }
  41. //java agent参数,其值为上面的JvmAgentConfigStr
  42. if (*targetContainers[i]).Env != nil {
  43. (*targetContainers[i]).Env = append((*targetContainers[i]).Env, s.Env)
  44. } else {
  45. (*targetContainers[i]).Env = []corev1.EnvVar{s.Env}
  46. }
  47. //注入环境变量,如果container本身存在,则忽略
  48. var envsTBA []corev1.EnvVar
  49. for j, envInject := range s.Envs {
  50. isExists := false
  51. for _, envExists := range targetContainers[i].Env {
  52. if strings.EqualFold(envExists.Name, envInject.Name) {
  53. isExists = true
  54. break
  55. }
  56. }
  57. if !isExists {
  58. envsTBA = append(envsTBA, s.Envs[j])
  59. }
  60. }
  61. if len(s.Envs) > 0 {
  62. (*targetContainers[i]).Env = append((*targetContainers[i]).Env, envsTBA...)
  63. }
  64. }
  65. }

除了Pod注入,SWCK项目还有其它Operator, 包括Storage,OAP,UI,Adapter等,有兴趣的话可自行探索。总体来说swck利用k8s的自定义资源以及自定义控制器,为skywalking部署到kubernetes提供了适配,使skywalking能够快速部署到kubernetes这个基座上。

注意事项

  1. SwAgent只能在业务空间起作用,不能在skywalking-swck-system生效

因为webhook触发调用handler后,在查找SwAgent时,只会查找与Pod在一个命名空间中的Swagent. 如果想将SwAgent放到skywalking-swck-system命令空间,需要修改operator

  1. 删除资源时JavaAgent状态中统计的注入的容器数量不变化

因为MutatingWebhookConfiguration只监听了Pod的Create与Update事件。

  1. 调试需要问题
  • 本地启用webhook前提下无法启动operator

因为启动webhook时,需要在本地启动webhook server,与k8s集群通过https通信, 本地需要添加tls.crt以及tls.key文件。而这两个文件从k8s获取。具体方法是查看skywalking-swck-controller-manager使用到的secret

  1. kubectl get secret skywalking-swck-controller-manager-cert -n skywalking-swck-system -o jsonpath='{.data.tls\.crt}'| base64 --decode > tls.crt
  2. kubectl get secret skywalking-swck-controller-manager-cert -n skywalking-swck-system -o jsonpath='{.data.tls\.key}'| base64 --decode > tls.key
  3. ```

Skywalking Swck Agent注入实现分析的更多相关文章

  1. PHPCMS \phpcms\modules\member\index.php 用户登陆SQL注入漏洞分析

    catalog . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述2. 漏洞触发条件 0x1: POC http://localhost/p ...

  2. sql注入实例分析

    什么是SQL注入攻击?引用百度百科的解释: sql注入_百度百科: 所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令.具 ...

  3. Mysql报错注入原理分析(count()、rand()、group by)

    Mysql报错注入原理分析(count().rand().group by) 0x00 疑问 一直在用mysql数据库报错注入方法,但为何会报错? 百度谷歌知乎了一番,发现大家都是把官网的结论发一下截 ...

  4. SpringBoot SpEL表达式注入漏洞-分析与复现

    目录 0x00前言 0x01触发原因 0x02调试分析 0x03补丁分析 0x04参考文章 影响版本: 1.1.0-1.1.12 1.2.0-1.2.7 1.3.0 修复方案:升至1.3.1或以上版本 ...

  5. Spring依赖注入原理分析

    在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...

  6. Beescms_v4.0 sql注入漏洞分析

    Beescms_v4.0 sql注入漏洞分析 一.漏洞描述 Beescms v4.0由于后台登录验证码设计缺陷以及代码防护缺陷导致存在bypass全局防护的SQL注入. 二.漏洞环境搭建 1.官方下载 ...

  7. 微服务-技术专区-监控专区(Skywalking与Pinpoint) - 监控对比分析

    由于公司目前有200多微服务,微服务之间的调用关系错综复杂,调用关系人工维护基本不可能实现,需要调研一套全链路追踪方案,初步调研之后选取了skywalking和pinpoint进行对比; 选取skyw ...

  8. PDO防sql注入原理分析

    使用pdo的预处理方式可以避免sql注入. 在php手册中'PDO--预处理语句与存储过程'下的说明: 很多更成熟的数据库都支持预处理语句的概念.什么是预处理语句?可以把它看作是想要运行的 SQL 的 ...

  9. [转]PDO防注入原理分析以及使用PDO的注意事项

    原文:http://zhangxugg-163-com.iteye.com/blog/1835721 好文章不得不转. 我们都知道,只要合理正确使用PDO,可以基本上防止SQL注入的产生,本文主要回答 ...

随机推荐

  1. 温控器/胎压检测/电表/热泵显示控制器等,低功耗高抗干扰断/段码(字段式)LCD液晶显示驱动IC-VK2C22A/B,替代市面16C22,44*4/40*4点显示

    产品品牌:永嘉微电/VINKA 产品型号:VK2C22A/B 封装形式:LQFP52/48 产品年份:新年份 概述: VK2C22是一个点阵式存储映射的LCD驱动器,可支持最大176点(44SEGx4 ...

  2. CodeForce——Deltix Round, Autumn 2021 (open for everyone, rated, Div. 1 + Div. 2)前三道题目题解

    目录 A: B: C: 题目链接 A Divide and Multiply standard input/output 1 s, 256 MB 正在上传-重新上传取消 x13036 B Willia ...

  3. 0202年,您真的需要Thrift这样一个RPC微服务框架来拯救一下传统HTTP接口(api)了

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_104 目前市面上类似Django的drf框架基于json的http接口解决方案大行其道,人们也热衷于在接口不多.系统与系统交互较少 ...

  4. 一网成擒全端涵盖,在不同架构(Intel x86/Apple m1 silicon)不同开发平台(Win10/Win11/Mac/Ubuntu)上安装配置Python3.10开发环境

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_200 时光荏苒,过隙白驹,即将进入2022年,著名敏捷开发语言Python也放出了3.10最终版,本次我们来展示一下在不同的系统和 ...

  5. Vue $nextTick && 过度与动画

    1 # $nextTick 2 # 1.语法: this.$nextTick(回调函数); 3 # 2.作用:在下一次DOM更新结束后执行其指定的回调. 4 # 3.什么时候用:当改变数据后,要基于更 ...

  6. JavaScript数组方法总结,本文是根据数组原型上的方法进行总结,由于方法太多将会分篇章发布

    通过浏览器控制台 console 可查看到 Array 数组上原型的所有方法(如下图).对于原型问题此文章暂不过多叙述,单针对对象中的方法进行自我看法的总结:细心的同学可以发现对象原型上所携带的方法基 ...

  7. leetcode之二叉树

    专题:二叉树遍历 987. 二叉树的垂序遍历 给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列. 对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row ...

  8. 054_末晨曦Vue技术_处理边界情况之组件之间的循环引用

    组件之间的循环引用 点击打开视频讲解更详细 假设你需要构建一个文件目录树,像访达或资源管理器那样的.你可能有一个 <tree-folder> 组件,模板是这样的: <p> &l ...

  9. html页面中插入html的标签,JS控制标签属性

    html页面中插入html的标签 方法1: 使用标签: <textara> </textara>标签 方法2: 使用JS: document.getElementById(&q ...

  10. 「题解报告」P7301 【[USACO21JAN] Spaced Out S】

    原题传送门 神奇的5分算法:直接输出样例. 20分算法 直接把每个点是否有牛的状态DFS一遍同时判断是否合法,时间复杂度约为\(O(2^{n^2})\)(因为有判断合法的剪枝所以会比这个低).而在前四 ...