In the CNCF ecosystem, Envoy
, an open source service proxy developed by Lyft, is a very common choice in service mesh networking. In a previous post
we discussed that both Consul and Istio leverage Envoy. Were you aware that you can extend Envoy’s capabilities with WebAssembly?
What is WebAssembly? WebAssembly, or Wasm as it is often abbreviated, is not so much of a programming language as it is a specification for a binary instruction format that can be run in sandboxed virtual machines. This approach allows you to extend Envoy’s capabilities in a secure and isolated environment without interfering with service operation.
The Wasm support for Envoy is a little different than vanilla WebAssembly, however. Envoy actually provides a Wasm environment that adheres to an ABI specification called proxy-wasm
This presents a challenge for Go developers because even though Go natively supports Wasm architecture target as a build flag
, it is incompatible with Envoy. Instead, you must also
supply a target OS build flag for Wasi
. This OS target is not part of the standard Go library, so the only way for you to build your extension is to use TinyGo
, an alternative Go implementation meant for programs running on embedded systems and microcontrollers.
At Speedscale, we use a Wasm extension to provide our integration and support for Istio installations. And while we prefer to develop our applications in Go, using TinyGo was ill-suited for our needs. If you intend on using TinyGo for Wasm extensions, you should be aware of certain caveats and concessions need to be made. See https://tinygo.org/docs/reference/lang-support/
for more details.
There are of course other language SDKs, C++
appearing to be the favorites. Either one of these are fine choices since the SDKs adhere to the same
ABI. For the purpose of demonstration in this post, I will focus on the Rust implementation.
Outside of the
itself, there is little available documentation about how to actually
develop these extensions in practice. The ABI spec is built around callback functions that Envoy invokes when certain events occur, the majority of which occur in what’s referred to as a Context. These Contexts can be thought of as a logical pairing between a request and a response – something very similar to what Speedscale does.
Event callbacks expose points during a context’s lifecycle when certain information is available, such as HTTP request headers, HTTP response trailers, etc. And as we will see later, these events need to be correlated using a context id value.
Let’s dive in! We’ll work through a simple example of an extension that adds an additional header value to an HTTP request. To get started, let’s initialize our project and fill in a few basic details in a
file so we can build our extension. Ensure that the wasm32 build target is installed and initialize the