外部サービスのフェイルオーバー設定

メッシュ外のエンドポイントに対する、ローカル優先ロードバランシングとフェイルオーバーの設定方法について説明します。

2021年6月4日 | Ram Vennam - Solo.io

Istioの強力なAPIは、様々なサービスメッシュのユースケースを解決するために使用できます。多くのユーザーはIstioの強力なイングレスとイーストウエスト機能について知っていますが、それはまた、エグレス(アウトバウンド)トラフィックのための多くの機能を提供します。これは、アプリケーションがクラウドプロバイダーが提供するデータベースエンドポイントなどの外部サービスと通信する必要がある場合に特に役立ちます。ワークロードの実行場所に応じて、選択できるエンドポイントは複数あります。たとえば、AmazonのDynamoDBは、複数のエンドポイントをリージョン全体に提供しています。レイテンシの理由から、通常はワークロードに最も近いエンドポイントを選択しますが、予期せず問題が発生した場合に備えて、別のエンドポイントへの自動フェイルオーバーを設定する必要がある場合があります。

サービスメッシュ内で実行されているサービスと同様に、Istioは外れ値を検出し、健全なエンドポイントにフェイルオーバーするように設定できます。これはアプリケーションに対して完全に透過的です。この例では、Amazon DynamoDBエンドポイントを使用し、Google Kubernetes Engine(GKE)クラスタで実行されているワークロードと同じリージョンまたは近接したリージョンをプライマリリージョンとして選択します。また、フェイルオーバーリージョンも設定します。

ルーティングエンドポイント
プライマリhttp://dynamodb.us-east-1.amazonaws.com
フェイルオーバーhttp://dynamodb.us-west-1.amazonaws.com

failover

ServiceEntryを使用した外部エンドポイントの定義

ローカル優先ロードバランシングは、通常はKubernetesノードに設定されたラベルから推論されるregionまたはzoneに基づいて機能します。まず、ワークロードの場所を特定します。

$ kubectl describe node | grep failure-domain.beta.kubernetes.io/region
                    failure-domain.beta.kubernetes.io/region=us-east1
                    failure-domain.beta.kubernetes.io/region=us-east1

この例では、GKEクラスタノードはus-east1で実行されています。

次に、使用するエンドポイントを集約するServiceEntryを作成します。この例では、ホストとしてmydb.comを選択しました。これは、アプリケーションが接続するように設定する必要があるアドレスです。プライマリエンドポイントのlocalityをワークロードと同じリージョンに設定します。

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-dns
spec:
  hosts:
  - mydb.com
  location: MESH_EXTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  endpoints:
  - address: dynamodb.us-east-1.amazonaws.com
    locality: us-east1
    ports:
      http: 80
  - address: dynamodb.us-west-1.amazonaws.com
    locality: us-west
    ports:
      http: 80

リクエスト送信のテストソースとして使用するsleepコンテナをデプロイしましょう。

圧縮
$ kubectl apply -f @samples/sleep/sleep.yaml@

sleepコンテナから、http://mydb.comに5回アクセスしてみてください。

$ for i in {1..5}; do kubectl exec deploy/sleep -c sleep -- curl -sS http://mydb.com; echo; sleep 2; done
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com

Istioは両方のエンドポイントにリクエストを送信していることがわかります。ノードと同じリージョンにマークされているエンドポイントにのみ送信する必要があります。

そのためには、DestinationRuleを設定する必要があります。

DestinationRuleを使用したフェイルオーバー条件の設定

IstioのDestinationRuleを使用すると、ロードバランシング、接続プール、外れ値検出の設定を行うことができます。エンドポイントが不安定と識別され、ロードバランシングプールから削除される条件を指定できます。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: mydynamodb
spec:
  host: mydb.com
  trafficPolicy:
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 15s
      baseEjectionTime: 1m

上記のDestinationRuleは、15秒ごとにエンドポイントをスキャンするように設定されており、5xxエラーコードでエンドポイントが1回でも失敗すると、1分間不安定とマークされます。このサーキットブレーカーがトリガーされない場合、トラフィックはポッドと同じリージョンにルーティングされます。

curlを再度実行すると、トラフィックが常にus-east1エンドポイントに送られていることがわかります。

$ for i in {1..5}; do kubectl exec deploy/sleep -c sleep -- curl -sS http://mydb.com; echo; sleep 2; done

healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com
healthy: dynamodb.us-east-1.amazonaws.com

障害のシミュレーション

次に、us-eastエンドポイントがダウンした場合にどうなるかを見てみましょう。これをシミュレートするために、ServiceEntryを変更し、us-eastエンドポイントを無効なポートに設定します。

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-dns
spec:
  hosts:
  - mydb.com
  location: MESH_EXTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
  endpoints:
  - address: dynamodb.us-east-1.amazonaws.com
    locality: us-east1
    ports:
      http: 81 # INVALID - This is purposefully wrong to trigger failover
  - address: dynamodb.us-west-1.amazonaws.com
    locality: us-west
    ports:
      http: 80

curlを再度実行すると、us-eastエンドポイントへの接続に失敗した後、トラフィックが自動的にus-westリージョンにフェイルオーバーされることがわかります。

$ for i in {1..5}; do kubectl exec deploy/sleep -c sleep -- curl -sS http://mydb.com; echo; sleep 2; done
upstream connect error or disconnect/reset before headers. reset reason: connection failure
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com
healthy: dynamodb.us-west-1.amazonaws.com

us-eastエンドポイントの外れ値ステータスは、以下を実行して確認できます。

$ istioctl pc endpoints <sleep-pod> | grep mydb
ENDPOINT                         STATUS      OUTLIER CHECK     CLUSTER
52.119.226.80:81                 HEALTHY     FAILED            outbound|80||mydb.com
52.94.12.144:80                  HEALTHY     OK                outbound|80||mydb.com

HTTPSのフェイルオーバー

外部HTTPSサービスのフェイルオーバーの設定も同様に簡単です。アプリケーションは引き続きプレーンHTTPを使用でき、IstioプロキシにHTTPSエンドポイントへのTLS開始を実行させることができます。

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-dns
spec:
  hosts:
  - mydb.com
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
    targetPort: 443
  resolution: DNS
  endpoints:
  - address: dynamodb.us-east-1.amazonaws.com
    locality: us-east1
  - address: dynamodb.us-west-1.amazonaws.com
    locality: us-west

上記のServiceEntryは、ポート80でmydb.comサービスを定義し、ポート443で実際のDynamoDBエンドポイントにトラフィックをリダイレクトします。

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: mydynamodb
spec:
  host: mydb.com
  trafficPolicy:
    tls:
      mode: SIMPLE
    loadBalancer:
      simple: ROUND_ROBIN
      localityLbSetting:
        enabled: true
        failover:
          - from: us-east1
            to: us-west
    outlierDetection:
      consecutive5xxErrors: 1
      interval: 15s
      baseEjectionTime: 1m

DestinationRuleは、TLS開始を実行し、外れ値検出を設定します。このルールには、フェイルオーバーフィールドも設定されており、フェイルオーバーターゲットとして正確にどのリージョンを指定できるようになっています。これは、複数のリージョンが定義されている場合に役立ちます。

まとめ

IstioのVirtualServiceDestinationRule APIは、トラフィックルーティング、障害復旧、障害注入機能を提供するため、耐障害性の高いアプリケーションを作成できます。ServiceEntry APIは、これらの機能の多くを、サービスメッシュの一部ではない外部サービスに拡張します。

この記事を共有