diff --git a/content_zh/help/ops/traffic-management/observing/index.md b/content_zh/help/ops/traffic-management/observing/index.md index 22c4faf899..ec62deffc3 100644 --- a/content_zh/help/ops/traffic-management/observing/index.md +++ b/content_zh/help/ops/traffic-management/observing/index.md @@ -1,23 +1,287 @@ --- -title: 流量管理观测 -description: 描述观测流量管理或相关问题的工具和技术。 -weight: 5 +title: 配置问题诊断 +description: 介绍一些工具和技术,用来针对流量管理方面的配置问题进行诊断。 +weight: 40 +keywords: [debug,proxy,status,config,pilot,envoy] --- -## Envoy 在负载下 crash +Istio 提供了两个非常有价值的命令,用于协助对流量管理方面的配置问题进行诊断:[`proxy-status`](/docs/reference/commands/istioctl/#istioctl-proxy-status) 和 [`proxy-config`](/docs/reference/commands/istioctl/#istioctl-proxy-config)。 -检查 `ulimit -a`。很多系统默认文件描述符最大为 1024,会导致 Envoy 断言出错并 crash: +`proxy-status` 命令可以获取网格的概要信息,可以用来确定代理服务器导致的问题;而 `proxy-status` 命令则可以用来观察 Envoy 的配置并对问题进行诊断。 -{{< text plain >}} -[2017-05-17 03:00:52.735][14236][critical][assert] assert failure: fd_ != -1: external/envoy/source/common/network/connection_impl.cc:58 +要试用下面的命令,首先要满足下列两个条件中的一个: + +* 一个部署了 Istio 和 Bookinfo 的 Kubernetes 集群(例如使用[安装步骤](/zh/docs/setup/kubernetes/quick-start/#安装步骤)中所写的 `istio.yaml` 完成 Istio 的安装,并完成 [Bookinfo 应用部署](/zh/docs/examples/bookinfo/#如果在-kubernetes-中运行))。 + +或者 + +* Kubernetes 环境下的 Istio 网格上运行自己的应用。 + +## 获取网格的概要情况 + +`proxy-status` 命令能够用来获取网格的概要情况。如果怀疑某个 Sidecar 无法获取配置,或者同步失败,就可以用这个命令来进行验证。 + +{{< text bash >}} +$ istioctl proxy-status +PROXY CDS LDS EDS RDS PILOT +details-v1-6dcc6fbb9d-wsjz4.default SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-75bdf98789-tfdvh +istio-egressgateway-c49694485-l9d5l.istio-system SYNCED SYNCED SYNCED (100%) NOT SENT istio-pilot-75bdf98789-tfdvh +istio-ingress-6458b8c98f-7ks48.istio-system SYNCED SYNCED SYNCED (100%) NOT SENT istio-pilot-75bdf98789-n2kqh +istio-ingressgateway-7d6874b48f-qxhn5.istio-system SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-75bdf98789-n2kqh +productpage-v1-6c886ff494-hm7zk.default SYNCED SYNCED SYNCED (100%) STALE istio-pilot-75bdf98789-n2kqh +ratings-v1-5d9ff497bb-gslng.default SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-75bdf98789-n2kqh +reviews-v1-55d4c455db-zjj2m.default SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-75bdf98789-n2kqh +reviews-v2-686bbb668-99j76.default SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-75bdf98789-tfdvh +reviews-v3-7b9b5fdfd6-4r52s.default SYNCED SYNCED SYNCED (100%) SYNCED istio-pilot-75bdf98789-n2kqh {{< /text >}} -确保调整了最大限制值。例如:`ulimit -n 16384` +如果一个代理没有出现在这个列表上,就说明该代理目前没有连接到 Pilot 实例上,不会接到任何配置。 -## 为什么创建加权路由规则在两个版本的服务之间切分的流量不按权重工作? +* `SYNCED`:Envoy 已经接收到了 Pilot 发送的最新配置。 +* `SYNCED (100%)`:Envoy 成功的同步了集群内的所有端点。 +* `NOT SENT`:Pilot 尚未向 Envoy 发送任何数据,这通常是因为 Pilot 没有需要发送的内容。 +* `STALE`:Pilot 已经向 Envoy 发出了更新,但是还没有收到响应。这很可能意味着 Envoy 和 Pilot 之间的网络存在故障,或者是 Istio 自身的 Bug。 -当前 Envoy sidecar 的实现,可能需要多于 100 个请求才能观察到相应的分布。 +## 获取 Envoy 和 Istio Pilot 之间的配置差异 -## 为什么配置的路由规则不会立即生效? +`proxy-status` 命令还可以通过一个 Proxy ID 作为输入,来获取 Envoy 已经载入的配置和 Pilot 将要发送的配置之间的差异,这有助于识别同步失败的问题,并且对原因分析也有帮助。 -Kubernetes 上的 Istio 使用最终一致性的算法来确保所有 Envoy sidecar 配置生效,包括所有路由规则。配置变更需要花一定时间才能保证在全部的 sidecar 上生效。对于大型部署,最终生效将花费更长时间,并且可能存在秒级的延迟。 \ No newline at end of file +{{< text bash json >}} +$ istioctl proxy-status details-v1-6dcc6fbb9d-wsjz4.default +--- Pilot Clusters ++++ Envoy Clusters +@@ -374,36 +374,14 @@ + "edsClusterConfig": { + "edsConfig": { + "ads": { + + } + }, + "serviceName": "outbound|443||public-cr0bdc785ce3f14722918080a97e1f26be-alb1.kube-system.svc.cluster.local" +- }, +- "connectTimeout": "1.000s", +- "circuitBreakers": { +- "thresholds": [ +- { +- +- } +- ] +- } +- } +- }, +- { +- "cluster": { +- "name": "outbound|53||kube-dns.kube-system.svc.cluster.local", +- "type": "EDS", +- "edsClusterConfig": { +- "edsConfig": { +- "ads": { +- +- } +- }, +- "serviceName": "outbound|53||kube-dns.kube-system.svc.cluster.local" + }, + "connectTimeout": "1.000s", + "circuitBreakers": { + "thresholds": [ + { + + } + +Listeners Match +Routes Match +{{< /text >}} + +这些内容中不难发现,监听器和路由都是匹配的,但是集群定义未能同步。 + +## 深入了解 Envoy 配置 + +`proxy-config` 命令能够用来查看某个 Envoy 实例的配置。通过对 Istio 配置和自定义资源的查看不能确诊问题时,这个命令会大有帮助。要获取网格中一个 Pod 的集群、监听器和路由的概要信息,只要使用如下命令(可以根据需要把 `clusters` 替换为 `listeners` 或者 `routes`): + +{{< text bash >}} +$ istioctl proxy-config clusters -n istio-system istio-ingressgateway-7d6874b48f-qxhn5 +SERVICE FQDN PORT SUBSET DIRECTION TYPE +BlackHoleCluster - - - STATIC +details.default.svc.cluster.local 9080 - outbound EDS +heapster.kube-system.svc.cluster.local 80 - outbound EDS +istio-citadel.istio-system.svc.cluster.local 8060 - outbound EDS +istio-citadel.istio-system.svc.cluster.local 9093 - outbound EDS +istio-egressgateway.istio-system.svc.cluster.local 80 - outbound EDS +... +{{< /text >}} + +要对 Envoy 进行除错,首先要了解一下 Envoy 的集群、监听器、路由、端点的概念,以及这些对象之间的交互过程。我们会使用 `proxy-config` 命令的 `-o json` 参数,并对结果进行过滤,来跟踪 Envoy 对请求(从 `productpage` Pod 发向 `reviews` Pod 上的 `reviews:9080`)的决策过程: + +1. 如果查询一个 Pod 的监听器概要信息,会看到 Istio 生成了如下的监听器: + + * `0.0.0.0:15001` 的监听器会接收所有出入 Pod 的流量,然后将请求转交给一个虚拟监听器。 + * 服务 IP 的虚拟监听器,用于 TCP/HTTPS 的非 HTTP 出站流量。 + * Pod IP 的虚拟监听器,用于暴露入站流量的端口。 + * `0.0.0.0` 的虚拟监听器用于出站的 HTTP 流量。 + + {{< text bash >}} + $ istioctl proxy-config listeners productpage-v1-6c886ff494-7vxhs + ADDRESS PORT TYPE + 172.21.252.250 15005 TCP <--+ + 172.21.252.250 15011 TCP | + 172.21.79.56 42422 TCP | + 172.21.160.5 443 TCP | + 172.21.157.6 443 TCP | + 172.21.117.222 443 TCP | + 172.21.0.10 53 TCP | + 172.21.126.131 443 TCP | Receives outbound non-HTTP traffic for relevant IP:PORT pair from listener `0.0.0.0_15001` + 172.21.160.5 31400 TCP | + 172.21.81.159 9102 TCP | + 172.21.0.1 443 TCP | + 172.21.126.131 80 TCP | + 172.21.119.8 443 TCP | + 172.21.112.64 80 TCP | + 172.21.179.54 443 TCP | + 172.21.165.197 443 TCP <--+ + 0.0.0.0 9090 HTTP <-+ + 0.0.0.0 8060 HTTP | + 0.0.0.0 15010 HTTP | + 0.0.0.0 15003 HTTP | + 0.0.0.0 15004 HTTP | + 0.0.0.0 9093 HTTP | Receives outbound HTTP traffic for relevant port from listener `0.0.0.0_15001` + 0.0.0.0 15007 HTTP | + 0.0.0.0 8080 HTTP | + 0.0.0.0 9091 HTTP | + 0.0.0.0 9080 HTTP | + 0.0.0.0 80 HTTP <-+ + 0.0.0.0 15001 TCP // Receives all inbound and outbound traffic to the pod from IP tables and hands over to virtual listener + 172.30.164.190 9080 HTTP // Receives all inbound traffic on 9080 from listener `0.0.0.0_15001` + {{< /text >}} + +1. 由上边的概要信息可以看出,每个 Sidecar 都有一个绑定到 `0.0.0.0:15001` 的监听器,IP tables 会路由 Pod 中所有的入站和出站流量到这一地址。这个监听器的 `useOriginalDst` 设置为 True,表明他会根据原始目的地来选择监听器,并将流量转发给最合适的监听器。如果找不到匹配的虚拟监听器,就会把请求发送给 `BlackHoleCluster`,它会返回一个 404。 + + {{< text bash json >}} + $ istioctl proxy-config listeners productpage-v1-6c886ff494-7vxhs --port 15001 -o json + { + "name": "virtual", + "address": { + "socketAddress": { + "address": "0.0.0.0", + "portValue": 15001 + } + }, + "filterChains": [ + { + "filters": [ + { + "name": "envoy.tcp_proxy", + "config": { + "cluster": "BlackHoleCluster", + "stat_prefix": "BlackHoleCluster" + } + } + ] + } + ], + "useOriginalDst": true + } + {{< /text >}} + +1. 我们的请求是一个出站的 HTTP 请求,目标是 `9080`,因此这个请求应该提交给 `0.0.0.0:9080` 虚拟监听器。这个监听器会在它的 RDS 中查找路由配置,这个例子中,就是在 Pilot(通过 ADS)配置的 RDS 信息中查找 `9080`。 + + {{< text bash json >}} + $ istioctl proxy-config listeners productpage-v1-6c886ff494-7vxhs -o json --address 0.0.0.0 --port 9080 + ... + "rds": { + "config_source": { + "ads": {} + }, + "route_config_name": "9080" + } + ... + {{< /text >}} + +1. `9080` 路由配置在每个服务中只有一个虚拟主机。我们的请求是发向 `reviews` 服务的,所有 Envoy 会选择符合请求域名的虚拟主机。选定虚拟主机之后,Envoy 会选择匹配该请求的第一条路由。这里没有定义任何的高级路由,所以只有一个匹配所有请求的路由。这个路由告诉 Envoy 发送请求到 `outbound|9080||reviews.default.svc.cluster.local` 集群。 + + {{< text bash json >}} + $ istioctl proxy-config routes productpage-v1-6c886ff494-7vxhs --name 9080 -o json + [ + { + "name": "9080", + "virtualHosts": [ + { + "name": "reviews.default.svc.cluster.local:9080", + "domains": [ + "reviews.default.svc.cluster.local", + "reviews.default.svc.cluster.local:9080", + "reviews", + "reviews:9080", + "reviews.default.svc.cluster", + "reviews.default.svc.cluster:9080", + "reviews.default.svc", + "reviews.default.svc:9080", + "reviews.default", + "reviews.default:9080", + "172.21.152.34", + "172.21.152.34:9080" + ], + "routes": [ + { + "match": { + "prefix": "/" + }, + "route": { + "cluster": "outbound|9080||reviews.default.svc.cluster.local", + "timeout": "0.000s" + }, + ... + {{< /text >}} + +1. 这个集群被配置从 Pilot(通过 ADS)获取端点列表。所以 Envoy 会使用 `serviceName` 字段作为关键字在端点列表中进行查找,然后将请求转发给查出来的端点中的一个。 + + {{< text bash json >}} + $ istioctl proxy-config clusters productpage-v1-6c886ff494-7vxhs --fqdn reviews.default.svc.cluster.local -o json + [ + { + "name": "outbound|9080||reviews.default.svc.cluster.local", + "type": "EDS", + "edsClusterConfig": { + "edsConfig": { + "ads": {} + }, + "serviceName": "outbound|9080||reviews.default.svc.cluster.local" + }, + "connectTimeout": "1.000s", + "circuitBreakers": { + "thresholds": [ + {} + ] + } + } + ] + {{< /text >}} + +1. 可以使用 `proxy-config endpoints` 命令来查看当前集群的可用端点。 + + {{< text bash json >}} + $ istioctl proxy-config endpoints productpage-v1-6c886ff494-7vxhs --cluster outbound|9080||reviews.default.svc.cluster.local + ENDPOINT STATUS CLUSTER + 172.17.0.17:9080 HEALTHY outbound|9080||reviews.default.svc.cluster.local + 172.17.0.18:9080 HEALTHY outbound|9080||reviews.default.svc.cluster.local + 172.17.0.5:9080 HEALTHY outbound|9080||reviews.default.svc.cluster.local + {{< /text >}} + +## 观察启动配置 + +我们已经了解了不少关于(绝大多数)来自于 Pilot 的配置方面的内容,Envoy 自身还有一些启动配置,例如在哪里查找 Pilot。用下面的命令可以查看这些信息: + +{{< text bash json >}} +$ istioctl proxy-config bootstrap -n istio-system istio-ingressgateway-7d6874b48f-qxhn5 +{ + "bootstrap": { + "node": { + "id": "router~172.30.86.14~istio-ingressgateway-7d6874b48f-qxhn5.istio-system~istio-system.svc.cluster.local", + "cluster": "istio-ingressgateway", + "metadata": { + "POD_NAME": "istio-ingressgateway-7d6874b48f-qxhn5", + "istio": "sidecar" + }, + "buildVersion": "0/1.8.0-dev//RELEASE" + }, +... +{{< /text >}} \ No newline at end of file