一.模块概览

本模块介绍了在使用 Istio 时可能遇到的问题的几种排查方法。

二.Envoy基础

2.1 Envoy 基础

为了排除 Istio 的问题,对 Envoy 的工作原理有一个基本的了解是很有帮助的。Envoy 配置是一个 JSON 文件,分为多个部分。我们需要了解 Envoy 的基本概念是监听器、路由、集群和端点。

这些概念映射到 Istio 和 Kubernetes 资源,Envoy 概念与 Istio 和 Kubernetes 的映射如下图所示:

监听器是命名的网络位置,通常是一个 IP 和端口。Envoy 对这些位置进行监听,这是它接收连接和请求的地方

每个 sidecar 都有多个监听器生成。每个 sidecar 都有一个监听器,它被绑定到 0.0.0.0:15006。这是 IP Tables 将所有入站流量发送到 Pod 的地址。第二个监听器被绑定到 0.0.0.0:15001,这是所有从 Pod 中出站的流量地址

当一个请求被重定向(使用 IP Tables 配置)到 15001 端口时,监听器会把它交给与请求的原始目的地最匹配的虚拟监听器。如果它找不到目的地,它就根据配置的 OutboundTrafficPolicy 来发送流量。默认情况下,请求被发送到 PassthroughCluster,该集群连接到应用程序选择的目的地,Envoy 没有进行任何负载均衡。

三.Envoy示例

让我们以 Web 前端和 customers 服务为例,看看 Envoy 如何确定将请求从 Web 前端发送到 customers 服务(customers.default.svc.cluster.local)的位置。使用 istioctl proxy-config 命令,我们可以列出 web 前端 pod 的所有监听器。

 $ istioctl proxy-config listeners web-frontend-64455cd4c6-p6ft2
ADDRESS PORT MATCH DESTINATION
10.124.0.10 53 ALL Cluster: outbound|53||kube-dns.kube-system.svc.cluster.local
0.0.0.0 80 ALL PassthroughCluster
10.124.0.1 443 ALL Cluster: outbound|443||kubernetes.default.svc.cluster.local
10.124.3.113 443 ALL Cluster: outbound|443||istiod.istio-system.svc.cluster.local
10.124.7.154 443 ALL Cluster: outbound|443||metrics-server.kube-system.svc.cluster.local
10.124.7.237 443 ALL Cluster: outbound|443||istio-egressgateway.istio-system.svc.cluster.local
10.124.8.250 443 ALL Cluster: outbound|443||istio-ingressgateway.istio-system.svc.cluster.local
10.124.3.113 853 ALL Cluster: outbound|853||istiod.istio-system.svc.cluster.local
0.0.0.0 8383 ALL PassthroughCluster
0.0.0.0 15001 ALL PassthroughCluster
0.0.0.0 15006 ALL Inline Route: /*
0.0.0.0 15010 ALL PassthroughCluster
10.124.3.113 15012 ALL Cluster: outbound|15012||istiod.istio-system.svc.cluster.local
0.0.0.0 15014 ALL PassthroughCluster
0.0.0.0 15021 ALL Non-HTTP/Non-TCP
10.124.8.250 15021 ALL Cluster: outbound|15021||istio-ingressgateway.istio-system.svc.cluster.local
0.0.0.0 15090 ALL Non-HTTP/Non-TCP
10.124.7.237 15443 ALL Cluster: outbound|15443||istio-egressgateway.istio-system.svc.cluster.local
10.124.8.250 15443 ALL Cluster: outbound|15443||istio-ingressgateway.istio-system.svc.cluster.local
10.124.8.250 31400 ALL Cluster: outbound|31400||istio-ingressgateway.istio-system.svc.cluster.local

从 Web 前端到 customers 的请求是一个向外的 HTTP 请求,端口为 80。这意味着它被移交给了0.0.0.0:80的虚拟监听器。我们可以使用 Istio CLI 按地址和端口来过滤监听器。你可以添加 -o json 来获得监听器的 JSON 表示:

 $ istioctl proxy-config listeners web-frontend-58d497b6f8-lwqkg --address 0.0.0.0 --port 80 -o json
...
"rds": {
"configSource": {"ads": {},
"resourceApiVersion": "V3"
},
"routeConfigName": "80"
},
...

Listener 使用 RDS(路由发现服务)来寻找路由配置(在我们的例子中是 80)。路由附属于监听器,包含将虚拟主机映射到集群的规则。这允许我们创建流量路由规则,因为 Envoy 可以查看头文件或路径(请求元数据)并对流量进行路由。

路由(route)选择集群(cluster)。集群是一组接受流量的类似的上游主机 —— 它是一个端点的集合。例如,Web 前端服务的所有实例的集合就是一个集群。我们可以在一个集群内配置弹性功能,如断路器、离群检测和 TLS 配置。

使用 routes 命令,我们可以通过名称过滤所有的路由来获得路由的详细信息

 $ istioctl proxy-config routes web-frontend-58d497b6f8-lwqkg --name 80 -o json

 [
{
"name": "80",
"virtualHosts": [
{
"name": "customers.default.svc.cluster.local:80",
"domains": [
"customers.default.svc.cluster.local",
"customers.default.svc.cluster.local:80",
"customers",
"customers:80",
"customers.default.svc.cluster",
"customers.default.svc.cluster:80",
"customers.default.svc",
"customers.default.svc:80",
"customers.default",
"customers.default:80",
"10.124.4.23",
"10.124.4.23:80"
],
],
"routes": [
{
"match": {"prefix": "/"},
"route": {
"cluster": "outbound|80|v1|customers.default.svc.cluster.local",
"timeout": "0s",
"retryPolicy": {
"retryOn": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
"numRetries": 2,
"retryHostPredicate": [
{"name": "envoy.retry_host_predicates.previous_hosts"}
],
"hostSelectionRetryMaxAttempts": "5",
"retriableStatusCodes": [503]
},
"maxGrpcTimeout": "0s"
},
...

路由 80 配置为每个服务都有一个虚拟主机。然而,由于我们的请求被发送到 customers.default.svc.cluster.local,Envoy 会选择与其中一个域匹配的虚拟主机(customers.default.svc.cluster.local:80)。

一旦域被匹配,Envoy 就会查看路由,并选择第一个匹配请求的路由。由于我们没有定义任何特殊的路由规则,它匹配第一个(也是唯一的)定义的路由,并指示 Envoy 将请求发送到名为 outbound|80|v1|customers.default.svc.cluster.local 的集群。

注意集群名称中的 v1 是因为我们部署了一个 DestinationRule 来创建 v1 子集。如果一个服务没有子集,这部分就留空:outbound|80||customers.default.svc.cluster.local

现在我们有了集群的名称,我们可以查询更多的细节。为了得到一个清楚显示 FQDN、端口、子集和其他信息的输出,你可以省略 -o json 标志。

 $ istioctl proxy-config cluster web-frontend-58d497b6f8-lwqkg --fqdn customers.default.svc.cluster.local
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
customers.default.svc.cluster.local 80 - outbound EDS customers.default
customers.default.svc.cluster.local 80 v1 outbound EDS customers.default

最后,使用集群的名称,我们可以查询请求最终将到达的实际端点:

 $ istioctl proxy-config endpoints web-frontend-58d497b6f8-lwqkg --cluster "outbound|80|v1|customers.default.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.120.0.4:3000 HEALTHY OK outbound|80|v1|customers.default.svc.cluster.local

端点地址等于 customers 应用程序正在运行的 pod IP。如果我们扩展 customers 的部署,额外的端点会出现在输出中,像这样:

 $ istioctl proxy-config endpoints web-frontend-58d497b6f8-lwqkg --cluster "outbound|80|v1|customers.default.svc.cluster.local"
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.120.0.4:3000 HEALTHY OK outbound|80|v1|customers.default.svc.cluster.local
10.120.3.2:3000 HEALTHY OK outbound|80|v1|customers.default.svc.cluster.local

我们也可以用下图来形象地说明上述流程。

四.调试备忘录

每当你遇到配置问题时,你可以使用这组步骤来浏览和解决问题。在第一部分,我们要检查配置是否有效。如果配置是有效的,下一步就是看看运行时是如何处理配置的,为此,你需要对 Envoy 配置有基本的了解。

4.1 配置

1. 配置是否有效?

Istio CLI 有一个叫 validate 的命令,我们可以用它来验证 YAML 配置。YAML 最常见的问题是缩进和数组符号相关的问题。要验证一个配置,请将 YAML 文件传递给 validate 命令,像这样:

 $ istioctl validate -f myresource.yaml
validation succeed

如果资源是无效的,CLI 会给我们一个详细的错误。例如,如果我们拼错了一个字段名:

 unknown field "worloadSelector" in v1alpha3.ServiceEntry

我们可以使用另一个命令istioctl analyze。使用这个命令,我们可以检测 Istio 配置的潜在问题。我们可以针对本地的一组配置文件或实时集群运行它。同时,寻找来自 istiod 的任何警告或错误。

下面是该命令的一个输出样本,它捕捉到了目的地主机名称中的一个错字:

 $ istioctl analyze
Error [IST0101] (VirtualService customers.default) Referenced host not found: "cusomers.default.svc.cluster.local"
Error [IST0101] (VirtualService customers.default) Referenced host+subset in destinationrule not found: "cusomers.default.svc.cluster.local+v1"
Error: Analyzers found issues when analyzing namespace: default.
See https://istio.io/docs/reference/config/analysis for more information about causes and resolutions.

2. 命名是否正确?资源是否在正确的命名空间?

几乎所有的 Istio 资源都是命名空间范围的。确保它们与你正在处理的服务处于同一命名空间。将 Istio 资源放在同一命名空间中尤其重要,因为选择器也是有命名空间的。

一个常见的错误配置是在应用程序的命名空间中发布 VirtualService(例如 default),然后使用 istio: ingressgateway 选择器来绑定到 istio-system 命名空间中的 ingress 网关部署。这只有在你的 VirtualService 也在 istio-system 命名空间中时才有效。

同样地,不要在 istio-system 命名空间中部署引用应用程序命名空间中的 VirtualService 的 Sidecar 资源。相反,为每个需要入口的应用程序部署一组 Envoy 网关。

3. 资源选择器是否正确?

验证部署中的 pod 是否有正确的标签设置。正如上一步提到的,资源选择器与资源发布的命名空间绑定。

在这一点上,我们应该有理由相信,配置是正确的。接下来的步骤是进一步研究运行时系统是如何处理配置的。

4.2 运行时

Istio CLI 的一个实验性功能可以提供信息,帮助我们了解影响 Pod 或服务的配置。下面是一个针对 Pod 运行 describe 命令的例子,这个 Pod 的主机名称中有一个错字:

 $ istioctl x describe pod customers-v1-64455cd4c6-xvjzm.default
Pod: customers-v1-64455cd4c6-xvjzm
Pod Ports: 3000 (svc), 15090 (istio-proxy)
--------------------
Service: customers
Port: http 80/HTTP targets pod port 3000
DestinationRule: customers for "customers.default.svc.cluster.local"
Matching subsets: v1
No Traffic Policy
VirtualService: customers
WARNING: No destinations match pod subsets (checked 1 HTTP routes)
Route to cusomers.default.svc.cluster.local

1. Envoy 是否接受(ACK)该配置?

你可以使用 istioctl proxy-status 命令来检查状态,看看 Envoy 是否接受配置。我们希望所有东西的状态都设置为 SYNCHED。任何其他值都可能表明有错误,你应该检查 Pilot 的日志。

 $ istioctl proxy-status
NAME CDS LDS EDS RDS ISTIOD VERSION
customers-v1... SYNCED SYNCED SYNCED SYNCED istiod-67b4c76c6-8lwxf 1.9.0
customers-v1... SYNCED SYNCED SYNCED SYNCED istiod-67b4c76c6-8lwxf 1.9.0
istio-egress... SYNCED SYNCED SYNCED NOT SENT istiod-67b4c76c6-8lwxf 1.9.0
istio-ingress... SYNCED SYNCED SYNCED SYNCED istiod-67b4c76c6-8lwxf 1.9.0
web-frontend-... SYNCED SYNCED SYNCED SYNCED istiod-67b4c76c6-8lwxf 1.9.0

列表显示所有连接到 Pilot 实例的代理。如果列表中缺少一个代理,这意味着它没有连接到 Pilot,也没有收到任何配置。如果任何一个代理被标记为STALE,可能有网络问题,或者我们需要扩展 Pilot。

如果 Envoy 接受了配置,但我们仍然看到问题,我们需要确保配置在 Envoy 中的表现符合预期。

2. 配置在 Envoy 中的表现和预期的一样吗?

我们可以使用 proxy-config 命令来检索特定 Envoy 实例的信息。请参考下面的表格,我们可以检索不同的代理配置。

命令 描述
istioctl proxy-config cluster [POD] -n [NAMESPACE] 检索 cluster 配置
istioctl proxy-config bootstrap [POD] -n [NAMESPACE] 检索 bootstrap 配置
istioctl proxy-config listener [POD] -n [NAMESPACE] 检索 listener 配置
istioctl proxy-config route [POD] -n [NAMESPACE] 检索 route 配置
istioctl proxy-config endpoints [POD] -n [NAMESPACE] 检索 endpoint 配置

该命令从 Envoy 的管理端点(主要是 /config_dump)收集数据,它包含了很多有用的信息

另外,请参考显示 Envoy 和 Istio 资源之间映射的图。例如,许多 VirtualService 规则将表现为 Envoy 路由,而 DestinationRules 和 ServiceEntries 则表现为 Cluster。

DestinationRules 不会出现在配置中,除非其主机的 ServiceEntry 首先存在。

让我们以客户的 VirtualService 为例。

 apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: customers
spec:
hosts:
- 'customers.default.svc.cluster.local'
http:
- route:
- destination:
host: customers.default.svc.cluster.local
port:
number: 80
subset: v1
weight: 80
- destination:
host: customers.default.svc.cluster.local
port:
number: 80
subset: v2
weight: 20
timeout: 5s

如果你运行 istioctl proxy-config routes [POD] -o json 命令,你会看到加权目的地和超时是如何在配置中体现的:

 ..
{
"name": "80",
"virtualHosts": [
{
"name": "customers.default.svc.cluster.local:80",
"domains": [
"customers.default.svc.cluster.local",
...
],
"routes": [
{
"match": {"prefix": "/"},
"route": {
"weightedClusters": {
"clusters": [
{
"name": "outbound|80|v1|customers.default.svc.cluster.local",
"weight": 80
},
{
"name": "outbound|80|v2|customers.default.svc.cluster.local",
"weight": 20
}
]
},
"timeout": "5s",
...

当你评估 VirtualService 时,你要寻找主机名是否像你写的那样出现在 Envoy 配置中(例如customers.default.svc.cluster.local),以及路由是否存在(见输出中的 80-20 流量分割)。你也可以使用之前的例子,通过监听器、路由和集群(和端点)来追踪调用。

Envoy 过滤器会表现在你告诉 Istio 把它们放在哪里(EnvoyFilter 资源中的 applyTo 字段)。通常情况下,一个坏的过滤器会表现为 Envoy 拒绝配置(即不显示 SYNCED 状态)。在这种情况下,你需要检查 Istiod 日志中的错误。

3. Istiod(Pilot)中是否有错误?

从 Pilot 查看错误的最快方法是跟踪日志(使用 --follow 标志),然后应用配置。下面是一个来自 Pilot 的错误的例子,这是由于过滤器的内联代码中的一个错字而导致的。

 2020-11-20T21:49:16.017487Z     warn    ads     ADS:LDS: ACK ERROR sidecar~10.120.1.8~web-frontend-58d497b6f8-lwqkg.default~default.svc.cluster.local-4 Internal:Error adding/updating listener (s) virtualInbound: script load error: [string"fction envoy_on_response (response_handle)..."]:1: '=' expected near 'envoy_on_response'

如果配置根本没有出现在 Envoy 中(Envoy 没有 ACK 它),或者它是一个 EnvoyFilter 配置,那么这个配置很可能是无效的。Istio 无法从语法上验证 EnvoyFilter 内部的配置。另一个问题可能是,过滤器在 Envoy 的配置中位于错误的位置。

无论哪种情况,Envoy 都会拒绝该配置,因为它是无效的,Pilot 会记录这个错误。一般来说,你可以搜索你的资源的名称来找到错误。

在这里,你必须使用判断力来确定它是你写的配置中的错误,还是 Pilot 的错误导致它产生了一个无效的配置。

4.3 检查 Envoy 日志

要检查 Envoy 代理的日志,我们可以使用 kubectl logs 命令:

 kubectl logs PODNAME -c istio-proxy -n NAMESPACE

要了解访问日志的格式和响应标志,我们可以参考 Envoy 访问日志 的内容。

最常见的响应标志。

  • NR:没有配置路由,检查 DestinationRule 或 VirtualService。
  • UO:上游溢出并断路。检查 DestinationRule 中的断路器配置。
  • UF:上游连接失败,如果使用 Istio 认证,检查 mTLS 配置。
  • UH:没有健康的上游主机。

4.4 配置 istiod 日志

我们可以使用 ControlZ 仪表板,通过 Logging Scopes 菜单配置堆栈跟踪级别和日志级别。

要打开仪表板,请运行:

 istioctl dashboard controlz $(kubectl -n istio-system get pods -l app=istiod -o jsonpath='{.items [0].metadata.name}').istio-system

仪表板打开后,点击 Logging Scopes 选项,调整日志级别和堆栈跟踪级别。

Istio(十二):Istio问题排查的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格

    多运行时是一个非常新的概念.在 2020 年,Bilgin Ibryam 提出了 Multi-Runtime(多运行时)的理念,对基于 Sidecar 模式的各种产品形态进行了实践总结和理论升华.那到 ...

  2. Istio的流量管理(实操二)(istio 系列四)

    Istio的流量管理(实操二)(istio 系列四) 涵盖官方文档Traffic Management章节中的inrgess部分. 目录 Istio的流量管理(实操二)(istio 系列四) Ingr ...

  3. Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin【Finchley 版】

    Spring Cloud(十二):分布式链路跟踪 Sleuth 与 Zipkin[Finchley 版]  发表于 2018-04-24 |  随着业务发展,系统拆分导致系统调用链路愈发复杂一个前端请 ...

  4. FreeSql (三十二)Aop

    FreeSql AOP 已有的功能介绍,未来为会根据用户需求不断增强. 审计 CRUD 马云说过,996是修福报.对于多数程序员来说,加班是好事...起码不是闲人,不会下岗. 当如果因为某个 sql ...

  5. 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了!

    大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...

  6. Istio(九):istio安全之授权

    目录 一.模块概览 二.系统环境 三.istio授权 3.1 istio授权 3.2 来源 3.3 操作 3.4 条件 四.实战:授权(访问控制) 4.1 访问控制 4.2 清理 一.模块概览 在Ku ...

  7. 前端开发中SEO的十二条总结

    一. 合理使用title, description, keywords二. 合理使用h1 - h6, h1标签的权重很高, 注意使用频率三. 列表代码使用ul, 重要文字使用strong标签四. 图片 ...

  8. CRL快速开发框架系列教程十二(MongoDB支持)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. 我的MYSQL学习心得(十二) 触发器

    我的MYSQL学习心得(十二) 触发器 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数 ...

  10. Web 前端开发精华文章推荐(jQuery、HTML5、CSS3)【系列十二】

    2012年12月12日,[<Web 前端开发人员和设计师必读文章>系列十二]和大家见面了.梦想天空博客关注 前端开发 技术,分享各种增强网站用户体验的 jQuery 插件,展示前沿的 HT ...

随机推荐

  1. 从入门到精通:C++ 学习路线指南,附详细学习计划

    C++是一种高级编程语言,广泛用于开发操作系统.应用程序.游戏和各种工具.如果你想学习这门语言,以下是一个适合初学者的学习路线: 第一步:学习C++基础知识 在学习C++之前,你需要掌握一些基础知识, ...

  2. Python 元组完全指南2

    更新元组 更改元组的值 元组是不可更改的,但有一种变通方法.您可以将元组转换为列表,更改列表,然后将列表转换回元组. 示例: x = ("apple", "banana& ...

  3. openGauss 列存表PSort索引

    openGauss 列存表 PSort 索引 概述 PSort(Partial sort) Index 是在列存表的列上建的聚簇索引.CUDesc 上有每个 CU 的 min 和 max 值,但如果业 ...

  4. 开源在线表单工具 HeyForm 使用教程

    HeyForm 是一个非常出色的开源在线表单工具,可以通过直观的拖拽式编辑器,快速构建出美观实用的表单. HeyForm 的功能非常丰富: 支持丰富的输入类型,从基础的文本.数字到高级的图片选择.日期 ...

  5. Node中的EventEmitter? 如何实现一个EventEmitter?

    一.是什么 我们了解到,Node采用了事件驱动机制,而EventEmitter就是Node实现事件驱动的基础 在EventEmitter的基础上,Node几乎所有的模块都继承了这个类,这些模块拥有了自 ...

  6. Java学生信息管理系统源码

    学生信息管理系统 功能说明 学生信息管理,包括学生.班级.院系.课程.成绩等的管理. 本程序仅供学习食用. 工程环境 JDK IntelliJ IDEA MySQL 运行说明 1.安装JDK. 2.导 ...

  7. CentOS7.9 systemctl

    目录 命令格式 语法 加载配置文件 关机和开机 unit 文件存放位置 unit 格式说明 service unit file 文件构成部分 unit 段的常用选项 service 段的常用选项 in ...

  8. 学习 XQuery:XML数据查询的关键

    XQuery 是 XML 数据的查询语言,类似于 SQL 是数据库的查询语言.它被设计用于查询 XML 数据. XQuery 示例 for $x in doc("books.xml" ...

  9. ArcPy自动绘制大量地图并设置地图要素:Python

      本文介绍基于Python语言中ArcPy模块,实现ArcMap自动批量出图,并对地图要素进行自定义批量设置的方法. 1 任务需求   首先,我们来明确一下本文所需实现的需求.   现有通过Pyth ...

  10. CNCF 沙箱项目 OCM Placement 多集群调度指南

    ​简介:在这篇文章中,将介绍 Placement 如何选择到所需的集群,Placement 可以提供的调度功能,以及一些场景下的最佳实践,使用者可以参考示例来编写符合自己要求的 Placement.其 ...