为网格内应用开启健康检查重定向

由于Sidecar对网格内应用接收请求的拦截机制,如果您为加入服务网格ASM(即注入了Sidecar)中的应用配置了HTTP请求或TCP请求形式的健康检查,则健康检查可能出现不符合预期的行为,例如健康检查一直失败。本文介绍如何为网格内应用开启健康检查重定向。

背景信息

为网格内应用启用HTTP和TCP请求的健康检查存在以下问题。因此,您需要基于Annotation方式为网格内应用开启健康检查重定向,让健康检查恢复正常。

类型

说明

使用HTTP请求的健康检查

Kubernetes集群由Kubelet服务统一发送Pod的健康检查请求,而在开启了双向TLS模式后,网格内应用被强制要求使用TLS方式进行通信。由于Kubelet服务并非网格的一部分,该服务没有服务网格为应用颁发的证书,导致使用HTTP方式的健康检查请求会被拒绝,健康检查一直失败。

说明

如果您未在ASM中开启双向TLS模式,无需配置健康检查重定向,就可以使用HTTP请求对应用Pod进行健康检查。

使用TCP请求的健康检查

由于Sidecar拦截请求的需要,网格内应用Pod的所有端口都会被监听。在使用TCP请求方式的健康检查时,Kubelet服务会检查应用Pod所配置的端口是否有应用正在进行监听,判断应用的健康状态。

由于上述原因,只要应用注入了Sidecar,且Sidecar正在运行,无论应用本身处于何种状态,健康检查都始终会成功。例如,您为应用配置了错误端口,Pod的健康检查理应始终失败,Pod应该处于未就绪状态,但实际上健康检查成功。

默认情况下,网格拓扑图中会显示应用服务的健康检查的请求调用,但在很多场景下可能会混淆流量统计的结果。如果您需要移除这些内部的健康检查调用统计,可以为网格内应用开启健康检查重定向。

启用HTTP请求的健康检查重定向

本文以Nginx应用为例,在开启双向TLS模式后,为Nginx应用配置HTTP请求的健康检查,但是健康检查一直失败,然后为Nginx应用开启健康检查重定向,查看Pod事件时无健康检查失败事件,且Pod处于就绪状态,说明为应用启用HTTP请求的健康检查重定向成功。

步骤一:开启网格全局双向TLS模式

  1. 登录ASM控制台

  2. 在左侧导航栏,选择服务网格 > 网格管理

  3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理

  4. 在网格详情页面左侧导航栏,选择网格安全中心 > 对等身份认证

  5. 对等身份认证页面顶部,选择命名空间,然后单击设置全局双向TLS模式

  6. 设置全局双向TLS模式页面,设置mTLS模式(命名空间级)STRICT - 严格遵循双向TLS认证,单击创建

步骤二:部署Nginx应用

  1. 获取集群KubeConfig并通过kubectl工具连接集群

  2. 部署Nginx应用。

    1. 使用以下内容,创建http-liveness.yaml

      展开查看http-liveness.yaml

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nginx-deployment
        labels:
          app: nginx
      spec:
        selector:
          matchLabels:
            app: nginx
        replicas: 1
        template:
          metadata:
            labels:
              app: nginx
          spec:
            containers:
            - name: nginx
              image: nginx
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 80
              readinessProbe:
                httpGet:
                  path: /index.html
                  port: 80
                  httpHeaders:
                  - name: X-Custom-Header
                    value: hello
                initialDelaySeconds: 5
                periodSeconds: 3

      readinessProbe参数下设置httpGet,表示为该应用启用HTTP请求的健康检查。

    2. 执行以下命令,部署Nginx应用。

      kubectl apply -f http-liveness.yaml
  3. 查看应用的健康检查状态。

    1. 执行以下命令,查看Nginx应用的Pod名称。

      kubectl get pod| grep nginx
    2. 执行以下命令,查看Pod事件。

      kubectl describe pod <Pod名称>

      预期输出:

      Warning  Unhealthy  45s               kubelet            Readiness probe failed: Get "http://172.23.64.22:80/index.html": read tcp 172.23.64.1:54130->172.23.64.22:80: read: connection reset by peer

      可以看到,针对Pod的HTTP健康检查失败,使得Pod一直处于未就绪的状态。

步骤三:为Nginx应用开启健康检查重定向

  1. 执行以下命令,编辑http-liveness.yaml

    vim http-liveness.yaml

    template参数下添加以下内容:

    annotations:
      sidecar.istio.io/rewriteAppHTTPProbers: "true"

    以下为添加Annotation注解后的http-liveness.yaml文件:

    展开查看http-liveness.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      replicas: 1
      template:
        metadata:
          labels:
            app: nginx
          annotations:
            sidecar.istio.io/rewriteAppHTTPProbers: "true"
        spec:
          containers:
          - name: nginx
            image: nginx
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
            readinessProbe:
              httpGet:
                path: /index.html
                port: 80
                httpHeaders:
                - name: X-Custom-Header
                  value: hello
              initialDelaySeconds: 5
              periodSeconds: 3
  2. 执行以下命令,部署Nginx应用。

    kubectl apply -f http-liveness.yaml

步骤四:验证健康检查结果是否符合预期

  1. 查看Pod的健康检查状态。

    1. 执行以下命令,查看Nginx应用的Pod名称。

      kubectl get pod| grep nginx
    2. 执行以下命令,查看Pod事件。

      kubectl describe pod <Pod名称>

      返回结果中不包含任务健康检查失败的事件,Pod处于就绪状态,启用健康检查成功,符合预期。

  2. 执行以下命令,查看经过健康检查重定向后的Pod YAML文件。

    kubectl get pod nginx-deployment-676f85f66b-7vxct -o yaml

    展开查看预期输出

    apiVersion: v1
    kind: Pod
    metadata:
      ...
      name: nginx-deployment-676f85f66b-cbzsx
      namespace: default
      ...
    spec:
      containers:
        - args:
            - proxy
            - sidecar
            - '--domain'
            - $(POD_NAMESPACE).svc.cluster.local
            - '--proxyLogLevel=warning'
            - '--proxyComponentLogLevel=misc:error'
            - '--log_output_level=default:info'
            - '--concurrency'
            - '2'
          env:
            ...
            - name: ISTIO_KUBE_APP_PROBERS
              value: >-
                {"/app-health/nginx/readyz":{"httpGet":{"path":"/index.html","port":80,"scheme":"HTTP","httpHeaders":[{"name":"X-Custom-Header","value":"hello"}]},"timeoutSeconds":1}}
          ...
        - image: nginx
          imagePullPolicy: IfNotPresent
          name: nginx
          ports:
            - containerPort: 80
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            httpGet:
              httpHeaders:
                - name: X-Custom-Header
                  value: hello
              path: /app-health/nginx/readyz
              port: 15020
              scheme: HTTP
            initialDelaySeconds: 5
            periodSeconds: 3
            successThreshold: 1
            timeoutSeconds: 1

    启用了健康检查重定向后,原先配置的健康检查端口由80改为15020,健康检查的路径也由/index.html改为/app-health/nginx/readyz。同时,Pod中的Sidecar容器新增一个名为ISTIO_KUBE_APP_PROBERS的环境变量,其值为改写健康检查之前的健康检查配置经过JSON序列化后的内容。

    对于网格内应用来说,15020是一个用于网格可观测性的特殊端口,发送到该端口的流量不会被Sidecar拦截,因此不需要遵循TLS模式的要求。 在启用健康检查重定向后,运行于Sidecar容器中的pilot-agent服务会开启监听15020端口,接收来自Kubelet服务的健康检查,并根据ISTIO_KUBE_APP_PROBERS环境变量中配置的健康检查内容将健康检查请求转发至业务容器,从而使HTTP请求方式的健康检查正常运行。

启用TCP请求的健康检查重定向

本文以Nginx应用为例,为Nginx应用配置了错误端口,但是使用TCP的方式对应用的Pod健康检查仍然成功,不符合预期。然后为Nginx应用开启健康检查重定向,使用TCP的方式对应用的Pod健康检查失败,符合预期,从而为应用成功启用TCP请求的健康检查重定向。

步骤一:部署Nginx应用

  1. 获取集群KubeConfig并通过kubectl工具连接集群

  2. 部署Nginx应用。

    1. 使用以下内容,创建tcp-liveness.yaml

      以下内容中配置了一个错误的健康检查端口2940,由于Nginx应用不在2940端口开启监听,因此部署应用后健康检查应始终失败,导致Pod一直处于未就绪状态。

      展开查看tcp-liveness.yaml

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: nginx-deployment
        labels:
          app: nginx
      spec:
        selector:
          matchLabels:
            app: nginx
        replicas: 1
        template:
          metadata:
            labels:
              app: nginx
          spec:
            containers:
            - name: nginx
              image: nginx
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 80
              readinessProbe:
                tcpSocket:
                  port: 2940
                initialDelaySeconds: 5
                periodSeconds: 3

      readinessProbe参数下设置tcpSocket,表示为该应用启用TCP请求的健康检查。

    2. 执行以下命令,部署Nginx应用。

      kubectl apply -f tcp-liveness.yaml
  3. 查看应用的健康检查状态。

    1. 执行以下命令,查看Nginx应用的Pod名称。

      kubectl get pod| grep nginx
    2. 执行以下命令,查看Pod事件。

      kubectl describe pod <Pod名称>

      返回结果中不包含任何健康检查失败事件,Pod处于就绪状态,不符合预期结果。

步骤二:为Nginx应用开启健康检查重定向

  1. 执行以下命令,编辑tcp-liveness.yaml文件。

    vim tcp-liveness.yaml

    tcp-liveness.yaml文件中template参数下添加以下内容:

    annotations:
      sidecar.istio.io/rewriteAppHTTPProbers: "true"

    以下为添加Annotation注解后的tcp-liveness.yaml文件:

    展开查看tcp-liveness.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      selector:
        matchLabels:
          app: nginx
      replicas: 1
      template:
        metadata:
          labels:
            app: nginx
          annotations:
            sidecar.istio.io/rewriteAppHTTPProbers: "true"
        spec:
          containers:
          - name: nginx
            image: nginx
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
            readinessProbe:
              tcpSocket:
                port: 2940
              initialDelaySeconds: 5
              periodSeconds: 3
  2. 执行以下命令,部署Nginx应用。

    kubectl apply -f tcp-liveness.yaml

步骤三:验证健康检查结果是否符合预期

  1. 查看应用的健康检查状态。

    1. 执行以下命令,查看Nginx应用的Pod名称。

      kubectl get pod| grep nginx
    2. 执行以下命令,查看Pod事件。

      kubectl describe pod <Pod名称>

      预期输出:

      Warning  Unhealthy  45s               kubelet            Readiness probe failed: HTTP probe failed with statuscode: 500

      可以看到返回结果中提示健康检查失败,符合预期。

  2. 执行以下命令,查看经过健康检查重定向的应用Pod YAML内容。

    kubectl get pod nginx-deployment-746458cdc9-m9t9q -o yaml

    展开查看预期输出

    apiVersion: v1
    kind: Pod
    metadata:
      ...
      name: nginx-deployment-746458cdc9-m9t9q
      namespace: default
      ...
    spec:
      containers:
        - args:
            - proxy
            - sidecar
            - '--domain'
            - $(POD_NAMESPACE).svc.cluster.local
            - '--proxyLogLevel=warning'
            - '--proxyComponentLogLevel=misc:error'
            - '--log_output_level=default:info'
            - '--concurrency'
            - '2'
          env:
            ...
            - name: ISTIO_KUBE_APP_PROBERS
              value: >-
                {"/app-health/nginx/readyz":{"tcpSocket":{"port":2940},"timeoutSeconds":1}}
          ...
        - image: nginx
          imagePullPolicy: IfNotPresent
          name: nginx
          ports:
            - containerPort: 80
              protocol: TCP
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /app-health/nginx/readyz
              port: 15020
              scheme: HTTP
            initialDelaySeconds: 5
            periodSeconds: 3
            successThreshold: 1
            timeoutSeconds: 1
          ...

    启用了健康检查重定向后,可以发现原先的TCP请求健康检查被改写为HTTP请求健康检查,健康检查端口由80改为15020,并配置了HTTP健康检查的路径为/app-health/nginx/readyz。同时,Pod中的Sidecar容器也会新增一个名为ISTIO_KUBE_APP_PROBERS的环境变量,其值为改写健康检查之前的TCP健康检查配置经过JSON序列化后的内容。

    对于TCP请求的健康检查,服务网格的健康检查重定向实际做了与HTTP请求的健康检查相同的处理,将其改写为一个15020端口的HTTP健康检查。同时在Pod内部,运行于Sidecar容器中的pilot-agent服务会开启监听15020端口,接收来自Kubelet服务的健康检查,并根据ISTIO_KUBE_APP_PROBERS环境变量中配置的TCP健康检查内容,对业务容器配置的TCP健康检查端口进行实际的探测。如果实际的TCP健康检查失败,pilot-agent服务会返回500状态码,以标识健康检查失败。