一、前言
什么是 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规则生效有延迟(参考 Istio文档 )
三、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
- 一个命名为
gw1
的Gateway
对象,其主机名是service1.test.com
,selector
定义为istio: ingressgateway
,使用网关加载的证书来进行 TLS 认证
- 一个命名为
gw2
的Gateway
对象,其主机名是service2.test.com
,selector
定义为istio: ingressgateway
,使用网关加载的证书来进行 TLS 认证
- 名为
vs1
的VirtaulService
对象,主机名为service1.test.com
,网关设置为gw1
- 名为
vs2
的VirtaulService
对象,主机名为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
对象,而不是分别配置两个 gw1
和 gw2
。例如下面的配置:
- 创建一个名为
gw
的Gateway
,对应主机为*.test.com
,selector 仍然是istio: ingressgateway
,TLS 还是使用网关加载的证书。
VirtualService
对象vs1
配置主机名为service1.test.com
,网关设置为gw
VirtualService
对象vs2
配置主机名为service2.test.com
,网关设置为gw