DNSプロキシ
Istioはアプリケーショントラフィックのキャプチャに加え、メッシュのパフォーマンスと可用性を向上させるためにDNSリクエストもキャプチャできます。DNSプロキシを使用すると、アプリケーションからのすべてのDNSリクエストはサイドカーにリダイレクトされ、そこでドメイン名とIPアドレスのローカルマッピングが保存されます。リクエストがサイドカーで処理できる場合、アップストリームのDNSサーバーへのラウンドトリップを回避し、アプリケーションに直接レスポンスを返します。そうでない場合は、標準の/etc/resolv.conf
DNS設定に従って、リクエストはアップストリームに転送されます。
KubernetesはKubernetes Service
に対するDNS解決を標準で提供しますが、カスタムServiceEntry
は認識されません。この機能により、DNSサーバーのカスタム設定を必要とせずに、ServiceEntry
アドレスを解決できます。Kubernetes Service
の場合、DNSレスポンスは同じですが、kube-dns
の負荷が軽減され、パフォーマンスが向上します。
この機能は、Kubernetes外で実行されているサービスでも利用できます。つまり、クラスタ外のKubernetes DNSエントリを公開するための面倒な回避策なしに、すべての内部サービスを解決できます。
はじめに
この機能は現在、デフォルトでは有効になっていません。有効にするには、次の設定でIstioをインストールします。
proxy.istio.io/config
アノテーション6を使用して、ポッドごとに有効にすることもできます。
動作中のDNSキャプチャ
DNSキャプチャを試すには、最初にいくつかの外部サービスのServiceEntry
を設定します。
DNSリクエストを開始するクライアントアプリケーションを起動します。
DNSキャプチャがない場合、address.internal
へのリクエストは解決に失敗する可能性があります。これが有効になると、代わりに設定されたaddress
に基づいてレスポンスが返されるようになります。
アドレス自動割り当て
上記の例では、リクエストを送信したサービスに対して事前に定義されたIPアドレスがありました。しかし、安定したアドレスを持たず、DNSに依存する外部サービスにアクセスすることが一般的です。この場合、DNSプロキシはレスポンスを返すための十分な情報を持たず、DNSリクエストをアップストリームに転送する必要があります。
これは特にTCPトラフィックで問題になります。Host
ヘッダーに基づいてルーティングされるHTTPリクエストとは異なり、TCPははるかに少ない情報しか運びません。宛先IPアドレスとポート番号でのみルーティングできます。バックエンドに安定したIPアドレスがないため、それにも基づいてルーティングすることもできず、ポート番号しか残らず、複数のTCPサービスのServiceEntry
が同じポートを共有する場合に競合が発生します。詳細については、次のセクションを参照してください。
これらの問題を回避するために、DNSプロキシは、明示的に定義されていないServiceEntry
にアドレスを自動的に割り当てる機能もサポートしています。これは、ISTIO_META_DNS_AUTO_ALLOCATE
オプションで設定されます。
この機能が有効になっている場合、DNSレスポンスには、各ServiceEntry
に固有の自動的に割り当てられたアドレスが含まれます。次に、プロキシは、このIPアドレスへのリクエストを一致させ、対応するServiceEntry
にリクエストを転送するように構成されます。ISTIO_META_DNS_AUTO_ALLOCATE
を使用する場合、Istioは、ワイルドカードホストを使用していない限り、そのようなサービスにルーティング不可能なVIP(Class Eサブネットから)を自動的に割り当てます。サイドカー上のIstioエージェントは、アプリケーションからのDNSルックアップクエリに対するレスポンスとしてVIPを使用します。Envoyは、各外部TCPサービスにバインドされたトラフィックを明確に区別し、適切なターゲットに転送できるようになりました。詳細については、スマートDNSプロキシに関するIstioブログを参照してください。
これを試すには、別のServiceEntry
を構成します。
次に、リクエストを送信します。
ご覧のとおり、リクエストは自動的に割り当てられたアドレス240.240.0.1
に送信されます。これらのアドレスは、実際のサービスとの競合を避けるために、240.240.0.0/16
の予約済みIPアドレス範囲から選択されます。
VIPなしの外部TCPサービス
デフォルトでは、Istioは、複数のTCPサービスを同じポートで区別できないため、外部TCPトラフィックをルーティングする際に制限があります。この制限は、AWS Relational Database Serviceなどのサードパーティデータベース、または地理的冗長性を持つデータベース設定を使用する場合に特に顕著です。類似しているが異なる外部TCPサービスは、デフォルトでは個別に処理できません。サイドカーがメッシュ外の2つの異なるTCPサービス間のトラフィックを区別するには、サービスが異なるポートにあるか、グローバルに一意のVIPを持つ必要があります。
たとえば、2つの外部データベースサービスmysql-instance1
とmysql-instance2
があり、両方のサービスエントリを作成した場合、クライアントサイドカーは依然として0.0.0.0:{port}
で単一のリスナーを持ち、パブリックDNSサーバーからmysql-instance1
のIPアドレスのみをルックアップし、トラフィックをそこに転送します。0.0.0.0:{port}
に到着したトラフィックがmysql-instance1
とmysql-instance2
のどちらにバインドされているかを区別する方法がないため、mysql-instance2
へのトラフィックをルーティングできません。
次の例は、DNSプロキシを使用してこの問題を解決する方法を示しています。仮想IPアドレスが各サービスエントリに割り当てられ、クライアントサイドカーは各外部TCPサービスにバインドされたトラフィックを明確に区別できるようになります。
はじめにセクションで指定されたIstio構成を更新して、
istio-injection
が有効になっている名前空間をメッシュに制限するdiscoverySelectors
も構成します。これにより、クラスタ内の他の名前空間を使用して、メッシュ外のTCPサービスを実行できます。最初の外部サンプルTCPアプリケーションをデプロイします。
2番目の外部サンプルTCPアプリケーションをデプロイします。
外部サービスに到達するための
ServiceEntry
を構成します。クライアント側で各サービスごとにリスナーが個別に構成されていることを確認します。