效能平台-研发篇(四)—— Istio故障排查技巧

1,897 阅读4分钟

一、前言

什么是 Istio ?

Istio 是一个完全开源的服务网格,通过在 POD 中注入 sidecar 代理为服务添加 Istio 的支持,而代理会拦截微服务之间的所有网络通信,然后使用其控制平面的策略进行流量管理。

动态环境用到的 KtEnv 就是基于 Istio 实现的,本文将列出动态环境的一系列排错方法。

排错说明

以下示例中,假设虚拟环境实例所在的Namespace已经存在环境变量$NS

在排查各类问题前,请按照效能平台-研发篇(二)—— 基于KtEnv的路由染色方案 证KtEnv的CRD和Webhook组件已正确安装到集群中。

二、路由规则不符合预期问题排查

基础组件检查

1、检查目标Namespace中是否正确创建了VirtualEnvironment实例:

kubectl -n $NS get VirtualEnvironment

2、检查是否生成了预期的Istio资源。

对于每一个选中包含路由标签Pod的Service实例,应该生成一个同名的VirtualService实例和一个同名的DestinationRule实例。

# 假设路由标签名是virtual-env(这个名称是在创建VirtualEnvironment实例时候候配置的)
kubectl -n $NS get Pod -l virtual-env

3、列举参与路由隔离的Service与virtualservice资源进行比较:

# 这两种资源的数目应该相同,且与参与路由隔离的Service逐一同名对应
kubectl -n $NS get VirtualService
kubectl -n $NS get DestinationRule

若数目不正确,请检查目标Service对象的端口命名:

端口名称必须依据Istio文档要求采用<协议>[-<后缀>]结构。由于当前Istio仅支持对HTTP协议的消息进行精细路由控制,因此KtEnv仅会处理名称以http开头的端口。

kubectl -n $NS get Service <要路由的目标服务名> -o jsonpath='{.spec.ports}'

流量请求头格式检查

开启 Envoy 日志

建议使用 Telemetry 资源开启日志,配置如下。 更多方法请参考获取Envoy访问日志

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: mesh-default
  namespace: istio-system
spec:
  accessLogging:
    - providers:
      - name: envoy

我们手动向指定环境发送请求

下图为正常连接请求,可以看到可以自动拼接到正确的域名

下面我看下方红色为异常的请求,黄色为正常请求,可以看到异常请求的域名值为"-" 并没有匹配到指定的环境,该流量会根据service机制进行随机负载。

导致这个问题的原因:请求中缺少带有服务名称的请求头Host:Host:格式不对,这会导致流量绕过 Istio 的路由规则。

参考:alibaba.github.io/virtual-env…

以下是其他几种比较常见的错误原因:

  • 同一个Pod被多个Service选中。当前Istio不支持一个Pod同时属于多个Service的情况

三、Istio virtualservice 配置问题排查

1、corsPolicy.allowOrigin 跨域规则不生效

问题描述:

参照官方扩展路由规则你可能会遇到corsPolicy.allowOrigins跨域属性不生效。

解决方法:

这是因为 KtEnv 采用了 v1alpha3 而不是 v1beta1 ,应该使用corsPolicy.allowOrigin,完整的跨域配置经参考下方代码。

{
        "Match": [{
                "Uri": {
                        "Prefix": "/"
                }
        }],
        "corsPolicy": {
                "allowOrigin": ["*"],
                "allowCredentials": true,
                "allowHeaders": ["demo-key", "ali-env-mark"],
                "allowMethods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
        }
}

2、更新 annotations 路由规则后 virtualservice 配置未更新

问题描述:

KtEnv 不会监听 annotations 状态变化去主动更新 virtualservice 需要手动更新。

解决方法:

参考下方命令

kubectl delete  virtualservice.networking.istio.io some-services -n $NS

3、多个网关共用同一个 TLS 证书时引起浏览器404问题

参考来源: github.com/istio/istio…

问题描述:

多个网关共用一个 TLS 证书时,如果使用支持 HTTP/2 连接复用的浏览器(多数浏览器都支持这一能力)来进行访问,在和第一个主机名建立连接之后,如果继续访问另一个主机名,就会出现 404 错误。

举个例子,假设有两个主机用这种方式来共享同样的 TLS 证书:

  • 安装在 istio-ingressgateway 上的通配符证书:*.test.com
  • 一个命名为 gw1Gateway 对象,其主机名是 service1.test.comselector 定义为 istio: ingressgateway,使用网关加载的证书来进行 TLS 认证
  • 一个命名为 gw2Gateway 对象,其主机名是 service2.test.comselector 定义为 istio: ingressgateway,使用网关加载的证书来进行 TLS 认证
  • 名为 vs1VirtaulService 对象,主机名为 service1.test.com,网关设置为 gw1
  • 名为 vs2VirtaulService 对象,主机名为 service2.test.com,网关设置为 gw2

两个网关对象使用的是一组工作负载(istio: ingressgateway),用同样的 IP 为两个服务提供网关支持。如果首先访问了 service1.test.com,会返回通配符证书 *.test.com,这一证书是可以用于连接 service2.test.com 的。Chrome 或者 Firefox 这样的浏览器会复用这已经存在的连接,来发起对 service2.test.com 的访问,但是 gw1 没有到 service2.test.com 的路由,所以就会返回 404 错误。

解决方法:

要解决这一问题,可以配置一个通用的 Gateway 对象,而不是分别配置两个 gw1gw2。例如下面的配置:

  • 创建一个名为 gwGateway,对应主机为 *.test.com,selector 仍然是 istio: ingressgateway,TLS 还是使用网关加载的证书。
  • VirtualService 对象 vs1 配置主机名为 service1.test.com,网关设置为 gw
  • VirtualService 对象 vs2 配置主机名为 service2.test.com,网关设置为 gw

四、参考文档

KtEnv 适配 spring-cloud
KtEnv 扩展路由规则
Istio 获取Envoy访问日志
Istio 路由规则下发延迟
Istio 协议选择
spring-cloud-kubernetes-with-istio
404 NR when using browser on multiple ingress gateways