Envoy での WebAssembly サポートと WebAssembly Hub, WASM OCI Image Specification について

## はじめに

この記事では Envoy で WebAssembly がサポートされるまでの背景と WebAssembly Hub, WASM OCI Image Specification に関する情報をまとめていきます。
<img width="740" alt="スクリーンショット 2020-06-15 19.08.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49924/8a8e7be3-3cbe-7eb5-eaac-60b7cbef23c6.png">

## Envoy で WebAssembly がサポートされるまでの背景

2016年に Istio で Envoy が採用されて以来、Istio ではユーザーの多様なニーズを満たすために豊富な拡張性が提供されてきました。Service Mesh の Data Plane の機能を拡張したい理由としては、独自のアクセス制御システムとの統合、独自のメトリクスを使用した Observability の向上、独自のプロトコルのサポートなどが挙げられます。

Istio 1.4 以前は [Mixer](https://archive.istio.io/v1.4/docs/reference/config/policy-and-telemetry/mixer-overview/) を使用して外部システム（例: アクセス制御システム, テレメトリデータ収集システム）との連携を行い、独自のプロトコルのサポートなど Mixer で実現できない要件がある場合には、Envoy 用に C++ で新しい Filter を開発して Envoy 自体に統合して再コンパイルしたオリジナルの Envoy を利用するアプローチが取られてきました。

しかし、これらのアプローチには課題が存在していました。Mixer でいうとレイテンシーやリソース使用率などパフォーマンスへの影響があり、Envoy の独自拡張でいうと Filter を C++ で開発する制限があったことや、機能追加やバグ修正などでリリースの度に新バイナリの配布とローリングリスタートが必要なことでダウンタウンタイム発生のリスクなどがありました。

上記の課題に加えて、Istio における拡張性を単一スタックに集約したいという考えが Istio コミュニティにはありました。そこで Envoy の拡張性の実装として挙がったのが WebAssembly です。

## WebAssembly とは

WebAssembly（以下 Wasm, "was-em" と発音します[^1]） は C++, Go, Rust, Java, Typescript など30以上のプログラミング言語でコンパイルできるバイナリコードの新しいフォーマット（仕様）で、Web ブラウザ上でネイティブコード並の実行速度でアプリケーションを実行することを目的に策定されました。主要ブラウザにおいて動作する HTML, CSS, Javascript に続く4番目の標準言語となります。

Wasm はクライアント側で利用するテクノロジーとして登場しましたが、サーバー側での利用にも多くの利点がありました。Wasm ランタイムがメモリーセーフでありセキュリティの観点からサンドボックス化されていること、周辺エコシステムの開発が活発であること、W3C で標準化が進められている [WebAssembly System Interface（WASI）](https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/)により Wasm プログラムに OS のような抽象化を提供できることなどが挙げられます。

## Envoy での WebAssembly サポート

ここまでの背景を受けて、Istio コミュニティ主導で Envoy で Wasm を利用した拡張性をサポートすることが開始（[envoyproxy/envoy#4272](https://github.com/envoyproxy/envoy/issues/4272)）されました。実装としては Google の [V8 engine](https://v8.dev) に組み込まれている Wasm ランタイムが使用されており、並行して Wasm 拡張（以下 Wasm Filter）を開発するための SDK やドキュメント整備などの作業も進められています。

Wasm ランタイムがサポートされたことで Envoy の Filter を C++ 以外の任意の言語でも実装することが可能になり、更には Envoy の拡張を動的に行えるようになった（Wasm バイナリを xDS で配布して動的ロードなイメージ）ことで拡張機能のポータビリティが向上しました。また、拡張機能である Wasm Filter 自体がリソース制限されたサンドボックス内で展開されるためリソース使用量を制限できる点や、Envoy から分離されていることにより Wasm Filter がクラッシュしても Envoy に影響を及ぼすことがない点など様々な利点もあります。ちなみに Envoy と Wasm Filter の通信で利用されるインターフェースは Proxy-Wasm と呼ばれる [WebAssembly for Proxies (ABI specification)](https://github.com/proxy-wasm/spec) で仕様が定義されている? ようですが、今回は深堀りしません。

そして、Istio 1.5 のリリースで Istio における拡張性モデルを Wasm を利用して Envoy に統合することが [アナウンス](https://istio.io/latest/news/releases/1.5.x/announcing-1.5/#a-new-model-for-extensibility) されました。Istio 1.5 以降では Wasm Filter をサポートした Envoy である [envoy-wasm](https://github.com/envoyproxy/envoy-wasm/) が同梱されており Alpha 機能（デフォルト無効）として利用することができます。envoy-wasm は [envoyproxy/envoy](https://github.com/envoyproxy/envoy) のフォークで envoy-wasm での実装をアップストリームにマージする作業も並行して進められています。

また、Istio 1.5 のリリースのタイミングで [Mixer Adapters](https://archive.istio.io/v1.4/docs/reference/config/policy-and-telemetry/adapters/) による拡張性モデルは Deprecated（Mixer Adapters として提供されていたものは Wasm Filter に移行されていく）になりました。Mixer 自体も将来的には廃止される予定ですが、Istio からの廃止後はレガシーなユースケースに対応するためにコミュニティプロジェクトでのメンテナンスは続けられていくとのことでした。

上記のアナウンスと同時期に Solo.io が Google と Istio コミュニティと協力して Envoy の Wasm Filter の 作成/共有/デプロイ を簡略化することを目的に、Wasm Filter を OCI イメージとして バンドル/配布 するための仕様である WASM OCI Image Specification と、そのイメージのプラットフォームとなる WebAssembly Hub を公開しました。

## WebAssembly Hub とは

![logo-wide.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49924/b1f61d4b-a97d-e116-6877-ad485e5eae91.png)

[WebAssembly Hub](https://webassemblyhub.io/) は Wasm Filter を OCI イメージとして 管理/配布 するためのプラットフォームです。WebAssembly Hub を利用することで Wasm Filter の build/push/pull/deploy が Docker コンテナと同じくらい簡単に行うことができるようになります。

WebAssembly Hub 上で公開されている Wasm Filter を Envoy で利用する場合には、専用の CLI である [wasme](https://github.com/solo-io/wasme)（"was-mi" と発音します[^1]）を使用してデプロイします。 また、[Wasme Operator（WebAssembly Hub Operator）](https://docs.solo.io/web-assembly-hub/latest/tutorial_code/wasme_operator/) を使用することで Istio により展開されている Kubernetes 内の Envoy に対して CRD ベースで Wasm Filter を自動的にデプロイすることも可能です。

以下は wasme の使用例となります。

```bash
$ wasme --version
wasme version 0.0.20

# WASM OCI Image の Build
$ wasme build assemblyscript -t webassemblyhub.io/ryysud/add-header:v0.1 .
...
INFO[0010] adding image to cache...                      filter file=/tmp/wasme333251785/filter.wasm tag="webassemblyhub.io/ryysud/add-header:v0.1"
INFO[0010] tagged image                                  digest="sha256:7775dee33290aa14eccd7357559bb99a1a9fe67cc734958ba0aa519b1485a351" image="webassemblyhub.io/ryysud/add-header:v0.1"

# WASM OCI Image の Build によって生成されるファイル
$ ll ~/.wasme/store/df0adcb62382d67405723a1cbc270ad2
total 56
-rw-r--r--  1 ryysud  staff   224B Jun 16 00:12 descriptor.json
-rw-r--r--  1 ryysud  staff    12K Jun 16 00:12 filter.wasm
-rw-r--r--  1 ryysud  staff    40B Jun 16 00:12 image_ref
-rw-r--r--  1 ryysud  staff   166B Jun 16 00:12 runtime-config.json

# WASM OCI Image の一覧表示
$ wasme list
NAME                                TAG  SIZE    SHA      UPDATED
webassemblyhub.io/ryysud/add-header v0.1 12.6 kB 7775dee3 16 Jun 20 00:12 JST

# WASM OCI Image の Push
$ wasme push webassemblyhub.io/ryysud/add-header:v0.1
INFO[0000] Pushing image webassemblyhub.io/ryysud/add-header:v0.1 
INFO[0002] Pushed webassemblyhub.io/ryysud/add-header:v0.1 
INFO[0002] Digest: sha256:847a15889f02afdb18d92003a2b3f9b121019070bdcb806f438227fbc4bb2221 

# WASM OCI Image の Deploy
$ wasme deploy istio webassemblyhub.io/ryysud/add-header:v0.1
...
```

## WASM OCI Image Specification とは

[WASM OCI Image Specification](https://github.com/solo-io/wasm-image-spec) は Wasm Module を OCI イメージとしてバンドルするための仕様です。一般的な仕様となるため Wasm Filter やブラウザ拡張など使用用途が限定されておらず、あらゆる種類の Wasm Module に対応しています。

Wasm OCI Image は以下のファイルから構成されており、Wasm Module を使用するアプリに特化して設計された OCI イメージ仕様の拡張という位置づけとなります。

- Wasm バイナリファイル（Wasm Module）
- Wasm ランタイムで利用される JSON 形式の設定ファイル（Runtime Configuration）
- JSON 形式の Wasm バイナリファイルのメタデータ

Envoy では Wasm OCI Image を ローカルディスク（WebAssembly Hub から pull してローカルキャッシュに保存して読み込むイメージ）または http でロードして実行する機能がサポートされています。

ちなみに WASM OCI Image Specification では Wasm Module で構築された Envoy のカスタムフィルターは Envoy Wasm Filter と定義されているので、Envoy における Wasm 拡張は Wasm Filter と呼ぶのが良いかと思います。

## さいごに

今回は Envoy で WebAssembly がサポートされるまでの背景と WebAssembly Hub、WASM OCI Image Specification を紹介しました。Istio の拡張性が今後 Envoy に集約されていくので引き続き Wasm 周りの動向を追いかけていきたいと思います。

次回は wasme を利用して Wasm Filter を開発して WebAssembly Hub で公開後に、Wasm Filter を Envoy にデプロイするまでの流れをまとめていきたいと思います。また、Wasm Operator の利用方法や Proxy-Wasm と呼ばれる [WebAssembly for Proxies (ABI specification)](https://github.com/proxy-wasm/spec) などを深堀りできていないので、時間があるときにそれらも調査していきたいと思います。

## 参考資料

- [Redefining extensibility in proxies - introducing WebAssembly to Envoy and Istio - Istio Blog](https://istio.io/latest/blog/2020/wasm-announce/)
- [サービスメッシュのIstio、機能拡張にWebAssemblyを採用。EnvoyにV8エンジンのWebAssemblyランタイムを統合 - Publickey](https://www.publickey1.jp/blog/20/istiowebassemblyenvoyv8webassembly.html)
- [WebAssembly がネットワーク プロキシにもたらす拡張性 - Google Developers](https://developers-jp.googleblog.com/2020/04/webassembly.html)
- [Introducing the WebAssembly Hub, a service for building, deploying, sharing, and discovering Wasm extensions for Envoy Proxy - Solo.io Blog](https://www.solo.io/blog/introducing-the-webassembly-hub-a-service-for-building-deploying-sharing-and-discovering-wasm/)
- [Announcing an extended and improved WebAssembly Hub to bring the power of WebAssembly to Envoy and Istio - Solo.io Blog](https://www.solo.io/blog/an-extended-and-improved-webassembly-hub-to-helps-bring-the-power-of-webassembly-to-envoy-and-istio/)

[^1]: 自分が探したところ公式な発音は明記されていなかったので、Solo.io の Slack で [質問](https://solo-io.slack.com/archives/CRN22JMLG/p1590477677127600) したところ [wasme の開発者](https://github.com/solo-io/wasme/graphs/contributors) から普段はこのように発音しているという回答が得られたので、それに基づいて記載しています。