wasmの可能性を「理解」したくてwasmCloudをさわってみている。動かしてみたメモや感想などを晒しておく
免責事項
wasmCloud公式のGetting Startedに書いてあるレベルのことしかしていないので、これから学ぶ人は直接そっちを読んだほうがいいと思う。
この記事は単に「副読本」というぐらいの認識でいいかなという感じ。
環境
multipassでセットアップした Ubuntu 22.04 (まだ24にしてない) カーネルの更新もサボってる...。
ubuntu@primary:~$ uname -a Linux primary 5.15.0-118-generic #128-Ubuntu SMP Fri Jul 5 09:30:28 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux
雑に立ち上げ
wash はすぐにインストールできる。
まず必要なプロセスを立ち上げるらしい。
$ wash up >>> ⡋⠁ Starting wadm ... Downloading new wadm from https://github.com/wasmcloud/wadm/releases/download/v0.14.0/wadm-v0.14.0-linux-aarch64.tar.gz >>> ⠈⢙ Starting wadm ... Saved wadm to /home/ubuntu/.wash/downloads/wadm 🏃 Running in interactive mode. 🎛️ To start the dashboard, run `wash ui` 🚪 Press `CTRL+c` at any time to exit 2024-08-25T09:19:54.778375Z INFO async_nats_wrpc: event: connected 2024-08-25T09:19:54.780084Z INFO async_nats_wrpc: event: connected 2024-08-25T09:19:54.785723Z INFO wasmcloud_host::wasmbus: created bucket with 1 replica bucket=LATTICEDATA_default 2024-08-25T09:19:54.787211Z INFO wasmcloud_host::wasmbus: created bucket with 1 replica bucket=CONFIGDATA_default 2024-08-25T09:19:54.790602Z INFO wasmcloud_host::wasmbus: wasmCloud host started host_id="NAM6TTXMMZNG5VLQTE3JMIPCPNXYGCWC45E4VCEYJGHAGLX4CZ7EW4NA"
ドキュメントの通りNATSと、wadmというプロセスが立ち上がった。
\_ wash up \_ /home/ubuntu/.wash/downloads/nats-server -js --addr 127.0.0.1 --port 4222 --pid /home/ubuntu/.wash/downloads/nats.pid --config /home/ubuntu/.wash/downloads/nats.conf \_ /home/ubuntu/.wash/downloads/wadm --nats-server 127.0.0.1:4222 \_ /home/ubuntu/.wash/downloads/v1.2.0/wasmcloud_host
NATS は汎用メッセージングサーバー。仕事でも使ったことがあるが、極めて安定していて使いやすい(特にGoからだとライブラリが整備されていて使いやすい)、その上パフォーマンスが出る、みたいなOSSのPub/Subサーバで、個人的に今回採用されたのも納得。
ちょっと性質が違うけど例えば昔ZeroMQとかを使ったことがある人は、同じような感じで使えたりするので別途試してもいいと思います。
ちなみに NATS はembedded NATS serverという、組み込んで使うより便利なやり方もあるんだけど、これはGoでしかできなくて(NATS serverはGo製のため)、wadmの言語はRustなのでNATSは別立てになっているのだろう。
多分NATSは本当にメッセージの仲介しかしていないはずで、ポイントはwadmにありそう。
READMEを見ると、
- アプリケーションのスペック管理
- stateの監視
- Reconcile周り
が責務ですよと言っており、Kubernetesで言うコントロールプレーン+Kubelet相当を1台で引き受ける、簡易版インスタンスマネージャーといったところだろうか。wasmのインスタンス?ワーカー?は lattice(格子模様) という単位でまとめられているらしい。あと、wadm自身だけでクラスタリング等ができるかは調べていない。
あと、 wasmcloud_host
と言うプロセスが立ち上がってる。これは何。
それぞれのwasmインスタンスはActorという単位で管理される、HostはそれらとOSをWASIで繋ぎます、みたいに読める。では実はこっちがKubelet相当? ちょっと色々いじりながら理解したい感じ。
Hello world
さて、washを使ってプロジェクトのスケルトンが作れそうなので作る。今回はRust。
$ wash new component hello --template-name hello-world-rust 🔧 Cloning template from repo wasmCloud/wasmCloud subfolder examples/rust/components/http-hello-world... 🔧 Using template subfolder examples/rust/components/http-hello-world... 🔧 Generating template... [ 1/62] Done: .gitignore [ 2/62] Done: Cargo.toml [ 3/62] Done: README.md [ 4/62] Done: local.wadm.yaml [ 5/62] Skipped: project-generate.toml [ 6/62] Done: src/lib.rs [ 8/62] Done: wadm.yaml [ 9/62] Done: wasmcloud.toml [10/62] Done: wit/deps/cli/command.wit [11/62] Done: wit/deps/cli/environment.wit [12/62] Done: wit/deps/cli/exit.wit ✨ Done! New project created /home/ubuntu/hello
結構色々なものがつくられるのだが、Cargo.tomlを見るとdependencyに wit-bindgen = "0.30"
が勝手に入ることとなる。
生成された src.rs はこういう感じで:
wit_bindgen::generate!({ generate_all }); use exports::wasi::http::incoming_handler::Guest; use wasi::http::types::*; struct HttpServer; impl Guest for HttpServer { fn handle(_request: IncomingRequest, response_out: ResponseOutparam) { let response = OutgoingResponse::new(Fields::new()); response.set_status_code(200).unwrap(); let response_body = response.body().unwrap(); ResponseOutparam::set(response_out, Ok(response)); response_body .write() .unwrap() .blocking_write_and_flush(b"Hello from Rust!\n") .unwrap(); OutgoingBody::finish(response_body, None).expect("failed to finish response body"); } } export!(HttpServer);
これはパブリッククラウドのFunction as a Serviceのコードを彷彿とさせる。こういう感じのプラットフォームをOSSで動かせるというのは期待が持てるなと思う。
で、wit_bindgenの generate_all
は多分生成されたwitを自動で読んで色々やってくれる感じか? 例えばこういうファイルが生成されている。
package wasi:cli@0.2.0; world command { include imports; export run; }
あと生成された wasmcloud.toml
には
[component] wit_world = "hello" wasm_target = "wasm32-wasi-preview2"
こういう記述もある。なのでここもビルド時に? 参照しそう。
一旦ビルドして動かしてみる(cargoはセットアップすること)。
$ wash build ... Component built and signed and can be found at "/home/ubuntu/hello/build/http_hello_world_s.wasm"
wit/world.wit
というのが生成されたっぽい、これが「関数」のエントリポイントとなりそう。
package wasmcloud:hello; world hello { export wasi:http/incoming-handler@0.2.0; }
デプロイはこう。即で終わる。
$ wash app deploy wadm.yaml Deployed application "rust-hello-world", version "01J64FG1JQ4Y0YRAH4NGK7N636" $ wash app list Name Deployed Version Status rust-hello-world 01J64FG1JQ4Y0YRAH4NGK7N636 Deployed └ HTTP hello world demo in Rust, using the WebAssembly Component Model and WebAssembly Interfaces Types (WIT)
$ curl localhost:8080 Hello from Rust!
できました。
wadm.yaml
をみると、レプリカ数などのKube感あるパラメータを発見できるので、今度色々いじってみよう。
もう一つポイントは、Pythonはすでにサポートされている。これはcomponentize-pyベースでやってるらしいのでバイナリサイズが大きいのかもしれないが、とにかく動くには動くらしい(次回試します)。
If you prefer working in a language that isn't listed here, let us know!
そうなりますよね。
正直、 mruby/edge 的なアプローチじゃなく、 MRI のコア部分(コアとは)をwasmにした後でcomponentize-pyみたいなアプローチでくっつける方も掘り進みがいがあるんだろうなと思うが、いずれにせよ理解の解像度が低い(componentize-pyって何してるの?から)。