解决 Cloud Service Mesh 中的代理问题
本文档介绍了常见的 Cloud Service Mesh 问题以及如何解决这些问题。如果您需要其他帮助,请参阅获取支持。
使用 Istio 访问端点时连接被拒
从集群到端点的通信时,您可能会遇到间歇性连接遭拒 (ECONNREFUSED
) 错误,例如 Memorystore Redis、CloudSQL 或应用工作负载需要访问的任何外部服务。
当应用工作负载启动速度快于 istio-proxy (Envoy
) 容器并尝试访问外部端点时,可能会发生这种情况。由于此阶段 istio-init (initContainer
) 已执行,因此存在的 iptables 规则会将所有传出流量重定向到 Envoy
。由于 istio-proxy 尚未准备就绪,iptables 规则会将流量重定向到尚未启动的边车代理并因此应用会收到 ECONNREFUSED
错误。
以下步骤详细介绍了如何检查是否遇到此错误:
使用以下过滤条件检查 Stackdriver 日志,以识别出现问题的 pod。
以下示例展示了典型的错误消息:
Error: failed to create connection to feature-store redis, err=dial tcp 192.168.9.16:19209: connect: connection refused [ioredis] Unhandled error event: Error: connect ECONNREFUSED
搜索问题发生实例。如果您使用的是旧版 Stackdriver,请使用
resource.type="container"
。resource.type="k8s_container" textPayload:"$ERROR_MESSAGE$"
展开最近的发生实例以获取 pod 的名称,然后记下
resource.labels
下的pod_name
。获取该 pod 的第一次问题:
resource.type="k8s_container" resource.labels.pod_name="$POD_NAME$"
输出示例:
E 2020-03-31T10:41:15.552128897Z post-feature-service post-feature-service-v1-67d56cdd-g7fvb failed to create connection to feature-store redis, err=dial tcp 192.168.9.16:19209: connect: connection refused post-feature-service post-feature-service-v1-67d56cdd-g7fvb
记下此 pod 的第一个错误的时间戳。
使用以下过滤条件查看 pod 启动事件。
resource.type="k8s_container" resource.labels.pod_name="$POD_NAME$"
输出示例:
I 2020-03-31T10:41:15Z spec.containers{istio-proxy} Container image "docker.io/istio/proxyv2:1.3.3" already present on machine spec.containers{istio-proxy} I 2020-03-31T10:41:15Z spec.containers{istio-proxy} Created container spec.containers{istio-proxy} I 2020-03-31T10:41:15Z spec.containers{istio-proxy} Started container spec.containers{istio-proxy} I 2020-03-31T10:41:15Z spec.containers{APP-CONTAINER-NAME} Created container spec.containers{APP-CONTAINER-NAME} W 2020-03-31T10:41:17Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503 spec.containers{istio-proxy} W 2020-03-31T10:41:26Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503 spec.containers{istio-proxy} W 2020-03-31T10:41:28Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503 spec.containers{istio-proxy} W 2020-03-31T10:41:31Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503 spec.containers{istio-proxy} W 2020-03-31T10:41:58Z spec.containers{istio-proxy} Readiness probe failed: HTTP probe failed with statuscode: 503 spec.containers{istio-proxy}
使用错误的时间戳和 istio-proxy 启动事件,以确认
Envoy
未准备就绪时发生的错误。如果 istio-proxy 容器尚未准备就绪时发生错误,则获取连接遭拒错误是正常的。在前面的示例中,pod 一旦
2020-03-31T10:41:15.552128897Z
就尝试连接到 Redis,但2020-03-31T10:41:58Z
istio-proxy 仍未通过就绪性探测。即使 istio-proxy 容器首先启动,它也可能在应用尝试连接到外部端点之前尚未足够快。
如果您遇到此问题,请继续执行以下问题排查步骤。
在 pod 级层为配置添加注释。这仅在 Pod 级层提供,在全局级层不可用。
annotations: proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
修改应用代码,使其在尝试向外部服务发出任何其他请求之前检查
Envoy
是否已准备就绪。例如,在应用启动时,启动向 istio-proxy 运行状况端点发出请求的循环,并且仅在获得 200 时继续。istio-proxy 运行状况端点如下所示:http://localhost:15020/healthz/ready
Vault 和 Istio 之间的边车注入期间的竞争条件
使用 vault
进行 Secret 管理时,有时 vault
会在 istio
之前注入边车,从而导致 Pod 卡在 Init
状态。发生这种情况时,创建的 Pod 会在重启任何部署或部署新部署后卡在 Init 状态。例如:
E 2020-03-31T10:41:15.552128897Z
post-feature-service post-feature-service-v1-67d56cdd-g7fvb failed to create
connection to feature-store redis, err=dial tcp 192.168.9.16:19209: connect:
connection refused post-feature-service post-feature-service-v1-67d56cdd-g7fvb
此问题是由竞态条件引起的,Istio 和 vault
都会注入边车,Istio 必须是最后执行此操作,istio
代理在 init 容器期间未运行。istio
init 容器设置 iptables 规则以将所有流量重定向到代理。由于这些规则尚未运行,因此这些规则不会重定向到任何规则,从而阻止所有流量。这就是 init 容器必须位于最后的原因,因此在设置 iptables 规则后,代理会立即启动并运行。遗憾的是,顺序是不确定的,因此如果先注入 Istio,则会中断。
如需排查这种情况,请允许 vault
的 IP 地址,以便流向 Vault IP 的流量尚未重定向到 Envoy 代理,而 Envoy 代理尚未准备就绪,因此阻止通信。为此,应该添加一个名为 excludeOutboundIPRanges
的新注释。
对于代管式 Cloud Service Mesh,只能在 Deployment 或 Pod 级层的 spec.template.metadata.annotations
下执行此操作,例如:
apiVersion: apps/v1
kind: Deployment
...
...
...
spec:
template:
metadata:
annotations:
traffic.sidecar.istio.io/excludeOutboundIPRanges:
对于集群内 Cloud Service Mesh,您可以选择在 spec.values.global.proxy.excludeIPRanges
下将其 IstioOperator 设置为全局项,例如:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
values:
global:
proxy:
excludeIPRanges: ""
添加注释后,重启工作负载。