コンテナ技術を捨て、 WASIを試す

こんにちは、NTTの藤田です。

Dockerfileを書くのに疲れた?イメージサイズの縮小で1日が終わった?コンテナの起動が遅すぎる?コンテナ技術と悪戦苦闘する皆様のための新技術、アーキテクチャに依存しないポータブルなバイナリフォーマットと数十μsで起動するsandbox環境を実現する、WebAssembly System Interface(WASI)を試してみました。

WebAssembly System Interfaceとは

WASIは、 WebAssembly(WASM)をウェブブラウザ以外の環境で実行するため、 ホストのファイルやネットワークなどの資源に安全にアクセスさせるための仕様です。 具体的には、POSIXに似たAPIが定義されており、WASMのバイナリが、OSが管理する資源にアクセスできるようになります。

WASMは、ネイティブコードなみの速度で動作する、ポータブルなバイナリフォーマットで、OSなどのアーキテクチャを問わず、主要なウェブブラウザでサポートされています。WASMは、安全でサンドボックス化された実行環境上で動作するように設計されています。

CDN事業者のFastly、Cloudflareは、彼らのエッジで実行されるFaaS的なサービスでWASMを使っています。Intelはウェブブラウザ以外でのOSSのWASM実行環境の開発を進めています。様々なWASMの実行環境が登場してきており、標準化を目指したWASIが始まったと思われます。

「Write once, run anywhere」は、Javaが実現済み!JVMも様々な言語から使える!という声も聞こえてきますが、この手の主張を繰り返すと、口だけ動かす老害だと思われてしまうので、試してみましょう。

ランタイム

ホストで、WASMのバイナリフォーマットはそのまま実行できませんので、WASMランタイムが、ネイティブコードに変換して実行します。

WASIの公式サイトでは、WASIをサポートするWASMのランタイムとして、wasmtimeFastlyのLucetがあげられています。公式サイトではとりあげられていませんが、wasmerもWASIサポートをうたっています。公式サイトに掲載されない理由は、wasmerのメインテナのコメントから想像しましょう。

今回は、WASIの関係者が密接に関わっており、実質WASIのリファレンス実装と思われるwasmtimeを使います。

試してみる

現在、CとRustが、WASIに対応していますので、指定したサーバにTCPで接続して、送られてきたデータを表示するだけの、下記の単純なRustのコードで試してみます。

まずは、ネイティブコードで試してみます。上記コードはgithubに置いてありますので、以下のようにコンパイルしてください。

$ git clone https://github.com/fujita/demo.git
$ cd demo/wasi-rust/
$ cargo build
$ ./target/debug/wasi-rust 127.0.0.1
Connected to 127.0.0.1:22
SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.8

想定通り動作しましたので、次は、WASI対応のWASMをコンパイルしますが、最新版のrustが必要です。

$ rustup update
$ rustup install nightly
$ rustup target add wasm32-wasi --toolchain nightly
$ cargo +nightly build --target wasm32-wasi

簡単すぎて、前回のgrpc webの環境構築とは雲泥の差ですね!なお、インターネット上に、コマンドのターゲット名が、wasm32-unknown-wasiとなっているものが沢山見つかると思いますが、数日前に変更されたので、注意してください。

wasmtimeのバイナリはリリースされていませんが、cargo buildコマンドで簡単にコンパイルできます。先ほどコンパイルしたWASMのバイナリを実行してみましょう。

$ wasmtime target/wasm32-wasi/debug/wasi-rust.wasm
thread 'main' panicked at 'Failed to connect: operation not supported on wasm yet', src/main.rs:24:19

あれ?

WASIの現状

原因解析のため、RustのWASIのネットワークのコードを眺めてみましょう。

TcpStreamの実装はなにもなくて、当然、connect()も、さきほどのエラーメッセージを表示して、エラーを返すだけ。

WASIはネットワーク機能をサポートしておらず、もちろん、Rustもwasmtimeもサポートしてません。極端に言うと、WASIにはファイルアクセス以外のリソースにアクセスする機能はないという状況で、コンテナ技術を捨てるどころの話ではなかったですね!

WASIのAPIは、既存のOSよりもセキュアな実行環境を目指すCloudABIの影響を受けていて、コードも流用されています。ネットワークに関しては、Unixのsocket()connect()listen()に相当するAPIがありません。これは、CloudABIのセキュリティモデルでは、ネットワークコネクションは特別なプロセスが管理し、通常のプロセスは、コネクションを作れないためです。

With Flower, we’re trying to move the responsibility of setting up network connections into a separate daemon, called the Switchboard. Processes can register servers on the Switchboard, to which clients can connect. When establishing a connection, the Switchboard creates a socket pair and uses Unix file descriptor passing to hand out socket endpoints to both processes. Special processes, called ingresses and egresses, can push existing socket file descriptors (e.g., IPv4, IPv6) into the Switchboard.

WASI開発者も、ちょっとどうなんだと考えているようで、今後、議論されそうです。

おわりに

WASMがホストのリソースにアクセスするためのAPIを標準化するWASIは始まったばかりで、これから楽しめそうですね!ご興味のある方は、ぜひ、ご連絡ください。