从源码看istio探针重写

背景

istio注入sidecar会重写pod原有的probe,这里记录一下相关源码

源码

istiod

pkg/kube/inject/webhook.go中

func NewWebhook(p WebhookParameters) (*Webhook, error) {
    ...
    注册注入的http入口方法
    p.Mux.HandleFunc("/inject", wh.serveInject)
    p.Mux.HandleFunc("/inject/", wh.serveInject)
    ...
}

处理注入的http入口方法
func (wh *Webhook) serveInject(w http.ResponseWriter, r *http.Request) {
    ...
    处理注入
            reviewResponse = wh.inject(ar, path)
    ...
}


注入方法
func (wh *Webhook) inject(ar *kube.AdmissionReview, path string) \*kube.AdmissionResponse {
    ...
    注入pod
    patchBytes, err := injectPod(params)
    ...
}

注入pod
func injectPod(req InjectionParameters) ([]byte, error) {
    ...
    pod根据注入模板处理后
    if err := postProcessPod(mergedPod, *injectedPodData, req); err != nil {
        return nil, fmt.Errorf("failed to process pod: %v", err)
    }
    ...
}

pod根据注入模板处理后
func postProcessPod(pod *corev1.Pod, injectedPod corev1.Pod, req InjectionParameters) error {
    ...
    重写
    if err := applyRewrite(pod, req); err != nil {
        return err
    }
    ...
}

重写探针
func applyRewrite(pod *corev1.Pod, req InjectionParameters) error {
    找到sidecar容器
    sidecar := FindSidecar(pod)
    if sidecar == nil {
        return nil
    }
    判断是否需要重写
    rewrite := ShouldRewriteAppHTTPProbers(pod.Annotations, req.valuesConfig.asStruct.GetSidecarInjectorWebhook().GetRewriteAppHTTPProbe().GetValue())
    if rewrite {
        if prober := DumpAppProbers(pod, req.meshConfig.GetDefaultConfig().GetStatusPort()); prober != "" {
            写入环境变量
            _, previouslyInjected := pod.Annotations[annotation.SidecarStatus.Name]
            sidecar.Env = mergeOrAppendProbers(previouslyInjected, sidecar.Env, prober)
        }
        修改探针
        patchRewriteProbe(pod.Annotations, pod, req.meshConfig.GetDefaultConfig().GetStatusPort())
    }
    return nil
}

合并或追加应用探针
func mergeOrAppendProbers(previouslyInjected bool, envVars []corev1.EnvVar, newProbers string) []corev1.EnvVar {
    如果未注入
    if !previouslyInjected {
        return append(envVars, corev1.EnvVar{Name: status.KubeAppProberEnvName, Value: newProbers})
    }
    ...
}

pkg/kube/inject/app_probe.go中

改写探针
func patchRewriteProbe(annotations map[string]string, pod *corev1.Pod, defaultPort int32) {
    ...
    遍历容器
    for i, c := range pod.Spec.Containers {
        if c.Name == ProxyContainerName {
            continue
        }
        转换探针
        convertProbe(&c, statusPort)
        pod.Spec.Containers[i] = c
    }
    ...
}

转换探针
func convertProbe(c *corev1.Container, statusPort int) {
    生成探针URL
    readyz, livez, startupz, prestopz, poststartz := status.FormatProberURL(c.Name)
    ...
    转换探针
    if probePatch := convertAppProber(c.ReadinessProbe, readyz, statusPort); probePatch != nil {
        c.ReadinessProbe = probePatch
    }
    ...
}

转换探针
func convertAppProber(probe *corev1.Probe, newURL string, statusPort int) *corev1.Probe {
    if probe == nil {
        return nil
    }
    if probe.HTTPGet != nil {
        return convertAppProberHTTPGet(probe, newURL, statusPort)
    } else if probe.TCPSocket != nil {
        return convertAppProberTCPSocket(probe, newURL, statusPort)
    } else if probe.GRPC != nil {
        return convertAppProberGRPC(probe, newURL, statusPort)
    }

    return nil
}

转换HTTPGet探针
func convertAppProberHTTPGet(probe *corev1.Probe, newURL string, statusPort int) *corev1.Probe {
    p := probe.DeepCopy()
    rewriteHTTPGetAction(p.HTTPGet, newURL, statusPort)
    return p
}


重写HTTPGetAction
func rewriteHTTPGetAction(action *corev1.HTTPGetAction, url string, port int) {
    action.Port = intstr.FromInt32(int32(port))
    action.Path = url
    // Kubelet -> HTTP -> Pilot Agent -> HTTPS -> Application
    if action.Scheme == corev1.URISchemeHTTPS {
        action.Scheme = corev1.URISchemeHTTP
    }
}


pilot/cmd/pilot-agent/status/server.go中

生成探针URL
func FormatProberURL(container string) (string, string, string, string, string) {
    return fmt.Sprintf("/app-health/%v/readyz", container),
        fmt.Sprintf("/app-health/%v/livez", container),
        fmt.Sprintf("/app-health/%v/startupz", container),
        fmt.Sprintf("/app-lifecycle/%v/prestopz", container),
        fmt.Sprintf("/app-lifecycle/%v/poststartz", container)
}

pilot-agent

pilot/cmd/pilot-agent/status/server.go中

var(
    ...
    KubeAppProberEnvName环境变量名
    KubeAppProberEnvName = "ISTIO_KUBE_APP_PROBERS"
    ...
)

pilot/cmd/pilot-agent/options/statusserver.go中

构建pilot-agent status server options
func NewStatusServerOptions(ipv6 bool, t model.NodeType, proxyConfig *meshconfig.ProxyConfig, agent *istioagent.Agent) *status.Options {
    return &status.Options{
        ...
        PodIP:          InstanceIPVar.Get(),
        ...
        KubeAppProbers: kubeAppProberNameVar.Get(),
        ...
    }
}


var (
    ...
    KubeAppProberEnvName环境变量
    kubeAppProberNameVar = env.Register(status.KubeAppProberEnvName, "", "")
    ...
    pod ip环境变量
    InstanceIPVar        = env.Register("INSTANCE_IP", "", "")
)

pilot/cmd/pilot-agent/status/server.go中

构建pilot-agent status server
func NewServer(config Options) (*Server, error) {
    ...
    解析KubeAppProbers
    if err := json.Unmarshal([]byte(config.KubeAppProbers), &s.appKubeProbers); err != nil {
        return nil, fmt.Errorf("failed to decode app prober err = %v, json string = %v", err, config.KubeAppProbers)
    }
    ...
    初始化appProbeClient
    s.appProbeClient = make(map[string]*http.Client, len(s.appKubeProbers))
    ...
    构建appProbeClient
    for path, prober := range s.appKubeProbers {
        ...
        if prober.HTTPGet != nil {
            ...
            s.appProbeClient[path] = &http.Client{
                Timeout: time.Duration(prober.TimeoutSeconds) * time.Second,
                Transport:     transport,
                CheckRedirect: redirectChecker(),
            }
        }
    }
}


运行pilot-agent status server
func (s *Server) Run(ctx context.Context) {
    ...
    注册app-health和app-lifecycle的handler
    mux.HandleFunc("/app-health/", s.handleAppProbe)
    mux.HandleFunc("/app-lifecycle/", s.handleAppProbe)
    ...
}


处理应用探针请求
func (s *Server) handleAppProbe(w http.ResponseWriter, req *http.Request) {
    ...
    判断探针类型
    switch {
    case prober.HTTPGet != nil:
        s.handleAppProbeHTTPGet(w, req, prober, path)
    case prober.TCPSocket != nil:
        s.handleAppProbeTCPSocket(w, prober)
    case prober.GRPC != nil:
        s.handleAppProbeGRPC(w, req, prober)
    }
    ...
}


处理HTTPGet探针
func (s *Server) handleAppProbeHTTPGet(w http.ResponseWriter, req *http.Request, prober *Prober, path string) {
    ...
    proberPath := prober.HTTPGet.Path

    ...
    hostPort := net.JoinHostPort(s.appProbersDestination, strconv.Itoa(prober.HTTPGet.Port.IntValue()))
    ...
    构建应用探针HTTP请求
    appReq, err := http.NewRequest(http.MethodGet, url, nil)
    if err != nil {
        log.Errorf("Failed to create request to probe app %v, original url %v", err, path)
        w.WriteHeader(http.StatusInternalServerError)
        return
    }
    ...
    获取应用探针HTTP客户端
    httpClient := s.appProbeClient[path]
    发送应用探针HTTP请求
    response, err := httpClient.Do(appReq)
    ...
}

配置

全局

修改istio-system/istio-sidecar-injector这个configmap(默认为true)

  values: |-
    {
      ...
      "sidecarInjectorWebhook": {
        ...
        "rewriteAppHTTPProbe": true,
        ...
      }
      ...
    }

pod级

pod添加注解

metadata:
  annotations:
    sidecar.istio.io/rewriteAppHTTPProbers: "true"
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容