トラフィック管理のベストプラクティス

このセクションでは、ネットワークやトラフィック管理の問題を回避するための特定のデプロイメントまたは構成ガイドラインを提供します。

サービスに対するデフォルトルートの設定

デフォルトのIstioの動作は、ルールを設定しなくても任意のソースから宛先サービスのすべてのバージョンにトラフィックを都合よく送信しますが、最初からすべてのサービスに対してデフォルトルートを持つVirtualServiceを作成することは、一般的にIstioのベストプラクティスと見なされています。

最初にサービスのバージョンが1つしかない場合でも、2番目のバージョンをデプロイすることを決定したらすぐに、新しいバージョンが制御されていない方法でトラフィックをすぐに受信するのを防ぐために、新しいバージョンが開始される**前**にルーティングルールを設定する必要があります。

Istioのデフォルトのラウンドロビンルーティングに依存する場合のもう1つの潜在的な問題は、Istioのデスティネーションルール評価アルゴリズムの微妙な点によるものです。リクエストをルーティングする際、Envoyはまず仮想サービスのルートルールを評価して、特定のサブセットがルーティングされているかどうかを判断します。もしそうなら、対応するサブセットに対応するデスティネーションルールポリシーのみをアクティブにします。したがって、Istioは、対応するサブセットにトラフィックを**明示的に**ルーティングした場合にのみ、特定のサブセットに対して定義したポリシーを適用します。

たとえば、次のデスティネーションルールを*レビュー*サービスに対して定義された唯一の構成と見なしてください。つまり、対応するVirtualService定義にルートルールはありません。

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  subsets:
  - name: v1
    labels:
      version: v1
    trafficPolicy:
      connectionPool:
        tcp:
          maxConnections: 100

Istioのデフォルトのラウンドロビンルーティングが「v1」インスタンスを時々呼び出す場合でも、「v1」が唯一の実行中のバージョンである場合は常にそうである場合でも、上記のトラフィックポリシーは決して呼び出されません。

上記例は、次の2つの方法のいずれかで修正できます。トラフィックポリシーをDestinationRuleの1つ上のレベルに移動して、任意のバージョンに適用されるようにすることができます。

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: reviews
spec:
  host: reviews
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
  subsets:
  - name: v1
    labels:
      version: v1

または、さらに良いことに、VirtualService定義でサービスに対して適切なルートルールを定義します。たとえば、「reviews:v1」に対する簡単なルートルールを追加します。

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
  - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1

名前空間を跨いだ構成の共有の制御

仮想サービス、宛先ルール、またはサービスエントリは、ある名前空間で定義し、それらを他の名前空間にエクスポートすれば、他の名前空間で再利用できます。Istio はデフォルトですべてのトラフィック管理リソースをすべての名前空間にエクスポートしますが、exportTo フィールドを使用して可視性を上書きできます。たとえば、次の仮想サービスは、同じ名前空間のワークロードからのリクエストのみに影響を与えます。

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: myservice
spec:
  hosts:
  - myservice.com
  exportTo:
  - "."
  http:
  - route:
    - destination:
        host: myservice

特定の名前空間で宛先ルールの可視性を設定しても、そのルールが使用される保証はありません。宛先ルールを他の名前空間にエクスポートすると、それらの名前空間で使用できるようになりますが、リクエスト中に実際に適用されるには、名前空間が宛先ルール検索パス上にある必要もあります。

  1. クライアントの名前空間
  2. サービスの名前空間
  3. 構成済みの meshconfig.rootNamespace 名前空間(デフォルトは istio-system

たとえば、次の宛先ルールを考えてみましょう。

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: myservice
spec:
  host: myservice.default.svc.cluster.local
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100

この宛先ルールを名前空間 ns1 で作成すると仮定します。

ns1 のクライアントから myservice サービスにリクエストを送信すると、宛先ルールは検索パスの最初の名前空間、つまりクライアントの名前空間にあるため適用されます。

ここで、別の名前空間(たとえば ns2)からリクエストを送信すると、クライアントは宛先ルールと同じ名前空間の ns1 には存在しなくなります。対応するサービスである myservice.default.svc.cluster.localns1 ではなく default 名前空間にあるため、宛先ルールは検索パスの2番目の名前空間であるサービスの名前空間でも見つかりません。

たとえ myservice サービスがすべての名前空間にエクスポートされていて、ns2 で可視であり、宛先ルールも ns2 を含むすべての名前空間にエクスポートされていても、検索パスのいずれの名前空間にも存在しないため、ns2 からのリクエスト中に適用されることはありません。

この問題を回避するには、対応するサービスと同じ名前空間(この例では default)に宛先ルールを作成します。そうすれば、どの名前空間のクライアントからのリクエストにも適用されます。また、宛先ルールを検索パスの3番目の名前空間である istio-system 名前空間に移動することもできますが、これは宛先ルールが本当にすべての名前空間に適用可能なグローバル構成である場合を除いて推奨されず、管理者権限が必要になります。

Istio がこの制限された宛先ルール検索パスを使用する理由は2つあります。

  1. 完全に無関係な名前空間のサービスの動作を上書きできる宛先ルールが定義されるのを防ぐ。
  2. 同じホストに対して複数の宛先ルールがある場合に、明確な検索順序を持つ。

大規模な仮想サービスとデスティネーションルールを複数のリソースに分割

特定のホストのルートルールまたはポリシーの完全なセットを単一の VirtualService または DestinationRule リソースで定義するのが不便な場合は、複数のリソースでホストの構成を段階的に指定する方が望ましい場合があります。コントロールプレーンは、そのような宛先ルールをマージし、仮想サービスがゲートウェイにバインドされている場合は、そのような仮想サービスをマージします。

パスベースの委任を使用して複数の実装サービスを公開するアプリケーションホストを公開するイングレスゲートウェイにバインドされた VirtualService のケースを考えてみましょう。

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
  - myapp.com
  gateways:
  - myapp-gateway
  http:
  - match:
    - uri:
        prefix: /service1
    route:
    - destination:
        host: service1.default.svc.cluster.local
  - match:
    - uri:
        prefix: /service2
    route:
    - destination:
        host: service2.default.svc.cluster.local
  - match:
    ...

この種の構成の欠点は、基礎となるマイクロサービスの他の構成(たとえば、ルートルール)も、個々のサービスチームに関連付けられ、所有される可能性のある別々のリソースではなく、この単一の構成ファイルに含める必要があることです。詳細については、イングレスゲートウェイのリクエストにルートルールが影響しないを参照してください。

この問題を回避するために、myapp.com の構成を、バックエンドサービスごとに1つずつ、いくつかの VirtualService フラグメントに分割する方が望ましい場合があります。例えば

apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: myapp-service1
spec:
  hosts:
  - myapp.com
  gateways:
  - myapp-gateway
  http:
  - match:
    - uri:
        prefix: /service1
    route:
    - destination:
        host: service1.default.svc.cluster.local
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: myapp-service2
spec:
  hosts:
  - myapp.com
  gateways:
  - myapp-gateway
  http:
  - match:
    - uri:
        prefix: /service2
    route:
    - destination:
        host: service2.default.svc.cluster.local
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: myapp-...

既存のホストに対して2番目以降の VirtualService が適用されると、istiod は追加のルートルールをホストの既存の構成にマージします。ただし、この機能を使用する際には慎重に考慮する必要があるいくつかの注意点があります。

  1. 特定のソース VirtualService のルールの評価順序は保持されますが、リソース間の順序は未定義です。言い換えれば、フラグメント構成全体でのルール評価の保証された順序はないため、フラグメント間のルール間に競合するルールまたは順序の依存関係がない場合にのみ、予測可能な動作になります。
  2. フラグメントには、「キャッチオール」ルール(つまり、match フィールドがないルール)は1つだけにする必要があります。このような「キャッチオール」ルールはすべて、マージされた構成のリストの最後に移動されますが、すべてのリクエストをキャッチするため、最初に適用されるものが他のルールを実質的に上書きして無効にします。
  3. VirtualService は、ゲートウェイにバインドされている場合にのみ、この方法でフラグメント化できます。ホストのマージはサイドカーではサポートされていません。

DestinationRule も、同様のマージセマンティクスと制限でフラグメント化できます。

  1. 同じホストの複数の宛先ルールで、任意の特定のサブセットの定義は1つだけにする必要があります。同じ名前のものが複数ある場合は、最初の定義が使用され、後続の重複は破棄されます。サブセットコンテンツのマージはサポートされていません。
  2. 同じホストに対して最上位の trafficPolicy は1つだけにする必要があります。最上位のトラフィックポリシーが複数の宛先ルールで定義されている場合、最初に処理されたものが使用されます。後続の最上位の trafficPolicy 構成は破棄されます。
  3. 仮想サービスのマージとは異なり、宛先ルールのマージはサイドカーとゲートウェイの両方で機能します。

サービスルートの再構成中の503エラーの回避

トラフィックをサービスの特定のバージョン(サブセット)にルーティングするようにルートルールを設定する場合、ルートで使用する前にサブセットが利用可能であることを確認する必要があります。そうしないと、再構成期間中にサービスへの呼び出しが 503 エラーを返す可能性があります。

対応するサブセットを定義する VirtualServicesDestinationRules の両方を単一の kubectl 呼び出し(たとえば、kubectl apply -f myVirtualServiceAndDestinationRule.yaml)を使用して作成することは、リソースが(構成サーバー、つまり Kubernetes API サーバーから)istiod インスタンスに最終的に整合性のある方法で伝播するため、十分ではありません。サブセットを使用する VirtualService がサブセットが定義されている DestinationRule より先に到着した場合、istiod によって生成された Envoy 構成は、存在しないアップストリームプールを参照します。これにより、すべての構成オブジェクトが istiod で利用可能になるまで HTTP 503 エラーが発生します。

サブセットを使用してルートを構成する際にサービスがダウンタイムなしになるようにするには、以下に示す「make-before-break」プロセスに従ってください。

  • 新しいサブセットを追加する場合

    1. 新しいサブセットを使用する VirtualServices を更新する前に、最初に DestinationRules を更新して新しいサブセットを追加します。kubectl またはプラットフォーム固有のツールを使用してルールを適用します。

    2. DestinationRule 構成が Envoy サイドカーに伝播するまで数秒待ちます。

    3. 新しく追加されたサブセットを参照するように VirtualService を更新します。

  • サブセットを削除する場合

    1. DestinationRule からサブセットを削除する前に、サブセットへの参照をすべて削除するように VirtualServices を更新します。

    2. VirtualService 構成が Envoy サイドカーに伝播するまで数秒待ちます。

    3. DestinationRule を更新して、未使用のサブセットを削除します。

この情報は役に立ちましたか?
改善のための提案はありますか?

フィードバックありがとうございます!