すべてのプロダクト
Search
ドキュメントセンター

Alibaba Cloud Service Mesh:ASMイングレスゲートウェイでのクライアントIPベースのルーティング

最終更新日:Jan 13, 2025

クライアントIPベースのルーティングは一般的に使用されます。たとえば、内部ネットワークとインターネットのユーザーが異なるバージョンのアプリケーションにアクセスする必要がある場合、および異なる地域のユーザーが異なる種類のコンテンツにアクセスする必要がある場合、クライアントIPベースのルーティングを使用してこれらの目標を達成できます。そのため、Service Mesh(ASM)は、クライアントのIPアドレスをルーティング用のリクエストヘッダーに変換するカスタムプラグインを提供します。このトピックでは、カスタムプラグインを使用してASMでクライアントIPベースのルーティングを実装する方法について説明します。

背景情報

ASMは、Envoy プロキシを使用してトラフィックを転送し、Envoyの豊富なプラグインを使用してメッシュ機能を拡張します。たとえば、EnvoyはHTTPベースのサービス向けに非常に柔軟な拡張インターフェースを提供します。これらのインターフェースを使用して、詳細なリクエストメタデータを読み取り、リクエストヘッダーや本文などのリクエストプロパティを変更することもできます。Envoyは、次の3種類のプラグインを提供します。

  • ネイティブEnvoyフィルター:C++で開発されています。このようなプラグインを開発することは困難ですが、より良いパフォーマンスを提供できます。

  • WebAssembly(Wasm)プラグイン:複数のプログラミング言語で開発できます。このようなプラグインの開発はより簡単で、より安全で柔軟性があります。

  • Luaプラグイン:Luaで開発されており、柔軟性は制限されますが、最も簡単に開発できます。

この例では、単純なLuaプラグインを使用して、リクエストのクライアントIPアドレスをリクエストヘッダーに変換します。仮想サービスを使用してヘッダーを照合します。このようにして、異なるソースからのリクエストに対して異なるレスポンスが返されます。

前提条件

ステップ 1:クライアントのソース IP アドレスを確認する

まず、sleepアプリケーションをクライアント(以下、sleepクライアント)としてクラスターにデプロイします。次に、sleepクライアントとローカルクライアントからHTTPBinアプリケーションにアクセスして、異なるソースIPアドレスからのリクエストをテストします。

説明

ローカルクライアントとは、特定のシナリオで操作を実行するユーザー端末を指し、パーソナルコンピューター(PC)とElastic Compute Service(ECS)インスタンスが含まれます。たとえば、PCからECSインスタンスにログオンしてからkubectlを使用してContainer Service for Kubernetes(ACK)マネージドクラスターにアクセスする場合、ECSインスタンスがローカルクライアントになります。

  1. kubeconfigファイルの情報に基づいてkubectlを使用してACKクラスターに接続し、sleep.yamlファイルを作成します。

    sleep.yaml ファイルを表示する

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: sleep
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: sleep
      labels:
        app: sleep
        service: sleep
    spec:
      ports:
      - port: 80
        name: http
      selector:
        app: sleep
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sleep
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sleep
      template:
        metadata:
          labels:
            app: sleep
        spec:
          terminationGracePeriodSeconds: 0
          serviceAccountName: sleep
          containers:
          - name: sleep
            image: registry.cn-hangzhou.aliyuncs.com/acs/curl:8.1.2
            command: ["/bin/sleep", "infinity"]
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - mountPath: /etc/sleep/tls
              name: secret-volume
          volumes:
          - name: secret-volume
            secret:
              secretName: sleep-secret
              optional: true
    ---
  2. 次のコマンドを実行して、sleepアプリケーションをデプロイします。

    kubectl apply -f sleep.yaml
  3. 次のコマンドを実行して、ASMイングレスゲートウェイのIPアドレスの環境変数を構成します。イングレスゲートウェイのIPアドレスを照会する方法の詳細については、「Istio リソースを使用してトラフィックを異なるバージョンのサービスにルーティングする」トピックのステップ 3 のサブステップ 1 をご参照ください。

    export ASM_GATEWAY_IP=112.35.xx.xx
  4. 次のコマンドを実行して、ローカルクライアントのIPアドレスを照会します。

    curl ${ASM_GATEWAY_IP}/ip
  5. 次のコマンドを実行して、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 です。
end
  1. Envoyフィルターを作成します。詳細については、「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)
                  end
  2. Envoyフィルターテンプレートをワークロードにバインドするには、目的のEnvoyフィルターテンプレートを見つけて、[アクション] 列の [テンプレートをワークロードにバインド] をクリックします。表示されるページで、[envoyfilter をワークロードにバインド] をクリックします。表示されるダイアログボックスで、[名前空間] ドロップダウンリストから [istio-system] を選択し、[ワークロードタイプ] ドロップダウンリストから [サービス] を選択し、ASMイングレスゲートウェイの対応するサービスを見つけて、目的のサービスの横にある [バインド] をクリックします。サービスの名前は、istio-${ASMイングレスゲートウェイの名前} の形式です。

  3. 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:構成を確認する

  1. ローカルクライアントで次のコマンドを実行します。

    curl ${ASM_GATEWAY_IP}/ip

    期待される出力:

    from my host
  2. kubeconfigファイルの情報に基づいて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 プラグインを作成する」をご参照ください。