WebVM: Tailscale経由のフルネットワーキングによるWebAssemblyでのLinux仮想化
WebVMは、ブラウザ上で完全にクライアントサイドで動作する仮想Linux環境です。
CheerpX(WebAssemblyによるx86仮想化技術)をベースにしています。強力なJITリコンパイルエンジンとext2ブロックベースのファイルシステムにより、大規模なユースケースの実行が可能です: GCC / Clang / Python / Node.js / Rubyやその他多くのものがすぐにサポートされます。
しかし、重要なことが欠けていました。
ネットワーキングはWebVMで最も要望の多かった機能で、それには理由があった。ネットワーキングがないと、ターミナル経由でしかデータを入出力できず、OSイメージに含まれているものしか使えないからです。
この機能を追加する際の主な難点は、ブラウザがUDPやTCPのような低レベルのプロトコルへのアクセスを公開しないことです。できるのはHTTP(S)だけで、それもCORSポリシーによって厳しく制限されます。
では、WebSocketはどうでしょうか?WebSocket接続は、"Upgrade "ヘッダーを持つHTTP接続から始まります。その後、アップグレードが承認されると、WebSocketプロトコルが引き継がれます。WebSocketパケットにも独自のヘッダーがあります。そのため、通常のTCPソケットに透過的に接続することはできません。
任意のソケットに接続するためには、プロトコルのアップグレードを実行し、宛先に送信する前にWebSocketパケットをアンラップする(逆方向にはその逆を行う)プロキシサーバーが必要です。
このプロキシサーバーをホストすると、新たな問題が発生します:
・サーバー側のインフラにお金を払って維持する必要があり、ユーザー数に応じて拡張しなければなりません。
・サーバーはユーザーの代わりにネットワークリクエストを実行するので、私たちはトラフィックに対して法的責任を負うことになる。このサービスは悪意のある行為者によって悪用される可能性があります。
2つ目の問題を解決するためには、ユーザーに認証を求め、ネットワークの使用状況を把握し、事実上VPNプロバイダーになる必要があります。
では、この"VPNプロバイダー"業務を、もっと適任の人間に任せることができるとしたらどうでしょうか?
ブラウザーから直接利用できるVPNサービスが見つかれば、1つ目の問題も解決し、サーバー・インフラを自分たちで用意する必要もなくなります。
Tailscaleの紹介
TailscaleはWireGuardプロトコルに基づくVPNサービスです。ネットワーク内のすべてのマシンのWireGuardキーを管理し、ユーザーの認証を行うコントロール・プレーンが含まれています。
TailscardはWireGuardの上に構築されており、WireGuardは通信にUDPを使用するため、振り出しに戻ったように思う人もいるでしょう。
ですがTailscaleの特徴のひとつとして、メッシュ・ネットワークでマシン同士を直接接続できることが挙げられます。これは、NATトラバーサルのためのSTUNサーバーを提供することで実現しています。
STUNサーバーでさえNATを突破できないことがあるため、Tailscaleは代替メカニズムとしてDERPサーバーを提供しています。
DERPDERP(Detoured Encrypted Routing Protocol)サーバーは、2つのピアが直接接続できない場合にトラフィックを中継するために使用されます。最も厄介なファイアウォールをも回避できるように設計されているため、通常のHTTPSとウェブソケットを使用して通信します。
これがまさに必要なものなのです!
あとは、Tailscaleのコントロール・プレーン・プロトコル、DERPプロトコル、WireGuardプロトコルをブラウザで再実装すれば完了です。
ほんの冗談!幸運なことに、Tailscaleの公式クライアント(Goで書かれている)はWasmにコンパイルされています。
ブラウザのsshクライアント(tsconnect)を少し修正し、カスタムTunデバイスを実装することで、JavaScriptのMessageChannelでIPパケットを送受信するだけで、Tailscaleネットワークとの通信に成功しました!
GoとWasmについて
GoのコードをWasmにコンパイルするのがとても簡単なことに驚きました。
環境変数GOOS=js GOARCH=wasmを設定し、$(go env GOROOT)/misc/wasm/wasm_exec.jsをwasmモジュールと一緒に出荷するだけです。
もちろん、依存関係はwasmターゲットをサポートする必要がある(私の場合、Tailscaleの人々が全ての作業をしてくれました)。
欠点はコンパイルされたwasmモジュールのサイズ: 16MBです!
wasm-optもあまり役に立たず、わずか1MBしか削減できませんでした。比較のため、CheerpX VM全体は6MB以下に収まっています。
このため、ネットワーキング・コードは、Tailscaleにログインしようとしたときだけロードされるようになっています。
TCP/IPスタック
驚くほど少しの作業で、ブラウザからIPパケットを交換できるようになりました。残念ながら、ほとんどのアプリケーションは生のIPパケットを送信せず、TCPやUDPを使って通信を行います。
TCP/IPスタックをゼロから作ることもできるが、できれば既存のものを見つけたい。
Lwip(Cで書かれている)は組み込みの世界では一般的な選択肢のようだ。Cheerpを使ってWasmにコンパイルし、MessageChannelネットワーク・インターフェース用の "ドライバー "を追加するのはとても簡単でした。
あとはCheerpXでlwipを使ってネットワーク関連のシステムコールを実装すればOKです。
デモ
理論はもう十分ですね、さて、これで何ができるのでしょうか?
SSH
ネットワーク対応WebVMの最も簡単な使い方は、sshクライアントとして使うことです:
Tailscaleネットワーク内の他のマシン(出口ノードがあればその先も)に、どのブラウザからでもプライバシーを保護した方法でアクセスできます。あなたのキー入力は暗号化されるだけでなく、Tailscaleのサーバには一切触れません。
また、ssh を使って WebVM の内外にファイルを簡単に移動することもできます。コードやデータをインポートして実行したり、作業結果をエクスポートしたりできるようになったので、WebVMで実質的にできることの範囲が広がります。
Full stack webの開発
より野心的な目標は、WebVMをfull-stack開発プラットフォームとして使うこと。
確かに、私たちはまだそこに到達しませんが、ネットワーキングはその目標に向けた重要な一歩です。
以下のデモGIFで確認することができます:
・github.comからPythonのgitリポジトリをダウンロードしているところ。
・pipを使った依存関係のインストール
・Sqliteデータベースを永続ストレージとして含むFlask webアプリケーションを実行し、2つ目のブラウザタブからアクセスする。
・別のWebVMタブからlynxでアクセスする。
・アプリケーションを編集し、gitにコミットし、githubにプッシュバックする。
pipの依存関係をインストールするのは確かに速くはありません(セットアップスクリプトの中には、そこでネイティブコードをコンパイルしているものもある!)が、IndexedDBにバックアップされたファイルシステムのおかげで、その作業は一度だけで済みます。
もちろん、他にも多くの制限があります。例えば、npmはまだ動いていないし、aptも動いていない。しかし、これらの問題を解決するのは特に複雑なことではありませんし、私たちのシスコール・エミュレーション・レイヤーは常に改善されています(ネットワーク・サポートで実行できるアプリケーションのセットを拡張したおかげでもあります)。
試してみる
自分で試してみたい方は、以下の手順でWebVMのネットワーク・アクセスを有効にしてください:
・webvm.ioにアクセスし、右上の "Tailscale Login "をクリックします。
・ネットワークの速度によっては、Tailscale Wasmモジュールがダウンロードされるまでしばらく待つ必要があります。
・Tailscaleの認証情報を使ってログインします。
・公共のインターネットにアクセスしたい場合は、Exit Nodeが必要です。設定方法はこちらを参照してください。Tailscaleネットワーク内のマシンにアクセスするだけなら、必要ありません。
・WebVMタブに戻ります。右上に自分のIPアドレスが表示されます。
・ネットワークリクエストを開始します!
WebVMの短命な性質を考慮して、私たちはエフェメラル・ノードとしてTailscaleにログインします。これは、一定期間操作が行われないと、ノードがTailscaleネットワークから消えてしまうことを意味します。また、タブを再読み込みすると、再度ログインする必要があります。2回目以降は速くなるはずです。
今後の予定
私たちは、ネットワークのサポートがWebVMの可能性を広げることにとても興奮しています。
そして、次に何をするか(ヒント:X11)についてのアイデアを持っていますが、WebVMを何に使いたいかについても聞きたいと思っています。
メールやX (旧Twitter)で連絡をとることもできますし、私たちのDiscordチャンネルでチャットすることもできます。
もし何か試してみてうまくいかなかったら、遠慮なくGitHubでissueを出してください。
Redditでの議論: https://www.reddit.com/r/programming/comments/xx3r83/webvm_linux_virtualization_in_webassembly_with/
Hacker Newsでの議論: https://news.ycombinator.com/item?id=33116245
引用元: https://leaningtech.com/webvm-virtual-machine-with-networking-via-tailscale/
Discussion