マルチクラスタのトラブルシューティング
このページでは、複数のクラスタやネットワークに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はサービス検出機能を提供して容易にしていますが、各クラスタのポッドがIstioなしで単一のネットワーク上にある場合でも、クラスタ間のトラフィックは成功するはずです。TLS/mTLSに関する問題を除外するために、Istioサイドカーなしのポッドを使用して手動でトラフィックテストを行うことができます。
各クラスタで、このテスト用に新しい名前空間を作成します。サイドカーインジェクションは**有効にしないでください**。
$ 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ポッドが実行されていることを確認します。これにより、ポッドの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
ポッドからこのポッド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インストールでは、それぞれ個別に生成されたルート認証機関が使用されます。マルチクラスタの場合、共有された信頼の根拠を手動で設定する必要があります。以下のプラグイン証明書の手順に従うか、IDと信頼モデルを参照して詳細を確認してください。
プラグイン証明書
証明書が正しく設定されていることを確認するには、各クラスタのルート証明書を比較できます。
$ 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検証に従っていることを前提としています。続行する前に、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
エンドポイントは1つしか表示されず、コントロールプレーンがリモートクラスタからエンドポイントを読み取ることができないことを示しています。リモートシークレットが正しく設定されていることを確認してください。
$ kubectl get secrets --context=$CTX_CLUSTER1 -n istio-system -l "istio/multiCluster=true"
- シークレットが見つからない場合は、作成してください。
- シークレットが存在する場合
- シークレットの設定を確認します。リモート
kubeconfig
のデータキーとして、クラスタ名が使用されていることを確認してください。 - シークレットが正しく見える場合は、リモートKubernetes APIサーバーにアクセスするための接続または権限の問題について、
istiod
のログを確認します。ログメッセージには、エラー理由とともにFailed to add remote cluster from 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
エンドポイントは1つしか表示されず、コントロールプレーンがリモートクラスタからエンドポイントを読み取ることができないことを示しています。リモートシークレットが正しく設定されていることを確認してください。
$ kubectl get secrets --context=$CTX_CLUSTER1 -n istio-system -l "istio/multiCluster=true"
- シークレットが見つからない場合は、作成してください。
- シークレットが存在し、エンドポイントが**プライマリ**クラスタ内のポッドの場合
- シークレットの設定を確認します。リモート
kubeconfig
のデータキーとして、クラスタ名が使用されていることを確認してください。 - シークレットが正しく見える場合は、リモートKubernetes APIサーバーにアクセスするための接続または権限の問題について、
istiod
のログを確認します。ログメッセージには、エラー理由とともにFailed to add remote cluster from secret
が含まれる場合があります。
- シークレットの設定を確認します。リモート
- シークレットが存在し、エンドポイントが**リモート**クラスタ内のポッドの場合
- プロキシは、リモートクラスタ内のistiodから設定を読み取っています。リモートクラスタにクラスタ内のistiodがある場合、それはサイドカーインジェクションとCAのみに使用されます。
istio-system
名前空間でistiod-remote
という名前のサービスを探して、これが問題であることを確認できます。見つからない場合は、values.global.remotePilotAddress
を設定して再インストールしてください。
- プロキシは、リモートクラスタ内のistiodから設定を読み取っています。リモートクラスタにクラスタ内のistiodがある場合、それはサイドカーインジェクションと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の1つがリモートクラスタの東西ゲートウェイの公開IPと一致することが期待されます。複数のポッドIPが表示されるということは、次の2つのいずれかを示しています。
- リモートネットワークのゲートウェイのアドレスを決定できません。
- クライアントまたはサーバーポッドのネットワークを決定できません。
リモートネットワークのゲートウェイのアドレスを決定できません
到達できないリモートクラスタで、サービスに外部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
が
のままになっている場合、環境はLoadBalancer
サービスをサポートしていない可能性があります。この場合、サービスのspec.externalIPs
セクションをカスタマイズして、ゲートウェイにクラスタ外部からアクセス可能なIPを手動で割り当てる必要がある場合があります。
外部IPが存在する場合は、サービスに正しい値を持つtopology.istio.io/network
ラベルが含まれていることを確認します。正しくない場合は、ゲートウェイを再インストールし、生成スクリプトで–networkフラグを設定してください。
クライアントまたはサーバーのネットワークを決定できません。
ソースポッドで、プロキシメタデータを確認します。
$ 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はソースプロキシとクライアントプロキシが同じネットワーク上にあり、ネットワークローカルエンドポイントを送信するとみなす可能性があります。これらの値が設定されていない場合は、インストール時にvalues.global.network
が正しく設定されているか、インジェクションWebhookが正しく設定されていることを確認してください。
Istioは、インジェクション時に設定されるtopology.istio.io/network
ラベルを使用して、ポッドのネットワークを決定します。インジェクションされていないポッドの場合、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