多叢集疑難排解
本頁說明如何疑難排解在多個叢集和/或網路中部署 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
...
當遵循驗證多叢集安裝的指南時,我們預期會收到 v1
和 v2
的回應,這表示流量正在傳送到兩個叢集。
此問題可能有多種原因。
連線和防火牆問題
在某些環境中,防火牆可能正在封鎖叢集之間的流量,這可能不明顯。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 sidecar 的 Pod 進行手動流量測試。
在每個叢集中,為此測試建立一個新的命名空間。不要啟用 sidecar 注入。
$ 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>
記下 helloworld
的 IP
欄位。在這個例子中,它是 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 設定之外。
本地負載平衡
本地性負載平衡可以用來讓客戶端偏好將流量傳送到最近的目的地。如果叢集位於不同的區域(region/zone),本地性負載平衡會偏好本地叢集,並且會按照預期運作。如果本地性負載平衡已停用,或叢集位於同一區域,則可能存在其他問題。
信任設定
跨叢集流量,如同叢集內流量一樣,依賴於 Proxy 之間的共同信任根。預設的 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}')
如果根憑證不符或 Secret 根本不存在,您可以遵循外掛 CA 憑證指南,並確保對每個叢集執行這些步驟。
逐步診斷
如果您已完成以上各節並且仍然遇到問題,那麼是時候深入挖掘了。
以下步驟假設您正在遵循HelloWorld 驗證。在繼續之前,請確保 helloworld
和 curl
都已部署在每個叢集中。
從每個叢集中,找到 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
只顯示一個端點,表示控制平面無法讀取遠端叢集的端點。驗證遠端 Secret 是否已正確設定。
$ kubectl get secrets --context=$CTX_CLUSTER1 -n istio-system -l "istio/multiCluster=true"
- 如果 Secret 遺失,請建立它。
- 如果 Secret 存在
- 查看 Secret 中的設定。請確保叢集名稱用作遠端
kubeconfig
的資料金鑰。 - 如果 Secret 看起來正確,請檢查
istiod
的日誌,以了解連線或存取遠端 Kubernetes API 伺服器的權限問題。日誌訊息可能包含Failed to add remote cluster from secret
以及錯誤原因。
- 查看 Secret 中的設定。請確保叢集名稱用作遠端
$ istioctl --context $CTX_CLUSTER2 proxy-config endpoint curl-dd98b5f48-djwdw.sample | grep helloworld
10.0.1.11:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
只顯示一個端點,表示控制平面無法讀取遠端叢集的端點。驗證遠端 Secret 是否已正確設定。
$ kubectl get secrets --context=$CTX_CLUSTER1 -n istio-system -l "istio/multiCluster=true"
- 如果 Secret 遺失,請建立它。
- 如果 Secret 存在且端點是主要叢集中的 Pod。
- 查看 Secret 中的設定。請確保叢集名稱用作遠端
kubeconfig
的資料金鑰。 - 如果 Secret 看起來正確,請檢查
istiod
的日誌,以了解連線或存取遠端 Kubernetes API 伺服器的權限問題。日誌訊息可能包含Failed to add remote cluster from secret
以及錯誤原因。
- 查看 Secret 中的設定。請確保叢集名稱用作遠端
- 如果 Secret 存在且端點是遠端叢集中的 Pod。
- Proxy 正在讀取遠端叢集中 Istiod 的設定。當遠端叢集具有叢集內 Istiod 時,它僅用於 sidecar 注入和 CA。您可以透過在
istio-system
命名空間中尋找名為istiod-remote
的 Service 來驗證這是否是問題所在。如果它遺失,請重新安裝,並確保已設定values.global.remotePilotAddress
。
- Proxy 正在讀取遠端叢集中 Istiod 的設定。當遠端叢集具有叢集內 Istiod 時,它僅用於 sidecar 注入和 CA。您可以透過在
主要和遠端叢集的步驟仍然適用於多網路,儘管多網路有一個額外的案例。
$ istioctl --context $CTX_CLUSTER1 proxy-config endpoint curl-dd98b5f48-djwdw.sample | grep helloworld
10.0.5.11:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
10.0.6.13:5000 HEALTHY OK outbound|5000||helloworld.sample.svc.cluster.local
在多網路中,我們預期其中一個端點 IP 會與遠端叢集的東西向閘道公用 IP 相符。看到多個 Pod IP 表示以下兩種情況之一:
- 無法判斷遠端網路的閘道位址。
- 無法判斷用戶端或伺服器 Pod 的網路。
無法判斷遠端網路的閘道位址。
在無法連線的遠端叢集中,檢查 Service 是否具有外部 IP。
$ kubectl -n istio-system get service -l "istio=eastwestgateway"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-eastwestgateway LoadBalancer 10.8.17.119 <PENDING> 15021:31781/TCP,15443:30498/TCP,15012:30879/TCP,15017:30336/TCP 76m
如果 EXTERNAL-IP
卡在 <PENDING>
狀態,則環境可能不支援 LoadBalancer
服務。在這種情況下,可能需要自訂 Service 的 spec.externalIPs
區段,以手動為閘道提供一個可以從叢集外部連線的 IP。
如果外部 IP 存在,請檢查 Service 是否包含具有正確值的 topology.istio.io/network
標籤。如果該標籤不正確,請重新安裝閘道並確保在產生腳本上設定了 --network
旗標。
無法判斷用戶端或伺服器的網路。
在來源 Pod 上,檢查 Proxy 的中繼資料。
$ kubectl get pod $CURL_POD_NAME \
-o jsonpath="{.spec.containers[*].env[?(@.name=='ISTIO_META_NETWORK')].value}"
$ kubectl get pod $HELLOWORLD_POD_NAME \
-o jsonpath="{.metadata.labels.topology\.istio\.io/network}"
如果這些值都未設定,或值錯誤,Istiod 可能會將來源和用戶端 Proxy 視為位於同一個網路上,並傳送網路本機端點。當這些值未設定時,請檢查在安裝期間是否已正確設定 values.global.network
,或是否已正確設定注入 Webhook。
Istio 使用在注入期間設定的 topology.istio.io/network
標籤來判斷 Pod 的網路。對於未注入的 Pod,Istio 依賴於叢集中系統命名空間上設定的 topology.istio.io/network
標籤。
在每個叢集中,檢查網路。
$ kubectl --context="${CTX_CLUSTER1}" get ns istio-system -ojsonpath='{.metadata.labels.topology\.istio\.io/network}'
如果上述命令沒有輸出預期的網路名稱,請設定標籤。
$ kubectl --context="${CTX_CLUSTER1}" label namespace istio-system topology.istio.io/network=network1