プラグイン コードを準備する

Service Extensions プラグイン用に作成するカスタムコードは、他のサービスがアクセスできるように、パッケージ化して Artifact Registry にアップロードする必要があります。このページでは、プラグイン コードを作成し、コードをパッケージ化して、Artifact Registry リポジトリにアップロードする方法について説明します。

この機能は Media CDN のプレビュー版です。

Service Extensions については、Service Extensions の概要をご覧ください。

始める前に、プラグイン コードの作成に関するベスト プラクティスを確認してください。

その他の例については、プラグインのコードサンプルをご覧ください。

始める前に

  1. Google Cloud アカウントにログインします。 Google Cloudを初めて使用する場合は、 アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. Google Cloud CLI をインストールします。

  6. 外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。

  7. gcloud CLI を初期化するには、次のコマンドを実行します。

    gcloud init
  8. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  9. Verify that billing is enabled for your Google Cloud project.

  10. Enable the Network Services, Network Actions, Artifact Registry, Cloud Build, Cloud Logging, and Cloud Monitoring APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  11. Google Cloud CLI をインストールします。

  12. 外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。

  13. gcloud CLI を初期化するには、次のコマンドを実行します。

    gcloud init

ツールチェーンを設定する

C++

Proxy-Wasm C++ SDK を使用すると、デベロッパーは C++ を使用して Service Extensions 用の WebAssembly(Wasm)プラグインを実装できます。この SDK は、C++ WebAssembly ツールチェーン Emscripten と、protobuf などの他のライブラリ(Abseil はオプション)を使用します。

C++ で記述されたプラグインのビルドは、これらのツールとライブラリの特定のバージョンに依存するため、Proxy-Wasm C++ SDK によって提供される Docker イメージを使用することをおすすめします。このページの C++ の手順では、Docker メソッドを使用します。Docker を使用せずに C++ プラグインをビルドするには、Proxy-Wasm C++ SDK のドキュメントをご覧ください。

  1. Docker をまだインストールしていなければ、インストールします。Docker は、 Google Cloud インタラクティブ シェル環境である Cloud Shell に含まれています。

  2. Proxy-Wasm C++ SDK のコピーをダウンロードします。最も簡単な方法は、Git リポジトリのクローンを作成することです。

    git clone https://github.com/proxy-wasm/proxy-wasm-cpp-sdk.git
    
  3. SDK で提供されている Dockerfile から Proxy-Wasm C++ SDK Docker イメージをビルドします。

    cd proxy-wasm-cpp-sdk
    docker build -t wasmsdk:v3 -f Dockerfile-sdk .
    

    コマンドが SDK ライブラリと依存関係のビルドを完了すると、結果の Docker イメージが指定されたタグ(この例では wasmsdk:v3)に関連付けられます。

Go

Proxy-Wasm Go SDK は、フル機能の Go SDK を提供します。Go は、優れたパフォーマンスと、純粋な Go で記述されたサードパーティ ライブラリの豊富なサポートを提供します。

Go ツールチェーン v1.24.0 をインストールします

Rust

Service Extensions のカスタマイズ機能は、WebAssembly と Proxy-Wasm を使用して提供されます。WebAssembly は、多くのプログラミング言語をサポートしています。Google は、優れた WebAssembly サポートを提供し、Proxy-Wasm がフル機能の Rust SDK を提供しているため、Rust を推奨しています。Rust は、優れたパフォーマンスと強力な型安全性も提供します。

  1. Rust ツールチェーンをインストールします

    インストール プロセスの最後に、コンソールに表示された手順に沿って構成プロセスを完了します。

  2. Rust ツールチェーンに Wasm のサポートを追加します。

    rustup target add wasm32-wasip1
    

プラグイン パッケージを作成する

C++

  1. proxy-wasm-cpp-sdk とは別の新しいディレクトリを作成します。

    mkdir myproject
    
  2. ディレクトリに、次の内容の Makefile を作成します。

    # Express any dependencies
    PROTOBUF=     # full / lite / none
    WASM_DEPS=    # absl_base re2 ...
    
    # Include the SDK Makefile
    PROXY_WASM_CPP_SDK=/sdk
    include ${PROXY_WASM_CPP_SDK}/Makefile
    
  3. 同じディレクトリにプラグイン用の C++ ソースファイルを追加します。C++ ソースファイルの名前は、Makefile がターゲットとする Wasm ファイルと一致する必要があります。ただし、.wasm 接尾辞は .cc に置き換えられます。この例では、ソースファイルの名前は myproject.cc にする必要があります。

  4. プラグイン コードをソースファイルに追加します。

    次のサンプル ソースコードは、リクエスト ホストを書き換え、レスポンス ヘッダーを出力するプラグインです。

    #include "proxy_wasm_intrinsics.h"
    
    class MyHttpContext : public Context {
     public:
      explicit MyHttpContext(uint32_t id, RootContext* root) : Context(id, root) {}
    
      FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                           bool end_of_stream) override {
        LOG_INFO("onRequestHeaders: hello from wasm");
    
        // Route Extension example: host rewrite
        if (replaceRequestHeader(":authority", "service-extensions.com") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :authority header");
        }
        if (replaceRequestHeader(":path", "/") != WasmResult::Ok) {
          LOG_ERROR("Failed to replace :path header");
        }
        return FilterHeadersStatus::Continue;
      }
    
      FilterHeadersStatus onResponseHeaders(uint32_t headers,
                                            bool end_of_stream) override {
        LOG_INFO("onResponseHeaders: hello from wasm");
    
        // Traffic Extension example: add response header
        if (addResponseHeader("hello", "service-extensions") != WasmResult::Ok) {
          LOG_ERROR("Failed to add response header");
        }
        return FilterHeadersStatus::Continue;
      }
    };
    
    static RegisterContextFactory register_StaticContext(
        CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(RootContext));

    onRequestHeaders メソッドは、Service Extensions が呼び出すコールバックです。

Go

  1. プラグイン用の新しいディレクトリを作成します。

    mkdir go-plugin
    
  2. ディレクトリで、Go ツールを使用して go.mod ファイルを作成します。

    go mod init go-plugin
    
  3. 同じディレクトリに、main.go という名前のソースファイルを作成し、プラグイン コードをファイルに追加します。

    次のサンプル ソースコードは、リクエスト ホストを書き換え、レスポンス ヘッダーを出力するプラグインです。

    package main
    
    import (
    	"fmt"
    
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
    	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
    )
    
    func main() {}
    func init() {
    	proxywasm.SetVMContext(&vmContext{})
    }
    
    type vmContext struct {
    	types.DefaultVMContext
    }
    
    type pluginContext struct {
    	types.DefaultPluginContext
    }
    
    type httpContext struct {
    	types.DefaultHttpContext
    }
    
    func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
    	return &pluginContext{}
    }
    
    func (*pluginContext) NewHttpContext(uint32) types.HttpContext {
    	return &httpContext{}
    }
    
    func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onRequestHeaders: hello from wasm")
    
    	// Route Extension example: host rewrite
    	err := proxywasm.ReplaceHttpRequestHeader(":authority", "service-extensions.com")
    	if err != nil {
    		panic(err)
    	}
    	err = proxywasm.ReplaceHttpRequestHeader(":path", "/")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    
    func (ctx *httpContext) OnHttpResponseHeaders(numHeaders int, endOfStream bool) types.Action {
    	defer func() {
    		err := recover()
    		if err != nil {
    			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
    		}
    	}()
    	proxywasm.LogInfof("onResponseHeaders: hello from wasm")
    
    	// Traffic Extension example: add response header
    	err := proxywasm.AddHttpResponseHeader("hello", "service-extensions")
    	if err != nil {
    		panic(err)
    	}
    	return types.ActionContinue
    }
    

    OnHttpRequestHeaders メソッドは、Service Extensions が呼び出すコールバックです。

  4. ライブラリの依存関係をダウンロードして固定するには、go mod tidy を実行します。

    go mod tidy
    

Rust

  1. Rust のパッケージ マネージャーである Cargocargo new コマンドを使用して、Rust パッケージ ディレクトリを作成します。

    cargo new --lib my-wasm-plugin
    

    このコマンドにより、Rust パッケージのビルド方法を記述するために更新できる cargo.toml ファイルと、プラグイン コードを保存する src ディレクトリを含むディレクトリが作成されます。

  2. cargo.toml ファイルを更新して、パッケージのビルドに必要なパラメータを指定します。

    [package]
    name = "my-wasm-plugin"
    version = "0.1.0"
    edition = "2021"
    
  3. Proxy-Wasm Rust SDK とロギング サポートを依存関係として登録するには、dependencies セクションを追加します。次に例を示します。

    [dependencies]
    proxy-wasm = "0.2"
    log = "0.4"
    
  4. プラグインに必要な動的ライブラリをビルドするには、lib セクションを追加します。次に例を示します。

    [lib]
    crate-type = ["cdylib"]
    
  5. コンパイル済みプラグインのサイズを小さくするには、profile.release セクションを追加します。次に例を示します。

    [profile.release]
    lto = true
    opt-level = 3
    codegen-units = 1
    panic = "abort"
    strip = "debuginfo"
    
  6. プラグイン コードを 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_http_context(|_, _| -> Box<dyn HttpContext> { Box::new(MyHttpContext) });
    } }
    
    struct MyHttpContext;
    
    impl Context for MyHttpContext {}
    
    impl HttpContext for MyHttpContext {
        fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onRequestHeaders: hello from wasm");
    
            // Route extension example: host rewrite
            self.set_http_request_header(":authority", Some("service-extensions.com"));
            self.set_http_request_header(":path", Some("/"));
            return Action::Continue;
        }
    
        fn on_http_response_headers(&mut self, _: usize, _: bool) -> Action {
            info!("onResponseHeaders: hello from wasm");
    
            // Traffic extension example: add response header
            self.add_http_response_header("hello", "service-extensions");
            return Action::Continue;
        }
    }

    on_http_request_headers メソッドは、Service Extensions が呼び出すコールバックです。

プラグインをコンパイルする

C++

プラグインをコンパイルするには、Makefile と C++ プラグインのソースファイルが置かれているディレクトリから次のコマンドを実行します。

docker run -v $PWD:/work -w /work wasmsdk:v3 /build_wasm.sh myproject.wasm

このコマンドは、現在のディレクトリを Docker イメージ内の work ディレクトリにマッピングし、Docker イメージで提供される build_wasm.sh スクリプトを実行してプラグイン コードをビルドします。コンパイル オペレーションが正常に完了すると、コンパイルされた Wasm バイトコードを含む myproject.wasm ファイルが現在のディレクトリに作成されます。

Docker イメージを使用してプラグイン コードを初めてコンパイルすると、Emscripten によって標準ライブラリが生成されます。これらを Docker イメージにキャッシュに保存して、毎回再生成する必要がないようにするには、最初のコンパイルが成功した後に、標準ライブラリを含むイメージを commit します。

docker commit `docker ps -l | grep wasmsdk:v3 | awk '{print $1}'` wasmsdk:v3

C++ プラグインのビルドの詳細については、Proxy-Wasm C++ SDK のドキュメントをご覧ください。

Go

プラグイン コードをコンパイルするには、go build コマンドを実行します。

env GOOS=wasip1 GOARCH=wasm go build -buildmode=c-shared -o main.wasm main.go

コンパイルが成功すると、現在のディレクトリに main.wasm ファイルが作成されます。

Rust

プラグイン コードをコンパイルするには、cargo build コマンドを実行します。

cargo build --release --target wasm32-wasip1

ビルドが正常に完了すると、Finished release [optimized] target(s) メッセージが表示されます。Envoy に精通している場合は、Envoy にプラグインを読み込んで、その動作を確認することをおすすめします。

コンパイルされたプラグイン コードを Artifact Registry にアップロードする

コンパイルされたプラグイン コードを Artifact Registry リポジトリにアップロードして、 Google Cloud サービスがアクセスできるようにします。

グローバル ロードバランサで Service Extensions を使用している場合は、マルチリージョン us ロケーションのリポジトリを使用します。リージョン ロードバランサを使用している場合は、同じリージョンまたは同じ大陸のマルチリージョン ロケーションにあるリポジトリを使用します。

プラグインをグローバル ロードバランサにアタッチすると、Service Extensions は Artifact Registry リポジトリから世界各地の独自のストレージに Wasm モジュールをコピーします。そのため、リポジトリのロケーションは、ロードバランサに送信されるリクエストのレイテンシに影響しません。リージョン ロードバランサの場合、プラグインはロードバランサが配置されている同じリージョンのロケーションにコピーされます。

Service Extensions プラグインは、Artifact Registry の汎用リポジトリまたは Docker リポジトリにアップロードできます。

スタンドアロン バイナリをより直接的に管理するには、汎用リポジトリを使用して Wasm ファイルを保存することをおすすめします。このオプションはプレビュー版です。

汎用リポジトリ

  1. ローカルの package/ ディレクトリを作成し、公開可能なプラグイン モジュールをコピーします。プラグイン アーティファクトの名前は plugin.wasm にする必要があります。次のサンプル コマンドは、Rust でビルドされたプラグイン アーティファクトをコピーします。

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  2. --repository-formatgeneric に設定して、Artifact Registry リポジトリを作成します。

  3. リポジトリに必要な権限が付与されていることを確認します。

  4. Wasm モジュールを汎用アーティファクトとしてリポジトリにアップロードするには、gcloud artifacts generic upload コマンドを使用します。

    gcloud artifacts generic upload \
        --project=PROJECT_ID \
        --location=LOCATION \
        --repository=REPOSITORY \
        --source=package/plugin.wasm \
        --package=PACKAGE \
        --version=VERSION
    

    次のように置き換えます。

    • PROJECT_ID: 実際の Google Cloud プロジェクト ID
    • LOCATION: リポジトリのリージョンまたはマルチリージョンのロケーション
    • REPOSITORY: Wasm モジュールをアップロードするリポジトリの名前
    • PACKAGE: ファイルのパッケージ名
    • VERSION: Wasm モジュールのバージョン

    アップロードが完了したら、name ラベルで指定された汎用アーティファクトの名前(次の例の add_header_plugin:v4 など)をメモします。この名前は、プラグインまたはプラグイン バージョンを作成するときに指定します。

    Uploading file: plugin.wasm...done.
    '@type': type.googleapis.com/google.devtools.artifactregistry.v1.GenericArtifact
    createTime: '2025-06-16T11:02:25.080248Z'
    name: projects/my-project/locations/us/repositories/my-generic-repo/genericArtifacts/add_header_plugin:v4
    updateTime: '2025-06-16T11:02:25.080248Z'
    version: v4
    
  5. アーティファクトが Artifact Registry に正常にアップロードされたことを確認するには、gcloud artifacts files list コマンドを実行し、リストに PACKAGE:VERSION:plugin.wasm という名前のファイルがあることを確認します。

     gcloud artifacts files list \
         --project=PROJECT_ID \
         --location=LOCATION \
         --repository=REPOSITORY
    

Docker リポジトリ

  1. --repository-formatdocker に設定して、Artifact Registry リポジトリを作成します。

  2. リポジトリに必要な権限が付与されていることを確認します。

  3. ローカルの package/ ディレクトリを作成し、公開可能なプラグイン アーティファクトをそのディレクトリにコピーします。次のサンプルは、Rust でビルドされたプラグイン アーティファクトをコピーします。

    mkdir -p package && cp -f target/wasm32-wasip1/release/my_wasm_plugin.wasm package/plugin.wasm
    
  4. package/Dockerfile ファイルを作成し、次の内容を追加します。

    FROM scratch
    COPY plugin.wasm plugin.wasm
    
  5. Cloud Build または Docker を使用して、プラグイン コードをパッケージ化します。

    Cloud Build

    1. 次の内容の package/cloudbuild.yaml ビルド構成ファイルを作成します。

      steps:
        - name: 'gcr.io/cloud-builders/docker'
          args: [ 'build', '--no-cache', '--platform', 'wasm',
                '-t', 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG', '.' ]
      images: [ 'LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG' ]
      

      プラグインを保存するパスは次の形式にする必要があります。

      LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      次のように置き換えます。

      • LOCATION: リポジトリのリージョンまたはマルチリージョン ロケーション
      • PROJECT_ID: Google Cloud コンソール プロジェクト ID
      • REPOSITORY: イメージを保存するリポジトリの名前
      • IMAGE: リポジトリ内のコンテナ イメージの名前(例: us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin
      • IMAGE_TAG: コンテナに割り当てるイメージタグ(例: production
    2. プラグイン コンテナをビルドして Artifact Registry にアップロードするオペレーションをトリガーします。

      gcloud builds submit --config package/cloudbuild.yaml package/
      

    Docker

    1. Docker をまだインストールしていなければ、インストールします。Docker は、 Google Cloud インタラクティブ シェル環境である Cloud Shell に含まれています。

    2. Artifact Registry で認証するように Docker を構成します。次に例を示します。

      gcloud auth login
      gcloud auth configure-docker LOCATION-docker.pkg.dev
      gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://LOCATION-docker.pkg.dev
      
    3. コンテナ イメージをビルドします。

      docker build --no-cache --platform wasm -t my-wasm-plugin package/
      
    4. ローカル イメージにリポジトリ イメージ名をタグ付けするには、イメージタグを使用します。

      docker tag my-wasm-plugin LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      

      次のように置き換えます。

      • LOCATION: リポジトリのリージョンまたはマルチリージョン ロケーション
      • PROJECT_ID: Google Cloud コンソール プロジェクト ID
      • REPOSITORY: イメージを保存するリポジトリの名前
      • IMAGE: リポジトリ内のコンテナ イメージの名前(例: us-docker.pkg.dev/my-project/my-repo/my-wasm-plugin)。
      • IMAGE_TAG: コンテナに割り当てるイメージタグ(production など)
    5. タグ付きコンテナ イメージを Artifact Registry にアップロードします。

      docker push LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE:IMAGE_TAG
      
  6. イメージが Artifact Registry に正常にアップロードされたことを確認するには、gcloud artifacts docker images list コマンドを実行します。

    gcloud artifacts docker images list LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE \
        --include-tags
    

構成ファイルを準備してアップロードする

プラグインは、必要に応じて構成データを受け取ることがあります。このデータは、実行時のプラグインの動作に影響を与える可能性があります。構成データはテキストまたはバイナリで、プラグインで受け入れられる任意の形式にできます。構成データのサイズが大きい場合は、構成ファイルを Artifact Registry にアップロードする必要があります。

構成データを読み取るプラグイン コードを記述する

C++

構成データは、ルート コンテキスト オブジェクトの onConfigure メソッドに渡されます。このオブジェクトは、プラグインの起動時に 1 回インスタンス化され、プラグインをホストする Wasm ランタイムの存続期間中アクティブなままになります。ルート コンテキスト オブジェクトは、RootContext クラスのインスタンスまたは RootContext のサブクラスのインスタンスです。

プラグイン コードは、RegisterContextFactory 値を使用して、ルート コンテキストに使用するクラスを制御できます。たとえば、次のプラグイン コードは、ルート コンテキスト インスタンスとストリーム コンテキスト インスタンスに使用するクラスとして MyRootContextMyHttpContext を登録します。次に、プラグイン構成データからシークレット値を読み取ります。このシークレット値は、ストリーム コンテキスト インスタンスがルート コンテキスト オブジェクトを介してアクセスできます。

#include <string>
#include <string_view>

#include "proxy_wasm_intrinsics.h"

class MyRootContext : public RootContext {
 public:
  explicit MyRootContext(uint32_t id, std::string_view root_id)
      : RootContext(id, root_id) {}

  bool onConfigure(size_t config_len) override {
    auto buffer = getBufferBytes(WasmBufferType::PluginConfiguration, 0, config_len);
    if (!buffer) {
      LOG_ERROR("Failed to retrieve plugin configuration");
      return false;
    }
    secret_ = buffer->toString();
    return true;
  }

  const std::string& secret() const { return secret_; }

 private:
  std::string secret_;
};

class MyHttpContext : public Context {
 public:
  explicit MyHttpContext(uint32_t id, RootContext* root)
      : Context(id, root),
        secret_(static_cast<MyRootContext*>(root)->secret()) {}

  FilterHeadersStatus onRequestHeaders(uint32_t headers,
                                       bool end_of_stream) override {
    // Use secret here...
    LOG_INFO("secret: " + secret_);
    return FilterHeadersStatus::Continue;
  }

 private:
  const std::string& secret_;
};

static RegisterContextFactory register_MyHttpContext(
    CONTEXT_FACTORY(MyHttpContext), ROOT_FACTORY(MyRootContext));

Go

構成データは、OnPluginStart の実行中に読み取られます。これは、プラグインの起動時に PluginContext 構造体でランタイムが 1 回実行するメソッド レシーバです。構成データは、プラグインをホストする Wasm ランタイムの存続期間中に変更されません。PluginContext は、初期化ロジックの実行や、多くのリクエストにわたる状態の維持に役立ちます。

プラグイン コードは、VMContextNewPluginContext メソッドを実装することで、PluginContext に使用するコンテキストを制御できます。このメソッドは PluginContext をインスタンス化します。PluginContextHttpContext コンテキストをインスタンス化します。

たとえば、次のプラグイン コードは VMContext を登録します。これは、構成データの読み取りと、必要に応じた HttpContext コンテキストのインスタンス化を担当するコンテキストである PluginContext をインスタンス化します。PluginContext は、プラグイン構成データからシークレット値を読み取り、PluginContext コンテキスト内に保存して、NewHttpContextHttpContext に渡します。

package main

import (
	"fmt"

	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm"
	"github.com/proxy-wasm/proxy-wasm-go-sdk/proxywasm/types"
)

func main() {}
func init() {
	proxywasm.SetVMContext(&vmContext{})
}

type vmContext struct {
	types.DefaultVMContext
}

type pluginContext struct {
	types.DefaultPluginContext
	secret string
}

type httpContext struct {
	types.DefaultHttpContext
	pluginContext *pluginContext
}

func (*vmContext) NewPluginContext(contextID uint32) types.PluginContext {
	return &pluginContext{}
}

func (ctx *pluginContext) OnPluginStart(int) types.OnPluginStartStatus {
	config, err := proxywasm.GetPluginConfiguration()
	if err != nil {
		proxywasm.LogErrorf("Error reading the configuration: %v", err)
		return types.OnPluginStartStatusFailed
	}
	if config == nil {
		proxywasm.LogError("Configuration is nil")
		return types.OnPluginStartStatusFailed
	}
	ctx.secret = string(config)
	return types.OnPluginStartStatusOK
}

func (ctx *pluginContext) NewHttpContext(uint32) types.HttpContext {
	return &httpContext{pluginContext: ctx}
}

func (ctx *pluginContext) Secret() string {
	return ctx.secret
}

func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
	defer func() {
		err := recover()
		if err != nil {
			proxywasm.SendHttpResponse(500, [][2]string{}, []byte(fmt.Sprintf("%v", err)), 0)
		}
	}()
	// Use secret here...
	proxywasm.LogInfof("secret: %v", ctx.pluginContext.Secret())
	return types.ActionContinue
}

Rust

構成データは RootContext トレイトから読み取られます。このトレイトは、プラグインの起動時に 1 回インスタンス化され、プラグインをホストする Wasm ランタイムのライフタイムの間アクティブなままになります。RootContext トレイトは、多くのリクエストにわたってオペレーションを実行したり、状態を維持したりする場合に便利です。

プラグイン コードは、set_root_context メソッドを介してルート コンテキストに使用されるクラスを制御できます。ルート コンテキストはストリーム コンテキストをインスタンス化します。たとえば、次のプラグイン コードは MyRootContext を登録します。これにより、必要に応じて MyHttpContext がインスタンス化されます。ルート コンテキストは、プラグイン構成データからシークレット値を読み取り、ストリーム コンテキストに渡します。

use log::info;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
use std::rc::Rc;

proxy_wasm::main! { {
    proxy_wasm::set_log_level(LogLevel::Trace);
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(MyRootContext { secret: Rc::new("missing".to_string()) })
    });
} }

struct MyRootContext {
    secret: Rc<String>,
}

impl Context for MyRootContext {}

impl RootContext for MyRootContext {
    fn on_configure(&mut self, _: usize) -> bool {
        if let Some(config_bytes) = self.get_plugin_configuration() {
            self.secret = Rc::new(String::from_utf8(config_bytes).unwrap())
        }
        true
    }

    fn create_http_context(&self, _: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(MyHttpContext {
            secret: self.secret.clone(), // shallow copy, ref count only
        }))
    }

    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}

struct MyHttpContext {
    secret: Rc<String>,
}

impl Context for MyHttpContext {}

impl HttpContext for MyHttpContext {
    fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
        // Use secret here...
        info!("secret: {}", self.secret);
        Action::Continue
    }
}

構成ファイルをアップロードする

on_configure でプラグインに配信されるデータのサイズが 900 KiB を超える場合は、コンパイル済みプラグイン コードを Artifact Registry にアップロードするで説明されている方法に沿って、Artifact Registry にアップロードします。この場合、構成ファイルは plugin.config という名前で保存します(plugin.wasm ではありません)。

次のステップは、プラグインを作成することです。

プラグインの作成時に、アップロードされた Wasm モジュールまたはイメージの URI を指定する必要があります。

プラグイン コードの新しいバージョンを作成する

プラグイン コードの新しいバージョンを作成するには、プラグイン ファイルを編集します。次に、前のセクションで説明したように、プラグイン コードをコンパイルして再パッケージ化し、Artifact Registry にアップロードします。

コールバック

Wasm にコンパイルするコードでは、任意のメソッドや関数を定義できますが、その一部には特別な意味があります。これらは、選択した言語の Proxy-Wasm SDK で定義され、Proxy-Wasm アプリケーション バイナリ インターフェース(ABI)仕様にマッピングされるメソッドです。Service Extensions は、ユーザー リクエストに応じて、またはプラグインのライフサイクル イベントに応じて、これらのコールバックを呼び出します。

これらのコールバックは、通常呼び出される順序で次の表に示されています。

コールバックの名前と説明 C++ メソッド名 Go メソッド名 Rust メソッド名
START_PLUGIN: プラグインの起動時に呼び出されます。 RootContext::onStart VMContext.OnVmStart RootContext::on_vm_start
CONFIGURE_PLUGIN: プラグインの起動後に呼び出され、プラグインに構成データを提供します。 RootContext::onConfigure PluginContext.OnPluginStart RootContext::on_configure
CREATE_CONTEXT: 新しいストリーム コンテキストが作成されたときに呼び出されます。各ストリームはクライアントの HTTP リクエストに対応します。 Context::onCreate PluginContext.NewHttpContext RootContext::create_http_context
HTTP_REQUEST_HEADERS: HTTP リクエスト ヘッダーを処理するために呼び出されます。 Context::onRequestHeaders HttpContext.OnHttpRequestHeaders HttpContext::on_http_request_headers
HTTP_REQUEST_BODY: HTTP リクエスト本文のチャンクを処理するために繰り返し呼び出されます。 Context::onRequestBody HttpContext.OnHttpRequestBody HttpContext::on_http_request_body
HTTP_RESPONSE_HEADERS: HTTP レスポンス ヘッダーを処理するために呼び出されます。 Context::onResponseHeaders HttpContext.OnHttpResponseHeaders HttpContext::on_http_response_headers
HTTP_RESPONSE_BODY: HTTP レスポンス本文のチャンクを処理するために繰り返し呼び出されます。 Context::onResponseBody HttpContext.OnHttpResponseBody HttpContext::on_http_response_body
DONE: プラグインの処理が完了したときに呼び出されます。 Context::onDone HttpContext.OnHttpStreamDone Context::on_done
DELETE: クライアント HTTP リクエストに対応するストリーム コンテキスト オブジェクトが削除されたときに呼び出されます。 Context::onDelete (コールバックなし) (コールバックなし)

次のステップ