WebAssembly for Proxies は、開発者が WebAssembly (Wasm) を使用してポータブルなプラグインを作成できるようにする新しい仕様です。これらのプラグインは、さまざまなプロキシサーバーで実行できます。Service Mesh (ASM) は、WebAssembly for Proxies 仕様をサポートしています。このトピックでは、ASM の Envoy プロキシ用に Go で Wasm プラグインを作成する方法について説明します。
前提条件
バージョンが 1.18 以降の ASM インスタンスにクラスターが追加されていること。ASM インスタンスにクラスターを追加する方法の詳細については、「ASM インスタンスへのクラスターの追加」をご参照ください。
サイドカープロキシの自動インジェクションが有効になっていること。詳細については、「サイドカーインジェクションポリシーの設定」をご参照ください。
イングレスゲートウェイがデプロイされていること。詳細については、「イングレスゲートウェイの作成」をご参照ください。
HTTPBin アプリケーションがデプロイされ、アクセス可能であること。HTTPBin アプリケーションのデプロイ方法の詳細については、「HTTPBin アプリケーションのデプロイ」をご参照ください。
Container Registry Enterprise Edition インスタンスが作成されていること。Container Registry Enterprise Edition インスタンスは、Open Container Initiative (OCI) イメージをサポートしています。詳細については、「Enterprise Edition インスタンスの作成」をご参照ください。
背景情報
Wasm は、新進気鋭のポータブルな実行可能コードのバイナリ形式です。コードは、(ホストにとって) メモリセーフなサンドボックス内で、ネイティブに近い速度で実行されます。サンドボックスには明確に定義されたリソース制約があり、埋め込みホスト環境 (ここではプロキシを指します) と通信するための明確に定義された API を提供します。
Wasm プラグインには、次の利点があります。
俊敏性:Envoy プロキシを再起動することなくプラグインを更新できます。そのため、リクエストは期待どおりに処理されます。
信頼性と隔離:プラグインはリソース制約のあるサンドボックス内にデプロイされるため、クラッシュしても Envoy プロキシを停止させることはありません。
セキュリティ:プラグインは、プロキシと通信するための明確に定義された API を持つサンドボックス内にデプロイされるため、適切に制御されます。
多様性:プラグインは、C++、Go、Rust などの複数のプログラミング言語で記述できます。
Wasm プラグインの詳細については、WebAssembly-in-Envoy.md、および OVERVIEW.md をご参照ください。
設定例
この例では、Go で Wasm プラグインを作成します。プラグインを作成した後、Wasm バイナリファイルを生成し、イメージにパッケージ化します。イメージは OCI イメージリポジトリにアップロードする必要があります。イメージをアップロードした後、ASM で WasmPlugin リソースを設定し、指定された Envoy プロキシにプラグインを適用します。
この例では、リクエストに allow: true ヘッダーが含まれているかどうかをチェックするプラグインを開発します。含まれていない場合、ステータスコード 403 と指定された本文が返されます。含まれている場合、HTTPBin アプリケーションに正常にアクセスできます。
ステップ 1:開発環境の準備
Envoy プロキシ用に Go で Wasm プラグインを開発するには、まず次のツールをインストールする必要があります。
Go:Go コンパイラと関連ツールは、Go プロジェクトを作成するために使用されます。詳細については、「The Go Programming Language」をご参照ください。
Docker:この例では、Docker を使用して OCI イメージをビルドし、プッシュします。
TinyGo:Wasm プラグインの作成には Go を使用します。ただし、公式の Go コンパイラを使用して Go コードを Wasm 形式にコンパイルすることはできません。TinyGo を使用する必要があります。TinyGo のインストール方法の詳細については、「Quick install guide」をご参照ください。
Wasm プラグインが依存する SDK の詳細については、GitHub の Web サイトにある「proxy-wasm-go-sdk」をご参照ください。この Web サイトでは、Proxy-Wasm 用の Go SDK の完全なコードを見つけることができます。他の SDK を使用したい場合は、Proxy-Wasm 用の Go SDK のコードをご参照ください。
ステップ 2:プラグインコードの作成
-
フォルダを作成し、次の内容を含む main.go ファイルを作成します。
作成したフォルダで次のコマンドを実行して、SDK の依存関係を取得します。
go mod init go mod tidy次のコマンドを実行して、コードを Wasm バイナリファイルにコンパイルします。
tinygo build -o plugin.wasm -scheduler=none -target=wasi main.goplugin.wasm ファイルが生成されます。このファイルは Wasm バイナリ実行可能ファイルです。
ステップ 3:Wasm プラグインの OCI イメージを作成し、Container Registry Enterprise Edition インスタンスへのプッシュ
ステップ 2 で作成したフォルダに、次の内容を含む Dockerfile ファイルを作成します。
FROM scratch ADD ./plugin.wasm ./plugin.wasm次のコマンドを実行して、イメージを作成します。
docker build -t header-authorization:v0.0.1 .-
イメージリポジトリを作成します。詳細については、「Coraza Wasm プラグインを使用して ASM ゲートウェイに WAF を実装する」トピックのステップ 1 のサブステップ 2.a と 2.b をご参照ください。
この例では、名前空間は
test-oci、リポジトリ名はheader-authorizationです。次の図は、作成されたリポジトリを示しています。リポジトリ詳細ページの [イメージガイド] の [レジストリにイメージをプッシュ] セクションには、
docker loginでレジストリインスタンスにログインし、docker tag [ImageId] <registry-url>/<namespace>/<repository>:[image-version]でイメージにタグを付け、docker push <registry-url>/<namespace>/<repository>:[image-version]でイメージをプッシュするコマンドが記載されています。[ImageId]と[image-version]を実際の値に置き換えてください。Container Registry Enterprise Edition インスタンスにイメージをプッシュする方法の詳細については、前の図の [レジストリにイメージをプッシュ] をご参照ください。
ステップ 4:イングレスゲートウェイへの Wasm プラグインの適用
イメージをプルするための権限を設定します。詳細については、「ステップ 2:イメージをプルするための権限の設定」をご参照ください。
次のコマンドを実行して、
wasm-secretという名前の Secret を作成します。kubectl create secret docker-registry -n istio-system wasm-secret --docker-server=${Domain name of the Container Registry Enterprise Edition instance} --docker-username =${Username} --docker-password =${Password}次の内容を含む asm-plugin.yaml ファイルを作成します。
apiVersion: extensions.istio.io/v1alpha1 kind: WasmPlugin metadata: name: header-authorization namespace: istio-system spec: imagePullPolicy: IfNotPresent imagePullSecret: wasm-secret selector: matchLabels: istio: ingressgateway url: oci://${Domain name of the Container Registry Enterprise Edition instance}/test-oci/header-authorization:v0.0.1 phase: AUTHNkubectl を使用して kubeconfig ファイルの情報に基づいて ASM インスタンスに接続します。次に、次のコマンドを実行して、Wasm プラグインを ASM インスタンスに適用します。
kubectl apply -f wasm-plugin.yaml
ステップ 5:Wasm プラグインの有効化の検証
イングレスゲートウェイが存在するデータプレーン上のクラスターの kubeconfig ファイルを使用し、次のコマンドを実行して、イングレスゲートウェイに適用された Wasm プラグインのデバッグロギング機能を有効にします。
kubectl -n istio-system exec ${Name of the pod where the ingress gateway resides} -c istio-proxy -- curl -XPOST "localhost:15000/logging?wasm=debug"次のコマンドを実行して、イングレスゲートウェイ経由で公開されている HTTPBin アプリケーションにアクセスします。
curl ${IP address of the ingress gateway}/status/418期待される出力:
Forbidden by ASM Wasm Pluginイングレスゲートウェイが存在する Pod のログを表示します。
ログのサンプル:
2024-03-08T08:16:46.747394Z debug envoy wasm external/envoy/source/extensions/common/wasm/context.cc:1168 wasm log istio-system.header-authorization: request header: 'allow' is , only true can passthrough thread=24 {"bytes_received":"0","bytes_sent":"28","downstream_local_address":"xxxxxxx","downstream_remote_address":"xxxxxxxx","duration":"0","istio_policy_status":"-","method":"GET","path":"/status/418","protocol":"HTTP/1.1","request_id":"780c8493-13e4-4f97-9771-486efe30347c","requested_server_name":"-","response_code":"403","response_flags":"-","route_name":"httpbin","start_time":"2024-03-08T08:16:46.747Z","trace_id":"-","upstream_cluster":"outbound|8000||httpbin.default.svc.cluster.local","upstream_host":"-","upstream_local_address":"-","upstream_service_time":"-","upstream_response_time":"-","upstream_transport_failure_reason":"-","user_agent":"curl/8.4.0","x_forwarded_for":"xxxxxx","authority_for":"xxxxxx"}-
次のコマンドを実行して、イングレスゲートウェイ経由で公開されている HTTPBin アプリケーションにアクセスします。
curl ${IP address of the ingress gateway}/status/418 -H "allow: true"期待される出力:
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`この出力は、HTTPBin アプリケーションに正常にアクセスできることを示しています。
TinyGo におけるメモリリーク
TinyGo を使用してコンパイルされた Envoy プロキシ用の Wasm プラグインにはメモリリークが存在します。proxy-wasm-go-sdk コミュニティでは、コンパイルの最適化のために nottinygc を使用することを推奨しています。nottinygc を使用してコンパイルを最適化するには、次の手順を実行します。
main.go ファイルの先頭に次の
importコードを追加します。import _ "github.com/wasilibs/nottinygc"依存関係が見つからない場合は、
go mod tidyコマンドを実行して依存関係を自動的にダウンロードできます。次のコマンドを実行してコードをコンパイルします。
tinygo build -o plugin.wasm -gc=custom -tags='custommalloc nottinygc_envoy' -target=wasi -scheduler=none main.go上記のコマンドは、
-gcおよび-tagsパラメーターを設定します。詳細については、「nottinygc」をご参照ください。