多集群故障排除

本页介绍如何解决部署到多个集群和/或网络的 Istio 问题。在阅读本页之前,请完成多集群安装步骤,并阅读部署模型指南。

跨集群负载均衡

多网络安装中最常见也是最广泛的问题是跨集群负载均衡不起作用。通常情况下,这会表现为只看到服务集群本地实例的响应。

$ for i in $(seq 10); do kubectl --context=$CTX_CLUSTER1 -n sample exec curl-dd98b5f48-djwdw -c curl -- curl -s helloworld:5000/hello; done
Hello version: v1, instance: helloworld-v1-578dd69f69-j69pf
Hello version: v1, instance: helloworld-v1-578dd69f69-j69pf
Hello version: v1, instance: helloworld-v1-578dd69f69-j69pf
...

按照验证多集群安装指南进行操作时,我们应该期望看到 v1v2 响应,这表示流量已发送到两个集群。

此问题可能有许多原因。

连接和防火墙问题

在某些环境中,可能无法明显地发现防火墙阻止了集群之间的流量。ICMP(ping)流量可能可以成功通过,但 HTTP 和其他类型的流量则无法通过。这可能表现为超时,或者在某些情况下表现为更令人困惑的错误,例如:

upstream connect error or disconnect/reset before headers. reset reason: local reset, transport failure reason: TLS error: 268435612:SSL routines:OPENSSL_internal:HTTP_REQUEST

虽然 Istio 提供服务发现功能以简化操作,但如果每个集群中的 Pod 位于同一个网络上,并且没有使用 Istio,跨集群流量仍应能成功通过。为了排除 TLS/mTLS 问题,可以使用没有 Istio 边车的 Pod 执行手动流量测试。

在每个集群中,为该测试创建一个新的命名空间。不要启用边车注入。

$ kubectl create --context="${CTX_CLUSTER1}" namespace uninjected-sample
$ kubectl create --context="${CTX_CLUSTER2}" namespace uninjected-sample

然后部署与验证多集群安装中使用的相同应用程序。

$ kubectl apply --context="${CTX_CLUSTER1}" \
    -f samples/helloworld/helloworld.yaml \
    -l service=helloworld -n uninjected-sample
$ kubectl apply --context="${CTX_CLUSTER2}" \
    -f samples/helloworld/helloworld.yaml \
    -l service=helloworld -n uninjected-sample
$ kubectl apply --context="${CTX_CLUSTER1}" \
    -f samples/helloworld/helloworld.yaml \
    -l version=v1 -n uninjected-sample
$ kubectl apply --context="${CTX_CLUSTER2}" \
    -f samples/helloworld/helloworld.yaml \
    -l version=v2 -n uninjected-sample
$ kubectl apply --context="${CTX_CLUSTER1}" \
    -f samples/curl/curl.yaml -n uninjected-sample
$ kubectl apply --context="${CTX_CLUSTER2}" \
    -f samples/curl/curl.yaml -n uninjected-sample

使用 -o wide 标志验证 cluster2 中是否运行着 helloworld Pod,以便我们可以获取 Pod IP。

$ kubectl --context="${CTX_CLUSTER2}" -n uninjected-sample get pod -o wide
NAME                             READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
curl-557747455f-jdsd8            1/1     Running   0          41s   10.100.0.2   node-2   <none>           <none>
helloworld-v2-54df5f84b-z28p5    1/1     Running   0          43s   10.100.0.1   node-1   <none>           <none>

记下 helloworldIP 列。在本例中,它是 10.100.0.1

$ REMOTE_POD_IP=10.100.0.1

接下来,尝试将流量从 cluster1 中的 curl Pod 直接发送到此 Pod IP。

$ kubectl exec --context="${CTX_CLUSTER1}" -n uninjected-sample -c curl \
    "$(kubectl get pod --context="${CTX_CLUSTER1}" -n uninjected-sample -l \
    app=curl -o jsonpath='{.items[0].metadata.name}')" \
    -- curl -sS $REMOTE_POD_IP:5000/hello
Hello version: v2, instance: helloworld-v2-54df5f84b-z28p5

如果成功,应该只收到来自 helloworld-v2 的响应。重复这些步骤,但将流量从 cluster2 发送到 cluster1

如果这成功了,则可以排除连接问题。如果未成功,则问题原因可能不在 Istio 配置范围内。

本地负载均衡

区域负载均衡可用于使客户端优先将流量发送到最近的目标。如果集群位于不同的区域(区域/区域),区域负载均衡将优先考虑本地集群,并且工作正常。如果禁用了区域负载均衡,或者集群位于同一区域,则可能存在其他问题。

信任配置

跨集群流量与集群内流量一样,依赖于代理之间共有的信任根。默认的 Istio 安装将使用其各自生成的根证书颁发机构。对于多集群,我们必须手动配置共享信任根。按照下面的“插入证书”操作进行操作,或阅读身份和信任模型了解详细信息。

插入证书

要验证证书是否配置正确,可以比较每个集群中的根证书。

$ diff \
   <(kubectl --context="${CTX_CLUSTER1}" -n istio-system get secret cacerts -ojsonpath='{.data.root-cert\.pem}') \
   <(kubectl --context="${CTX_CLUSTER2}" -n istio-system get secret cacerts -ojsonpath='{.data.root-cert\.pem}')

如果根证书不匹配,或者根本不存在该机密,则可以按照插入 CA 证书指南进行操作,确保对每个集群都运行这些步骤。

分步诊断

如果您已经完成了上述部分,但仍然遇到问题,则需要深入调查。

以下步骤假设您按照HelloWorld 验证进行操作。在继续之前,请确保 helloworldcurl 都已部署到每个集群中。

从每个集群中查找 curl 服务针对 helloworld 的端点。

$ istioctl --context $CTX_CLUSTER1 proxy-config endpoint curl-dd98b5f48-djwdw.sample | grep helloworld

故障排除信息因流量源集群而异

$ istioctl --context $CTX_CLUSTER1 proxy-config endpoint curl-dd98b5f48-djwdw.sample | grep helloworld
10.0.0.11:5000                   HEALTHY     OK                outbound|5000||helloworld.sample.svc.cluster.local

仅显示一个端点,表示控制平面无法从远程集群读取端点。验证是否已正确配置远程机密。

$ kubectl get secrets --context=$CTX_CLUSTER1 -n istio-system -l "istio/multiCluster=true"
  • 如果缺少机密,请创建它。
  • 如果机密存在
    • 查看机密中的配置。确保集群名称用作远程 kubeconfig 的数据键。
    • 如果机密看起来正确,请检查 istiod 的日志,以查找连接或权限问题,这些问题会导致无法访问远程 Kubernetes API 服务器。日志消息可能包含 Failed to add remote cluster from secret 以及错误原因。
这些信息有用吗?
您有什么改进建议吗?

感谢您的反馈!