トラフィックルーティングについて
Istioの目標の一つは、「透過的なプロキシ」として機能し、既存のクラスタに導入でき、トラフィックが以前と変わらずに流れ続けるようにすることです。ただし、Istioはリクエストロードバランシングなどの追加機能により、通常のKubernetesクラスタとは異なる強力な方法でトラフィックを管理できます。メッシュ内で何が起こっているかを理解するには、Istioがどのようにトラフィックをルーティングするかを理解することが重要です。
フロントエンドとバックエンド
Istioのトラフィックルーティングには、主に2つのフェーズがあります。
- 「フロントエンド」とは、処理しているトラフィックのタイプをどのように一致させるかを指します。これは、トラフィックをルーティングするバックエンドと、適用するポリシーを特定するために必要です。たとえば、
http.ns.svc.cluster.local
のHost
ヘッダーを読み取り、リクエストがhttp
サービス宛であることを識別します。このマッチングがどのように機能するかについては、以下で詳しく説明します。 - 「バックエンド」とは、トラフィックが一致した後に送信する場所を指します。上記の例を使用すると、リクエストが
http
サービスをターゲットにしていると識別した後、そのサービスのエンドポイントに送信します。ただし、この選択は常に単純ではありません。Istioでは、VirtualService
ルーティングルールを通じてこのロジックをカスタマイズできます。
標準のKubernetesネットワークにもこれらの同じ概念がありますが、はるかに単純で、通常は隠されています。Service
が作成されると、通常、関連付けられたフロントエンド、つまり自動的に作成されたDNS名(http.ns.svc.cluster.local
など)と、サービスを表すために自動的に作成されたIPアドレス(ClusterIP
)があります。同様に、バックエンドも作成されます。これは、サービスによって選択されたすべてのポッドを表すEndpoints
またはEndpointSlice
です。
プロトコル
Kubernetesとは異なり、IstioはHTTPやTLSなどのアプリケーションレベルのプロトコルを処理できます。これにより、Kubernetesで利用できるものとは異なるタイプのフロントエンドマッチングが可能になります。
一般的に、Istioが理解するプロトコルには3つのクラスがあります。
- HTTP。これには、HTTP/1.1、HTTP/2、およびgRPCが含まれます。これにはTLSで暗号化されたトラフィック(HTTPS)は含まれないことに注意してください。
- TLS。これにはHTTPSが含まれます。
- 生のTCPバイト。
プロトコル選択ドキュメントでは、Istioがどのプロトコルを使用するかを決定する方法について説明しています。
「TCP」の使用は混乱を招く可能性があります。他のコンテキストでは、UDPなどの他のL4プロトコルを区別するために使用されます。IstioでTCPプロトコルを参照する場合、これは通常、生のバイトストリームとして扱い、TLSやHTTPなどのアプリケーションレベルのプロトコルを解析しないことを意味します。
トラフィックルーティング
Envoyプロキシがリクエストを受信すると、どこに(もしあれば)転送するかを決定する必要があります。デフォルトでは、カスタマイズされていない限り、リクエストされた元のサービスに転送されます。これがどのように機能するかは、使用するプロトコルによって異なります。
TCP
TCPトラフィックを処理する場合、Istioには接続をルーティングするための非常に少ない有用な情報しかありません。つまり、宛先IPとポートのみです。これらの属性は、対象のサービスを特定するために使用されます。プロキシは、各サービスIP(<Kubernetes ClusterIP>:<Port>
)ペアでリッスンし、トラフィックをアップストリームサービスに転送するように構成されています。
カスタマイズについては、TCP VirtualService
を構成できます。これにより、特定のIPとポートのマッチングが可能になり、リクエストされたものとは異なるアップストリームサービスにルーティングできます。
TLS
TLSトラフィックを処理する場合、Istioは生のTCPよりもわずかに多くの情報を利用できます。TLSハンドシェイク中に提示されるSNIフィールドを調べることができます。
標準サービスの場合、生のTCPと同じIP:ポートマッチングが使用されます。ただし、ExternalNameサービスなど、サービスIPが定義されていないサービスの場合、ルーティングにSNIフィールドが使用されます。
さらに、TLS VirtualService
を使用してカスタムルーティングを構成し、SNIに基づいて一致させ、リクエストをカスタムの宛先にルーティングできます。
HTTP
HTTPは、TCPおよびTLSよりもはるかに豊富なルーティングを可能にします。HTTPを使用すると、接続だけでなく、個々のHTTPリクエストをルーティングできます。さらに、ホスト、パス、ヘッダー、クエリパラメーターなど、多数の豊富な属性を利用できます。
TCPおよびTLSトラフィックは、一般的にIstioの有無にかかわらず同じように動作しますが(ルーティングをカスタマイズするために構成が適用されていない場合)、HTTPには大きな違いがあります。
- Istioは個々のリクエストをロードバランスします。一般的に、これは非常に望ましく、特に接続レベルのロードバランシングが効果的でないgRPCやHTTP/2などの長寿命接続があるシナリオではそうです。
- リクエストは、ポートと
Host
ヘッダーに基づいてルーティングされます。つまり、宛先IPアドレスは事実上無視されます。たとえば、curl 8.8.8.8 -H "Host: productpage.default.svc.cluster.local"
は、productpage
サービスにルーティングされます。
一致しないトラフィック
上記のいずれかの方法を使用してもトラフィックを一致させることができない場合、パストラフィックとして扱われます。デフォルトでは、これらのリクエストはそのまま転送されるため、Istioが認識していないサービス(ServiceEntry
が作成されていない外部サービスなど)へのトラフィックが機能し続けることが保証されます。これらのリクエストが転送されると、相互TLSは使用されず、テレメトリー収集は制限されることに注意してください。
サービスタイプ
標準のClusterIP
サービスに加えて、Istioは、いくつかの注意点があるものの、幅広いKubernetesサービスをサポートしています。
LoadBalancer
と NodePort
サービス
これらのサービスはClusterIP
サービスのスーパーセットであり、主に外部クライアントからのアクセスを許可することに関係しています。これらのサービスタイプはサポートされており、標準のClusterIP
サービスとまったく同じように動作します。
ヘッドレスサービス
ヘッドレスサービスとは、ClusterIP
が割り当てられていないサービスのことです。代わりに、DNS応答には、サービスの一部である各エンドポイント(つまり、ポッドIP)のIPアドレスが含まれます。
一般に、Istioはサービスレベルで機能するため、各ポッドIPに対してリスナーを構成しません。ただし、ヘッドレスサービスをサポートするために、ヘッドレスサービスの各IP:ポートペアに対してリスナーが設定されます。この例外は、HTTPとして宣言されたプロトコルであり、Host
ヘッダーによってトラフィックを一致させます。
ExternalName サービス
ExternalNameサービスは、本質的にDNSエイリアスにすぎません。
より具体的にするために、次の例を考えてみましょう。
apiVersion: v1
kind: Service
metadata:
name: alias
spec:
type: ExternalName
externalName: concrete.example.com
TCPトラフィックの場合、一致させるためのClusterIP
もポッドIPもないため、Istioでのトラフィックマッチングにはまったく変更はありません。Istioがリクエストを受信すると、concrete.example.com
のIPが表示されます。これがIstioが認識しているサービスである場合、上記のようにルーティングされます。そうでない場合は、一致しないトラフィックとして処理されます。
ホスト名で一致するHTTPとTLSの場合、少し異なります。ターゲットサービス(concrete.example.com
)がIstioが認識しているサービスである場合、エイリアスホスト名(alias.default.svc.cluster.local
)がTLSまたはHTTPマッチングへの追加マッチとして追加されます。そうでない場合、変更はないため、一致しないトラフィックとして処理されます。
ExternalName
サービスは、単独でバックエンドになることはありません。代わりに、既存のサービスへの追加のフロントエンドマッチとしてのみ使用されます。VirtualService
の宛先など、明示的にバックエンドとして使用されている場合、同じエイリアスが適用されます。つまり、alias.default.svc.cluster.local
が宛先として設定されている場合、リクエストはconcrete.example.com
に送信されます。そのホスト名がIstioに認識されていない場合、リクエストは失敗します。この場合、concrete.example.com
のServiceEntry
を使用すると、この構成が機能します。
ServiceEntry
Kubernetesサービスに加えて、サービスエントリを作成して、Istioに認識されるサービスのセットを拡張できます。これは、example.com
などの外部サービスへのトラフィックがIstioの機能を取得できるようにするために役立ちます。
addresses
が設定されたServiceEntryは、ClusterIP
サービスのようにルーティングを実行します。
ただし、addresses
がないサービスエントリの場合、ポート上のすべてのIPが一致します。これにより、同じポートでの一致しないトラフィックが正しく転送されない可能性があります。したがって、可能な限りこれらを回避するか、必要な場合は専用ポートを使用するのが最適です。HTTPとTLSは、ルーティングがホスト名/SNIに基づいて行われるため、この制約を共有しません。