Getting started with proxy-rust-sdk

dorayakikun
6 min readDec 30, 2020

--

Photo by Omar Flores on Unsplash

What is proxy-wasm-rust-sdk ?

It is a library made based on WebAssembly for Proxies.
It makes WebAssembly development easier by implementing prepared traits.

How to use proxy-wasm-rust-sdk

The usage consists of 3 steps.

  1. Add the proxy-wasm dependency to cargo.toml
  2. Create a `_start()` method
  3. Create an implement of arbitrary context

Add the proxy-wasm dependency to cargo.toml

[dependencies]
log = "0.4.8"
proxy-wasm = "0.1.0" # The Rust SDK for proxy-wasm
[lib]
path = "src/lib.rs"
crate-type = ["cdylib"]

It is necessary to add `crate-type = [“cdylib”]`.
(This is the purpose of dynamic loading from another language.)

Create a `_start()` method

#[no_mangle]
pub fn _start() {
proxy_wasm::set_log_level(LogLevel::Trace);
proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(HelloWorld) });
}

Call a set_xxx_context() function to connect arbitrary struct to the below three context traits.

  1. RootContext
  2. StreamContext
  3. HttpContext

Create an implement of arbitrary context

struct HelloWorld;impl Context for HelloWorld {}impl RootContext for HelloWorld {
fn on_vm_start(&mut self, _: usize) -> bool {
info!("ka23 dayo");
self.set_tick_period(Duration::from_secs(5));
true
}
...
}

Add implementation to an arbitrary context.
The tick interval is set to 5 seconds after the info log is output in the above example.

Now all you have to do is build it.
Let’s build it with the following command.

% cargo build — target wasm32-unknown-unknown — release

This should create the Wasm file successfully.
Before we look at how to configure the envoy, let’s take a more in-depth look at how proxy-wasm-rust-sdk works.

What is WebAssembly for Proxies

From here, I will explain about WebAssembly for Proxies.

Quoted from https://github.com/proxy-wasm/spec/blob/master/docs/WebAssembly-in-Envoy.md

The design that the wasm file is called from the native extension of C++ is in the above figure.

Why was it designed this way? Here’s how it happened.

  • envoy is a static binary
  • envoy extension that had to compile at the same time
  • For the above reasons, any envoy extension had to run its envoy binary (in other words, some teams could not use the official envoy binary or the vanilla envoy binary).
  • Extending with dynamically loaded C++ was also considered, but it didn’t match well with the envoy’s active development speed.
  • So they decided to solve this problem by providing WebAssembly and a stable ABI.

At first, the attempt started as the envoy-wasm repository that fork the envoy repository.

And then, WebAssembly for Proxies is published on the following blog on 5th March 2020.

Finally, the envoy-wasm repository merged with the envoy repository on 10th October 2020.

wasm-filter is available in the upstream envoy. (6th December 2020)

The definition of ABI is summarized below.

By the way, the reason why the method to get the ABI version is not a global variable, but a function named proxy_abi_version_X_Y_Z is because…

Considered alternatives: Ideally, this would be exported as a global variable, but existing toolchains have trouble with that (some don’t support global variables at all, some incorrectly export language-specific and not Wasm-generic variables).

Deploying the wasm filter and wasme

Let’s go back to the deployment of the wasm-filter.

% curl -sL https://run.solo.io/wasme/install | sh
% export PATH=$HOME/.wasme/bin:$PATH

For deployment, we will use a client tool called wasme.
When deploying wasm-filter using wasme, we need to create a file called runtime-config.json.

% vi runtime-config.json
{
"type": "envoy_proxy",
"abiVersions": ["v0-097b7f2e4cc1fb490cc1943d0d633655ac3c522f", "v0-4689a30309abf31aee9ae36e73d34b1bb182685f", "v0.2.1"],
"config": {
"rootIds": [
"hello_world"
]
}
}

Once you have done this, you can check the operation by build & deploy.

% wasme build precompiled target/wasm32-unknown-unknown/release/hello_world.wasm --tag hello_world:v0.1
% wasme deploy envoy hello_world:v0.1

This command can create an OCI image from a wasm file. A command called % wasme build rust can create an OCI image directly from a Rust file.

About wasme

wasme is a client tool produced by Solo.io; it is a tool for the WebAssembly Hub, a registry service for the envoy filters.

It has features that push or pull OCI images and has features to deploy locally, istio, and Gloo.

(Side trip — 1) About The WASM OCI Artifact

The definition created by wasme is on the following repository.

The definition created by wasme is on the following repository.

This OCI image is composed of two layers.

  • application/vnd.module.wasm.config.v1+json
  • application/vnd.module.wasm.content.layer.v1+wasm

Of these, the definition of application/vnd.module.wasm.config.v1+json depends on runtime-config.json.

This is the reason why we needed to create runtime-config.json in the previous step.

It can define three configuration values on the runtime-config.json.

  1. type
  2. abiVersions
  3. root_Ids

The value of type is fixed to envoy_proxy. abiVersions specifies the abiVersion to be used in the array. rootIds specifies the rootId that can be used in the provided filters.

Also, for simplicity, you can register only one module in one OCI image.

When you do wasme pull / wasme build, wasme will save the following directories and files directly under ~/.wasme/store/imageref.

  • descriptor.json
  • filter.wasm
  • image_ref
  • runtime-config.json

The conversion to OCI is done by wasme push. (Conversely, in wasme pull, the OCI is extracted to the above file structure in the local caching stage.)

(Side trip — 2) About wasme deploy envoy

You may be wondering why you can check the behavior of wasme deploy envoy so that I will explain the simple process flow.

  1. Get the image of the wasm filter specified by the user (located under ~/.wasme/store)
  2. Add the absolute path to the wasm filter set by the user to the config of the envoy.
  3. Run envoy using docker(*)

* As shown above, we are using docker to deploy to the envoy.

The docker image and envoy config we are using are as follows. (6th December 2020)

  • Image used by default: docker.io/istio/proxyv2:1.5.1
  • The config of envoy used by default: one that filters requests to jsonplaceholder.typicode.com

At the end

Initially, I focused my research on the proxy-wasm-rust-sdk s, but my study’s scope diverged unexpectedly.
On the other hand, I found the envoy filter’s development using Wasm to be an exciting and practical product. (It’s nice to be able to implement it in the language of your choice!)

After doing all this research, I realized the fact that the GetEnvoy Extension Toolkit looks interesting.

I’ll take a look at this one when I get a chance.
Thank you for reading this far.

--

--

dorayakikun
dorayakikun

Written by dorayakikun

Flag of Japan he/him. Web Developer. A founder of the http://rust.tokyo . An organizer of http://RustFest.global . All my own views.

No responses yet