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

Alibaba Cloud Service Mesh:ASM の Envoy プロキシ向け Wasm プラグインを Rust で記述する

最終更新日:Jan 13, 2025

Service Mesh (ASM) は、カスタム処理ロジックを実装するために、Envoy プロキシ内への Wasm プラグインのデプロイをサポートしています。 Proxy-Wasm コミュニティは、Wasm 開発用の Rust SDK を提供しています。このトピックでは、ASM の Envoy プロキシ向け Wasm プラグインを Rust で記述する方法について説明します。

背景情報

Wasm は、ネイティブバイナリに近い実行効率を提供し、ランタイムサンドボックスを備えているため、セキュリティが強化されます。 現在、Wasm には、組み込みの ガベージコレクション を使用する言語でのパフォーマンスの問題など、いくつかの欠点があります。 そのため、C++ や Rust など、手動メモリ管理が可能な言語を使用することをお勧めします。 C++ と比較して、Rust は現時点ではコンパイルとビルドの段階でより便利ですが、学習曲線は少し高くなっています。 実際の状況に基づいて選択できます。

前提条件

使用方法

このトピックでは、Rust で Wasm プラグインを記述する方法について説明します。 Wasm バイナリを生成した後、それをイメージにパッケージ化します。 イメージをビルドした後、イメージサービスの OCI イメージリポジトリにアップロードします。 アップロードが完了したら、ASM で Wasm プラグインリソースを設定して、指定された Envoy プロキシに適用します。

このプラグインは、リクエストヘッダー allow: true がリクエストに存在するかどうかを判断するために使用されます。 存在しない場合は、403 ステータスコードと指定されたレスポンス本文が返されます。 存在する場合は、HTTPBin アプリケーションに正常にアクセスできます。

手順 1:開発環境を準備する

  1. rustup をインストールします。 具体的な操作については、「Rust のインストール」をご参照ください。

  2. 次のコマンドを実行して、Wasm バイナリをコンパイルするために必要なツールチェーンをインストールします。

    rustup target add wasm32-wasi

    すでにインストールされている場合は、次のコマンドを実行して Rust を更新します。

    rustup update

手順 2:プラグインを記述する

  1. 新しいプラグインディレクトリ rust-example を作成し、このディレクトリに切り替えて、次のコマンドを実行します。

    cargo init --lib
  2. 生成された Cargo.toml ファイルに次の内容を追加します。

    [lib]
    // C/C++ から呼び出すことができる動的ライブラリであることを宣言します。
    crate-type = ["cdylib"]
    
    [dependencies]
    log = "0.4.8"
    proxy-wasm = "0.2.2"
  3. src/lib.rs に次の内容を追加します。

    use log::info;
    use proxy_wasm::traits::*;
    use proxy_wasm::types::*;
    
    proxy_wasm::main! {{
        proxy_wasm::set_log_level(LogLevel::Trace);
        proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(HttpHeadersRoot) });
    }}
    
    struct HttpHeadersRoot;
    
    // いくつかの基本的なユーティリティ関数。この行を追加すると、さまざまなユーティリティ関数を self で直接呼び出すことができます。
    // 例:self.set_property(path, value)
    impl Context for HttpHeadersRoot {}
    
    impl RootContext for HttpHeadersRoot {
        fn get_type(&self) -> Option<ContextType> {
            Some(ContextType::HttpContext)
        }
    
        fn create_http_context(&self, context_id: u32) -> Option<Box<dyn HttpContext>> {
            Some(Box::new(HttpHeaders { context_id }))
        }
    }
    
    struct HttpHeaders {
        context_id: u32,
    }
    
    impl Context for HttpHeaders {}
    
    impl HttpContext for HttpHeaders {
        fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
            info!("#{} wasm-rust: on_http_request_headers", self.context_id);
    
            match self.get_http_request_header("allow") {
                Some(allow) if allow == "true" => {
                    Action::Continue
                }
                _ => {
                    info!("#{} wasm-rust: allow ヘッダーが見つからないか true ではないため、デフォルトで拒否します", self.context_id);
                    self.send_http_response(
                        403, 
                        vec![("Content-Type", "text/plain")],
                        Some(b"ASM Wasm プラグインによって禁止されています。rust バージョン\n"),
                    );
                    Action::Pause
                }
            }
        }
    }
  4. 次のコマンドを実行して、プラグインをコンパイルします。

    cargo build --target wasm32-wasi --release

    コンパイルが成功すると、ターゲットファイルが生成され、最終的な WASM バイナリファイルは target/wasm32-wasi/release/rust_example.wasm になります。

手順 3:OCI イメージを作成し、Container Registry にプッシュする

次の内容で Dockerfile を作成します。

FROM scratch
// 生成された wasm バイナリファイルをイメージにコピーし、plugin.wasm に名前を変更します。
ADD target/wasm32-wasi/release/rust_example.wasm ./plugin.wasm

イメージのビルドとプッシュの手順については、「Wasm プラグインの OCI イメージを作成し、Container Registry Enterprise Edition インスタンスにプッシュする」をご参照ください。 イメージ名とタグを指定します。

手順 4:Wasm プラグインをゲートウェイに適用する

具体的な操作手順については、「イングレスゲートウェイに Wasm プラグインを適用する」をご参照ください。 Wasm プラグインで設定された url が正しいイメージアドレスを指定していることを確認します。

手順 5:プラグインが有効であることを確認する

  1. データプレーンクラスターの kubeconfig を使用して、次のコマンドを実行し、ゲートウェイの Wasm コンポーネントのデバッグログを有効にします。

    kubectl -n istio-system exec ${gateway pod name} -c istio-proxy -- curl -XPOST "localhost:15000/logging?wasm=debug"
  2. 次のコマンドを実行して、HTTPBin アプリケーションにアクセスします。

    curl ${ASM gateway IP}/status/418

    予期される出力:

    ASM Wasm プラグインによって禁止されています。rust バージョン
  3. ゲートウェイ Pod のログを確認します。 ログの例は次のとおりです。

    2024-09-05T08:33:31.079869Z	info	envoy wasm external/envoy/source/extensions/common/wasm/context.cc:1195	wasm log istio-system.header-authorization: #2 wasm-rust: on_http_request_headers	thread=35
    2024-09-05T08:33:31.079943Z	info	envoy wasm external/envoy/source/extensions/common/wasm/context.cc:1195	wasm log istio-system.header-authorization: #2 wasm-rust: allow ヘッダーが見つからないか true ではないため、デフォルトで拒否します	thread=35
    {"authority_for":"xx.xx.xx.xx","bytes_received":"0","bytes_sent":"43","downstream_local_address":"xx.xx.xx.xx:80","downstream_remote_address":"xx.xx.xx.xx:xxxxx","duration":"0","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"d5250d1a-54b3-406d-8bea-5a51b617b579","requested_server_name":"-","response_code":"403","response_flags":"-","route_name":"httpbin","start_time":"2024-09-05T08:33:31.079Z","trace_id":"-","upstream_cluster":"outbound|8000||httpbin.default.svc.cluster.local","upstream_host":"-","upstream_local_address":"-","upstream_response_time":"-","upstream_service_time":"-","upstream_transport_failure_reason":"-","user_agent":"curl/8.9.0-DEV","x_forwarded_for":"xx.xx.xx.xx"}
  4. リクエストヘッダー allow: true を追加し、ゲートウェイの httpbin アプリケーションに再度アクセスします。

    curl ${ASM gateway IP}/status/418 -H "allow: true"

    予期される出力:

        -=[ teapot ]=-
    
           _...._
         .'  _ _ `.
        | ."` ^ `". _,
        \_;`"---"`|//
          |       ;/
          \_     _/
            `"""`

    ご覧のとおり、リクエストヘッダー allow: true を追加するとアクセスが成功し、プラグインが有効になります。