Cloud Service Mesh でのプロキシの問題の解決
このドキュメントでは、Cloud Service Mesh の一般的な問題とその解決方法について説明します。さらにサポートが必要な場合は、サポートの利用をご覧ください。
Istio でエンドポイントにアクセスしたときに接続が拒否される
クラスタからエンドポイント(Memorystore Redis、CloudSQL、またはアプリケーション ワークロードがアクセスする必要がある外部サービスなど)に通信するときに、接続拒否(ECONNREFUSED
)エラーが断続的に発生する場合があります。
これは、アプリケーション ワークロードが istio-proxy(Envoy
)コンテナよりも先に開始され、外部エンドポイントにアクセスしようとした場合に発生する可能性があります。この段階で istio-init(initContainer
)はすでに実行されているため、すべての送信トラフィックを Envoy
にリダイレクトする iptables ルールが適用されています。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 がまだ readiness プローブに失敗していました。istio-proxy コンテナのほうが先に起動されていた場合でも、アプリが外部エンドポイントへの接続を試みるまでに準備が完了しなかった可能性があります。
これが発生した問題である場合は、次のトラブルシューティング手順を実施してください。
Pod レベルで config にアノテーションを付けます。これは Pod レベルでのみ使用できます。グローバル レベルでは使用できません。
annotations: proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
外部サービスに対する他のリクエストを試行する前に、
Envoy
の準備ができているかどうかを確認するように、アプリケーション コードを変更します。たとえば、アプリケーションの起動時に istio-proxy ヘルス エンドポイントにリクエストを送信するループを開始します。このループは、200 が取得された場合のみ続行されます。istio-proxy health エンドポイントは次のとおりです。http://localhost:15020/healthz/ready
Vault と Istio 間のサイドカー インジェクション中に競合状態になる
vault
を secret management に使用すると、vault
が istio
の前にサイドカーを挿入することがあります。これにより、Pod が Init
ステータスで停止する可能性があります。この場合、Deployment の再起動後または新たな Deployment のデプロイ後も、作成された 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 が行う必要があり、init コンテナ中に istio
プロキシを実行することはできません。istio
初期コンテナは、すべてのトラフィックをプロキシにリダイレクトする iptables ルールを設定します。初期コンテナがまだ実行されていないため、このルールによるリダイレクトは行わず、すべてのトラフィックがブロックされます。そのため初期コンテナを最後に配置し、iptables ルールが設定された直後にプロキシを起動および実行する必要があります。残念ながら、順序は決定的ではないため、Istio を最初に挿入すると機能しなくなります。
この状態をトラブルシューティングするには、Vault IP に送信されるトラフィックがまだ準備できていない Envoy プロキシにリダイレクトされないように、vault
の IP アドレスを許可してください。これにより、通信がブロックされます。これを実現するには、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: ""
アノテーションを追加したら、ワークロードを再起動します。