Introduction
WebAssembly(WASM)はブラウザー上で高速に実行することを可能にする
バイナリーフォーマットであり、
いろいろなプログラミング言語で実装することが可能です。
しかし、WASMは単なるJavascriptの一部を高速化するだけの目的でなく、
さらに広い範囲でのWASM実行基盤としても進化しています。
今回はそんなWASM実行基盤の1つ、
wasmCloudを試してみました。
WasmCloud?
wasmCloudは、WASMランタイムだけでなく、
どこでも実行できるWASMモジュールを作成するための分散プラットフォームです。
CNCF Sandbox プロジェクトにもなっています。
AssemblyScriptやTinyGo、Rustなどをつかって
WASMモジュール(wasmCloudでいうActor)を作成できます。
Environment
- MacBook Pro (13-inch, M1, 2020)
- OS : MacOS 12.4
- rust : 1.61.0
Setup
では、wasmCloudをセットアップしてみます。
まずはHomebrewでwasmcloudとwasmCloudのCLIツール(wash)をインストールしましょう。
% brew tap wasmcloud/wasmcloud
% brew install wash
・・・
% wash -V
wash 0.11.0
次に、NATS serverをインストールします。
NATS serverはCNCFの分散メッセージング・ストリーミングプラットフォームです。
(Apache Kafkaとかと同じ系統のミドルウェア)
wasmCloudではNATS serverに依存しているので、こちらも Homebrewでインストールしましょう。
% brew install nats-server
インストールできたらNATSサーバを起動します。
% nats-server --jetstream
[31443] 2022/06/06 16:51:44.327471 [INF] Starting nats-server
[31443] 2022/06/06 16:51:44.327670 [INF] Version: 2.8.4
[31443] 2022/06/06 16:51:44.327674 [INF] Git: [not set]
[31443] 2022/06/06 16:51:44.327678 [INF] Name: NBIMPZ5HC6REUMZ7GZFCB5HHNGBWNTROI3GRFZG4RHGTMIS72YLPDZ5F
[31443] 2022/06/06 16:51:44.327682 [INF] Node: 09kWZkEV
[31443] 2022/06/06 16:51:44.327684 [INF] ID: NBIMPZ5HC6REUMZ7GZFCB5HHNGBWNTROI3GRFZG4RHGTMIS72YLPDZ5F
[31443] 2022/06/06 16:51:44.328762 [INF] Starting JetStream
[31443] 2022/06/06 16:51:44.330078 [INF] _ ___ _____ ___ _____ ___ ___ _ __ __
[31443] 2022/06/06 16:51:44.330088 [INF] _ | | __|_ _/ __|_ _| _ \ __| /_\ | \/ |
[31443] 2022/06/06 16:51:44.330091 [INF] | || | _| | | \__ \ | | | / _| / _ \| |\/| |
[31443] 2022/06/06 16:51:44.330093 [INF] \__/|___| |_| |___/ |_| |_|_\___/_/ \_\_| |_|
[31443] 2022/06/06 16:51:44.330095 [INF]
[31443] 2022/06/06 16:51:44.330098 [INF] https://docs.nats.io/jetstream
[31443] 2022/06/06 16:51:44.330100 [INF]
[31443] 2022/06/06 16:51:44.330102 [INF] ---------------- JETSTREAM ----------------
[31443] 2022/06/06 16:51:44.330109 [INF] Max Memory: 12.00 GB
[31443] 2022/06/06 16:51:44.330113 [INF] Max Storage: 210.21 GB
[31443] 2022/06/06 16:51:44.330115 [INF] Store Directory: "/var/folders/lj/lgpgz22d01d4d4thn86sksnw0000gp/T/nats/jetstream"
[31443] 2022/06/06 16:51:44.330118 [INF] -------------------------------------------
[31443] 2022/06/06 16:51:44.331195 [INF] Listening for client connections on 0.0.0.0:4222
[31443] 2022/06/06 16:51:44.331525 [INF] Server is ready
さきほどインストールしたwasmcloudをforegroundで起動します。
% bin/wasmcloud_host foreground
16:52:51.344 [info] Wrote "./host_config.json"
16:52:51.345 [info] Wrote "~/.wash/host_config.json"
16:52:51.345 [info] Connecting to control interface NATS without authentication
16:52:51.345 [info] Connecting to lattice rpc NATS without authentication
16:52:51.346 [info] Host XXXXXXXXXXXXX (blue-wind-5028) started.
16:52:51.346 [info] Valid cluster signers: XXXXXXXXXXXXX
16:52:51.356 [info] Started wasmCloud OTP Host Runtime
16:52:51.360 [info] Running WasmcloudHostWeb.Endpoint with cowboy 2.9.0 at :::4000 (http)
16:52:51.362 [info] Access WasmcloudHostWeb.Endpoint at http://localhost:4000
16:52:51.459 [info] Lattice cache stream created or verified as existing (0 consumers).
16:52:51.459 [info] Attempting to create ephemeral consumer (cache loader)
16:52:51.461 [info] Created ephemeral consumer for lattice cache loader
wasmcloudが起動しました。
http://localhost:4000にアクセスし、
ダッシュボード(GUIでwasmCloudのアプリを作成できるツール)が
表示できればインストール成功です。
Try
では、ダッシュボードとCLI(wash)をつかってwasmCloudアプリを作成してみます。
Actorの作成
Actorとは、
wasmCloudにおいて最小単位のモジュールです。
これはWASMモジュールとなっており、後述するProviderとリンクして処理を行います。
今回はHTTPリクエストを受けとり、メッセージを返すシンプルなActorを作成します。
wash new actorでWASMモジュールの雛形を作成します。
このプロジェクトはRustのプロジェクトです。
% wash new actor hello --template-name hello
🔧 Using template subfolder `actor/hello`...
🔧 Generating template ...
[ 1/14] Done: .cargo/config.toml
[ 7/14] Done: .gitignore
[ 8/14] Done: Cargo.toml
[ 9/14] Done: Makefile
[10/14] Done: README.md
[11/14] Done: actor.mk
[12/14] Skipped: project-generate.toml
[13/14] Done: src/lib.rs
✨ Done! New project created /path/your/hello
Makefileも自動で生成され、makeコマンドで簡単にWASMの登録や起動ができます。
(そのはずなのですが、私の環境ではmake startが動かなかったので別の方法で行う)
src/lib.rs(Actor本体のコード)みてみましょう。
handle_request関数でリクエスト時の処理を記述します。
ここではリクエストを受け取り、nameクエリパラメータを取得して文字列レスポンスを返しています。
use wasmbus_rpc::actor::prelude::*;
use wasmcloud_interface_httpserver::{HttpRequest, HttpResponse, HttpServer, HttpServerReceiver};
#[derive(Debug, Default, Actor, HealthResponder)]
#[services(Actor, HttpServer)]
struct HelloActor {}
/// Implementation of HttpServer trait methods
#[async_trait]
impl HttpServer for HelloActor {
/// Returns a greeting, "Hello World", in the response body.
/// If the request contains a query parameter 'name=NAME', the
/// response is changed to "Hello NAME"
async fn handle_request(
&self,
_ctx: &Context,
req: &HttpRequest,
) -> std::result::Result<HttpResponse, RpcError> {
let text = form_urlencoded::parse(req.query_string.as_bytes())
.find(|(n, _)| n == "name")
.map(|(_, v)| v.to_string())
.unwrap_or_else(|| "World".to_string());
Ok(HttpResponse {
body: format!("Hello {}", text).as_bytes().to_vec(),
..Default::default()
})
}
}
Actorのビルド&起動
helloアクターをビルドします。
% rustup target add wasm32-unknown-unknown
% cargo build --target /wasm32-unknown-unknown --release
Downloaded 1 crate (28.1 KB) in 0.51s
Compiling proc-macro2 v1.0.39
Compiling unicode-ident v1.0.0
Compiling syn v1.0.96
・・・
ビルドに成功すると、hello.wasmが作成されます。
次にこのwasmモジュールに署名をします。
※署名しないとActorとして登録できない
% wash claims sign -q --name hello ./target/wasm32-unknown-unknown/release/hello.wasm
・・・
署名すると、hello.wasmと同じ階層にhello_s.wasmという署名ずみwasmファイルが生成されます。
% wash claims inspect ./target/wasm32-unknown-unknown/release/hello_s.wasm
hello - Module
Account ABTTYWV3WF3MQYQNK7NE7DTUOSNWRPY23MBDL2YTKOHDGECUUN5OZE7H
Module MAQEK2N5YGOO2NR7JET2SEE7T3FIVFOGEDCDKMJCFHJAR5CZ272SEPEF
Expires never
Can Be Used immediately
Version None (0)
Call Alias (Not set)
Capabilities
Tags
None
署名ずみwasmができたら、ダッシュボードでActorの登録をします。
Start Actor -> From Fileでさきほどのhello_s.wasmを指定して、
submitします。
statusがHealthyになったらOKです。
今回はファイルを指定しましたが、OCI(Open Container Initiative)レジストリを指定することもできます。
Providerの登録
ダッシュボードでProvidersとしてWebサーバーを起動させます。
hello ActorはWebサーバーが必要なので、
HTTPサーバー機能プロバイダーを起動します。
ダッシュボードでStart Provider -> From Registoryを選択して、
OCI Referenceに「wasmcloud.azurecr.io/httpserver:0.14.10」と入力します。
※おそらくProvider作成もwash CLIでできます
Define Link
ActorとProviderをwashコマンドで関連づけます。
ダッシュボードにActionsにある青いボタンをクリックすると、
モジュールIDがコピーされるのでそれぞれ指定してください。
% wash ctl link put <ActorのモジュールID> <ProviderのモジュールID> wasmcloud:httpserver address=0.0.0.0:8567
Published link (ActorのモジュールID) <-> (ProviderのモジュールID) successfully
Contract IDにはwasmcloud:httpserver を指定し、
Values に address=0.0.0.0:8567 を入力しています。
こうするとlocalhost:8567に対するアクセスにActorが応答します。
curlを使って動作確認してみます。
% curl localhost:8567
Hello World
% curl "localhost:8567?name=syuta"
Hello syuta
ちゃんとActorが動いてますね。
Summary
今回はWASM実行基盤であるwasmCloudを使ってみました。
これ以外にもKrustlet(k8s内でWASMワークロードを実行するkubelet)とか、
おもしろそうなものがあるのでいろいろ試していきたいと思います。