Anthos Service Mesh のプロキシに関する問題を解決する

このドキュメントでは、Anthos Service Mesh の一般的な問題とその解決方法について説明します。さらにサポートが必要な場合は、サポートの利用をご覧ください。

Istio でエンドポイントにアクセスしたときに接続が拒否される

クラスタからエンドポイント(Memorystore Redis、CloudSQL、またはアプリケーション ワークロードがアクセスする必要がある外部サービスなど)に通信するときに、接続拒否(ECONNREFUSED)エラーが断続的に発生する場合があります。

これは、アプリケーション ワークロードが istio-proxy(Envoy)コンテナよりも先に開始され、外部エンドポイントにアクセスしようとした場合に発生する可能性があります。この段階で istio-init(initContainer)はすでに実行されているため、すべての送信トラフィックを Envoy にリダイレクトする iptables ルールが適用されています。istio-proxy の準備ができていないため、iptables ルールによって、まだ起動されていないサイドカー プロキシにトラフィックがリダイレクトされることになり、アプリケーションは ECONNREFUSED エラーを受け取ります。

このエラーが発生しているかどうかを確認する方法については、次の手順で詳しく説明します。

  1. 次のフィルタを使用して Google Cloud Observability のログを確認し、問題のある 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
    
  2. 次のフィルタを使用して Google Cloud Observability のログを確認し、istio プロキシ(Envoy)コンテナの準備ができていないことを確認します。

     resource.labels.pod_name="$POD_FROM_STEP_1$"
     resource.type="k8s_container"
     resource.labels.container_name="istio-proxy"
     textPayload:"Envoy proxy is NOT ready"
    
  3. 発生した問題を検索します。従来の Stackdriver を使用している場合は、resource.type="container" を使用します。

    resource.type="k8s_container"
    textPayload:"$ERROR_MESSAGE$"
    
  4. 最近発生した問題を開いて Pod の名前を取得し、resource.labelspod_name をメモします。

  5. この 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
    
  6. この Pod の最初のエラーのタイムスタンプをメモします。

  7. 次のフィルタを使用して、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}
    
  8. エラーと istio-proxy 起動イベントのタイムスタンプを使用して、Envoy の準備ができていないときにエラーが発生していることを確認します。

    istio-proxy コンテナの準備ができていないときにエラーが発生した場合、通常は接続拒否エラーが取得されます。前の例では、Pod は 2020-03-31T10:41:15.552128897Z と同時に Redis に接続しようとしましたが、2020-03-31T10:41:58Z istio-proxy がまだ readiness プローブに失敗していました。

    istio-proxy コンテナのほうが先に起動されていた場合でも、アプリが外部エンドポイントへの接続を試みるまでに準備が完了しなかった可能性があります。

    この問題が発生した場合は、次のトラブルシューティング手順に進んでください。

  9. Pod レベルで config にアノテーションを付けます。これは Pod レベルでのみ使用できます。グローバル レベルでは使用できません。

    annotations:
    proxy.istio.io/config: '{ "holdApplicationUntilProxyStarts": true }'
    
  10. 外部サービスに対する他のリクエストを試行する前に、Envoy の準備ができているかどうかを確認するように、アプリケーション コードを変更します。たとえば、アプリケーションの起動時に istio-proxy ヘルス エンドポイントにリクエストを送信するループを開始します。このループは、200 が取得された場合のみ続行されます。istio-proxy ヘルス エンドポイントは次のとおりです。

    http://localhost:15020/healthz/ready
    

Vault と Istio 間のサイドカー インジェクション中に競合状態になる

シークレット管理に vault を使用している場合、vaultistio の前にサイドカーを挿入したために、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 のほうが後になる必要があり、初期コンテナの実行中に istio プロキシを実行することはできません。istio 初期コンテナは、すべてのトラフィックをプロキシにリダイレクトする iptables ルールを設定します。初期コンテナがまだ実行されていないため、このルールによるリダイレクトは行わず、すべてのトラフィックがブロックされます。そのため初期コンテナを最後に配置し、iptables ルールが設定された直後にプロキシを起動および実行する必要があります。順序は決定的ではないため、Istio を最初に挿入すると機能しなくなります。

この状態のトラブルシューティングを行うには、vault の IP アドレスを許可します。これにより、Vault IP に送信されるトラフィックが、まだ準備ができていない Envoy プロキシにリダイレクトされ、そこで通信がブロックされることはなくなります。これを実現するには、excludeOutboundIPRanges という名前の新しいアノテーションを追加する必要があります。

マネージド Anthos Service Mesh の場合は、Deployment レベルまたは Pod レベルで、spec.template.metadata.annotations においてのみ実行できます。次に例を示します。

apiVersion: apps/v1
kind: Deployment
...
...
...
spec:
  template:
    metadata:
      annotations:
        traffic.sidecar.istio.io/excludeOutboundIPRanges:

クラスタ内の Anthos Service Mesh では、spec.values.global.proxy.excludeIPRanges において、IstioOperator を使用してグローバル サービス メッシュとして設定することもできます。次に例を示します。

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  values:
    global:
      proxy:
        excludeIPRanges: ""

アノテーションを追加したら、ワークロードを再起動します。