[WASM] イベント駆動型フレームワーク Spin

2022.06.02

Introduction

先日はWasmtime(WASMランタイム)を紹介しましたが、
今回はSpinという名前の、
WebAssemblyを使用するイベント駆動型フレームワークについて紹介します。  

SpinはWebアプリ用のフレームワークで、
HTTPリクエストに対してレスポンスを返すWASMモジュールを
作成するためのインターフェイスを提供します。

現状、RustとGoがサポートされていますが、
WASMで動くのでPythonやAssemblyScript、C/C ++などでも作成可能とのことです。

Spinでは、「Httpトリガー」と「Redisトリガー」という2つのタイプの
アプリを作成することができます。 
Httpトリガーは要するにWebサーバーです。
アプリの定義(URL)に基づいて、適切なWASMコンポーネントにルーティングし、
HTTPのリクエスト/レスポンスを行います。

Redisトリガーは、 任意のRedisチャンネルに対するメッセージによって
SpinのWASMコンポーネントを起動することができるタイプのアプリです。

今回はここにある、
Httpトリガータイプのサンプルプロジェクトを作成してみましょう。  

Environment

  • MacBook Pro (13-inch, M1, 2020)
  • OS : MacOS 11.3.1
  • rust : 1.61.0

Setup

Spinを使うには、Githubからダウンロードしてきます。
下記のようにダウンロード&解凍してspinコマンドが実行できれば大丈夫です。

% mkdir spin && cd spin
% curl -L https://github.com/fermyon/spin/releases/download/v0.2.0/spin-v0.2.0-macos-aarch64.tar.gz > spin-v0.2.0-macos-aarch64.tar.gz
% tar xfv spin-v0.2.0-macos-aarch64.tar.gz

% ./spin --help
spin 0.2.0 (4ff1c75 2022-05-12)
The Spin CLI

Try

では、Spinの提供するテンプレートから新しいアプリを作成していきます。

% spin templates list
You have no templates installed. Run
spin templates install --git https://github.com/fermyon/spin
to install a starter set.

まず、Spinリポジトリからテンプレートを構成する必要があります。
template installで現在提供されているテンプレートを取得。

% spin templates install --git https://github.com/fermyon/spin --branch v0.2.0
Copying remote template source
Installing template redis-rust...
Installing template http-rust...
Installing template http-go...
Installing template redis-go...
Installed 4 template(s)

・・・

template listで現在使用可能なテンプレートが表示されます。
GoとRustのHttp/Redisトリガータイプのテンプレートがあります。

% spin templates list
+---------------------------------------------------+
| Name         Description                          |
+===================================================+
| http-go      HTTP request handler using (Tiny)Go  |
| http-rust    HTTP request handler using Rust      |
| redis-go     Redis message handler using (Tiny)Go |
| redis-rust   Redis message handler using Rust     |
+---------------------------------------------------+

ではRustのHttpテンプレートタイプでアプリの雛形をつくります。
プロジェクト名とかURLのbase、パスをきめて作成。

% spin new http-rust

Project description: spin http project
Project name: spin-http
HTTP base: /
HTTP path: hello
Invalid value: Input 'hello' does not match pattern '^/\S*$' #正しいパスじゃないと怒られる
HTTP path: /hello

これで最低限必要なファイルはすべて生成されました。
spinアプリはアプリの定義ファイル「spin.toml」と
1つ以上のWASMコンポーネントから構成されます。
spin.tomlは、下記のようなマニフェストファイルになっています。

spin_version = "1"
authors = ["shuta nakamura"]
description = "spin http project"
name = "spin-http"
trigger = { type = "http", base = "/" }
version = "0.1.0"

[[component]]
id = "spin-http"
source = "target/wasm32-wasi/release/spin_http.wasm"
[component.trigger]
route = "/hello"
[component.build]
command = "cargo build --target wasm32-wasi --release"

Httpリクエストをトリガーとするアプリであることを示し、
/helloリクエストに対してWASMモジュール(spin_hello_world.wasm)を
実行することが定義されています。

次にRustで記述されたコンポーネントを見てみます。
↓はsrc/lib.rsのコードです。
http_componentアトリビュートがついており、
これがコンポーネントであることを表しています。
関数自体はリクエストを受け取り、レスポンスを返すシンプルなものです。

use anyhow::Result;
use spin_sdk::{
    http::{Request, Response},
    http_component,
};

/// A simple Spin HTTP component.
#[http_component]
fn spin_http(req: Request) -> Result<Response> {
    println!("{:?}", req.headers());
    Ok(http::Response::builder()
        .status(200)
        .header("foo", "bar")
        .body(Some("Hello, Fermyon".into()))?)
}

spin buildコマンドでビルドを行います。
実際はspin.tomlにあるように、cargo buildをwasm32-wasターゲットで実施しています。

% spin build
Executing the build command for component spin-http: cargo build --target wasm32-wasi --release
    Updating crates.io index
    Updating git repository `https://github.com/fermyon/spin`
    Updating git repository `https://github.com/bytecodealliance/wit-bindgen`
    Updating git repository `https://github.com/deislabs/wasi-experimental-http`
    Updating git repository `https://github.com/bytecodealliance/wit-bindgen`
   Compiling anyhow v1.0.57
   Compiling version_check v0.9.4

・・・


    Finished release [optimized] target(s) in 21.72s
Successfully ran the build command for the Spin components.

中身を見ると、build時にwit-bindgenを使って
witやらjsバインディングやらを生成したりして
Rustのwasmを実行できるようにしてるみたいです。

そして、アプリを実行するにはspin upコマンドを叩く。

% spin up

Serving HTTP on address http://127.0.0.1:3000
2022-06-02T05:12:36.251490Z  INFO spin_http_engine: Serving HTTP on address 127.0.0.1:3000
Available Routes:
  spin-http: http://127.0.0.1:3000/hello

起動したのでcurlで動作確認してみます。

% curl -i http://localhost:3000/hello
HTTP/1.1 200 OK
foo: bar
content-length: 14
date: Thu, 02 Jun 2022 06:00:02 GMT

Hello, Fermyon%

これでシンプルなHttpトリガーのSpinアプリができました。
ちなみに、buildと起動を同時に行うには下記コマンドを実行します。

% spin build --up

Summary

今回はSpinフレームワークのHttpトリガーアプリを動かしてみました。
次回はRedisトリガーのアプリを作ってみようかと思います。

References