WASM実行基盤、wasmCloudを試してみる

2022.06.08

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

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)とか、
おもしろそうなものがあるのでいろいろ試していきたいと思います。

References