クライアントIPベースのルーティングは一般的に使用されます。たとえば、内部ネットワークとインターネットのユーザーが異なるバージョンのアプリケーションにアクセスする必要がある場合、および異なる地域のユーザーが異なる種類のコンテンツにアクセスする必要がある場合、クライアントIPベースのルーティングを使用してこれらの目標を達成できます。そのため、Service Mesh(ASM)は、クライアントのIPアドレスをルーティング用のリクエストヘッダーに変換するカスタムプラグインを提供します。このトピックでは、カスタムプラグインを使用してASMでクライアントIPベースのルーティングを実装する方法について説明します。
背景情報
ASMは、Envoy プロキシを使用してトラフィックを転送し、Envoyの豊富なプラグインを使用してメッシュ機能を拡張します。たとえば、EnvoyはHTTPベースのサービス向けに非常に柔軟な拡張インターフェースを提供します。これらのインターフェースを使用して、詳細なリクエストメタデータを読み取り、リクエストヘッダーや本文などのリクエストプロパティを変更することもできます。Envoyは、次の3種類のプラグインを提供します。
ネイティブEnvoyフィルター:C++で開発されています。このようなプラグインを開発することは困難ですが、より良いパフォーマンスを提供できます。
WebAssembly(Wasm)プラグイン:複数のプログラミング言語で開発できます。このようなプラグインの開発はより簡単で、より安全で柔軟性があります。
Luaプラグイン:Luaで開発されており、柔軟性は制限されますが、最も簡単に開発できます。
この例では、単純なLuaプラグインを使用して、リクエストのクライアントIPアドレスをリクエストヘッダーに変換します。仮想サービスを使用してヘッダーを照合します。このようにして、異なるソースからのリクエストに対して異なるレスポンスが返されます。
前提条件
HTTPBinアプリケーションがクラスターにデプロイされており、ASMイングレスゲートウェイを介してアクセスできます。詳細については、「HTTPBin アプリケーションをデプロイする」をご参照ください。
ステップ 1:クライアントのソース IP アドレスを確認する
まず、sleepアプリケーションをクライアント(以下、sleepクライアント)としてクラスターにデプロイします。次に、sleepクライアントとローカルクライアントからHTTPBinアプリケーションにアクセスして、異なるソースIPアドレスからのリクエストをテストします。
ローカルクライアントとは、特定のシナリオで操作を実行するユーザー端末を指し、パーソナルコンピューター(PC)とElastic Compute Service(ECS)インスタンスが含まれます。たとえば、PCからECSインスタンスにログオンしてからkubectlを使用してContainer Service for Kubernetes(ACK)マネージドクラスターにアクセスする場合、ECSインスタンスがローカルクライアントになります。
kubeconfigファイルの情報に基づいてkubectlを使用してACKクラスターに接続し、sleep.yamlファイルを作成します。
次のコマンドを実行して、sleepアプリケーションをデプロイします。
kubectl apply -f sleep.yaml次のコマンドを実行して、ASMイングレスゲートウェイのIPアドレスの環境変数を構成します。イングレスゲートウェイのIPアドレスを照会する方法の詳細については、「Istio リソースを使用してトラフィックを異なるバージョンのサービスにルーティングする」トピックのステップ 3 のサブステップ 1 をご参照ください。
export ASM_GATEWAY_IP=112.35.xx.xx次のコマンドを実行して、ローカルクライアントのIPアドレスを照会します。
curl ${ASM_GATEWAY_IP}/ip次のコマンドを実行して、sleepポッドのIPアドレスを照会します。
kubectl exec deploy/sleep -it -- curl ${ASM_GATEWAY_IP}/ip説明HTTPBinアプリケーションの
/ipパスにアクセスするリクエストに対して、クライアントのIPアドレスが返されます。このメソッドを使用してクライアントのIPアドレスを取得するには、ASMイングレスゲートウェイのService構成でExternalTrafficPolicyをlocalに設定する必要があります。
ステップ 2:Lua プラグインを作成し、ASM イングレスゲートウェイで使用する
Luaプラグインは、EnvoyのLuaフィルターを使用して実装されます。Luaコードを記述し、Luaフィルター構成の一部としてLuaコードをEnvoyに送信できます。リクエスト処理中に、Envoyは構成されたLuaコードを呼び出して、対応する操作を実行します。
次のコードブロックは、このトピックの例で必要なLuaコードを示しています。
function envoy_on_request(request_handle)
-- 受信したリクエストを処理するために envoy_on_request 関数を定義します。
-- request_handle パラメーターは、リクエスト情報を取得および変更するために使用されます。
local client_address = request_handle:streamInfo():downstreamRemoteAddress()
-- リクエストのソース IP アドレスを取得します。
request_handle:headers():add("x-client-address", client_address)
-- リクエストヘッダーを設定します。ヘッダーのキーは x-client-address です。
endEnvoyフィルターを作成します。詳細については、「Envoy フィルターテンプレートを使用して Envoy フィルターを作成する」をご参照ください。
Envoyフィルターテンプレートを作成するときは、次のYAMLコードを [複数バージョン対応 Envoyfilter テンプレート] セクションのコードエディターに貼り付けます。
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: add-header-by-ip namespace: istio-system spec: workloadSelector: labels: istio: ingressgateway configPatches: - applyTo: HTTP_FILTER match: context: GATEWAY listener: filterChain: filter: name: "envoy.filters.network.http_connection_manager" patch: operation: INSERT_BEFORE value: name: envoy.lua typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua" inlineCode: | function envoy_on_request(request_handle) local client_address = request_handle:streamInfo():downstreamRemoteAddress() request_handle:headers():add("x-client-address", client_address) endEnvoyフィルターテンプレートをワークロードにバインドするには、目的のEnvoyフィルターテンプレートを見つけて、[アクション] 列の [テンプレートをワークロードにバインド] をクリックします。表示されるページで、[envoyfilter をワークロードにバインド] をクリックします。表示されるダイアログボックスで、[名前空間] ドロップダウンリストから [istio-system] を選択し、[ワークロードタイプ] ドロップダウンリストから [サービス] を選択し、ASMイングレスゲートウェイの対応するサービスを見つけて、目的のサービスの横にある [バインド] をクリックします。サービスの名前は、
istio-${ASMイングレスゲートウェイの名前}の形式です。Envoyフィルターテンプレートがワークロードにバインドされた後、左側のナビゲーションペインで [envoyfilter] をクリックします。[EnvoyFilter] ページで、対応するEnvoyフィルターが作成されていることがわかります。
ステップ 3:クライアント IP ベースのルーティングルールを作成する
kubeconfigファイルの情報に基づいてkubectlを使用してASMインスタンスに接続し、HTTPBinアプリケーション用に作成された仮想サービスを変更します。次のコードブロックは、最終的なYAMLコードを示しています。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: httpbin-vs
namespace: default
spec:
gateways:
- httpbin
hosts:
- '*'
http:
- match:
- headers:
x-client-address:
prefix: ${取得した sleep クライアントの IP アドレス}
directResponse:
status: 200
body:
string: "from sleep"
- match:
- headers:
x-client-address:
prefix: ${取得したローカルクライアントの IP アドレス}
directResponse:
status: 200
body:
string: "from my host"
- name: test
route:
- destination:
host: httpbin.default.svc.cluster.local
port:
number: 8000上記の構成は、次の情報を示しています。
sleepクライアントから送信されたすべてのリクエストに対して、
from sleep文字列が返されます。ローカルクライアントから送信されたすべてのリクエストに対して、
from my host文字列が返されます。
ステップ 4:構成を確認する
ローカルクライアントで次のコマンドを実行します。
curl ${ASM_GATEWAY_IP}/ip期待される出力:
from my hostkubeconfigファイルの情報に基づいてkubectlを使用してACKクラスターに接続し、sleepクライアントで次のコマンドを実行します。
kubectl exec deploy/sleep -it -- curl ${ASM_GATEWAY_IP}/ip期待される出力:
from sleep
参考資料
Envoyアーキテクチャに精通している場合、他のEnvoyプラグインよりもLuaプラグインを簡単に開発できます。EnvoyのLuaプラグインを開発する方法の詳細については、「HTTP フィルターの Lua スクリプト」をご参照ください。
Wasmプラグインは、WebAssembly for Proxies仕様に基づいて記述されたEnvoyプラグインであり、複数のプログラミング言語で開発できます。簡単なGolangを使用してWasmプラグインを開発してみてください。詳細については、「Envoy プロキシ用の Go で Wasm プラグインを作成する」をご参照ください。