WebAssembly for Cloud Workloads
WebAssembly (or WASM) was born for web, but not for web only. This article provides high level introduction of WASM and an overview of its application on cloud workloads of server side. The article also quotes some conclusive statements and demo codes.
WebAssembly
WebAssembly is a new, portable, size- and load-time-efficient format suitable for compilation to the web. It was first announced in 2015. In the beginning, it was designed for web usage only. Specifically, it was designed to work with JaveScript. WebAssembly modules can be imported into a web app, exposing its functions for use via JavaScript.
WebAssembly aims to provide new features and major gains in performance. It is not primarily intended to be written by hand, rather it is designed to be an effective compilation target for source languages like C, C++, Rust, etc.
The design targets of WebAssembly is to: (from WASM concepts)
- “Be fast, efficient, and portable — WebAssembly code can be executed at near-native speed across different platforms by taking advantage of common hardware capabilities.
- “Be readable and debuggable — WebAssembly is a low-level assembly language, but it does have a human-readable text format that allows code to be written, viewed, and debugged by hand.
- “Keep secure — WebAssembly is specified to be run in a safe, sandboxed execution environment. Like other web code, it will enforce the browser’s same-origin and permissions policies.
- “Don’t break the web — WebAssembly is designed so that it plays nicely with other web technologies and maintains backwards compatibility.
WASI
WebAssembly System Interface, or WASI, is a family of APIs for WebAssembly being designed and standardized through the WASI Subgroup of the W3C WebAssembly Commmunity Group. You can know about the goal and the scope of the subgroup in this charter.
WASI was first proclaimed by Lin Clark in a Mozilla blog:
Now the interface itself is still a work in progress. Quite a few good readings are available in the docs folder of WASI Github repositoty (https://github.com/WebAssembly/WASI/). I suggest you start from the overview.
WASI was originally designed by wasmtime project, this is mentioned in the beginning of this document.
CLI Program Example
To execute command-line programs on server side, a WASM runtime is required. Here I take wasmtime as an example to show how to run WASM bytecode, more about runtime is discussion in next session.
Install a the runtime:
$ curl https://wasmtime.dev/install.sh -sSf | bash
Working with Rust
WASM bytecode can be built from many kinds of programming languages. In this example, the hello-world example is written in Rust. The demo source code is from wasmtime Github front page. It is simple enough for you to understand how a WASM CLI application works.
Create Rust source code file (hello.rs), including following content:
fn main() {
println!("Hello, world!");
}
Compile the Rust source code:
# Before this step, please make sure `rustup` has been installed.
# If not, follow this page to setup:
# https://www.rust-lang.org/tools/install$ rustup target add wasm32-wasi
$ rustc hello.rs --target wasm32-wasi
$ ls hello.wasm
Then run the WASM file:
$ wasmtime hello.wasm
Hello, world!
Working with WAT
A WASM program can also be written in textual format which is related to the underlying bytecode it represents. This format is S-expression based WAT (WebAssembly Text Format):
If you are interested in what the WAT code of this hello program look like, you can build some tools provided by the project wabt: , or simply upload the “hello.wasm” file to this website and view online.
Usually, the runtime can execute the WebAssembly source code in WAT format directly. So if you save the decoded content of “hello.wasm” to a file “hello.wat”, execute it with wasmtime should show the same thing:
$ wasmtime hello.wat
Hello, world!
Runtimes
A lot of WebAssembly runtimes have been created so far. Here I would like to introduce some famous ones.
Wasmtime
Wasmtime claims itself to be “A small and efficient runtime for WebAssembly & WASI”.
It features in:
- Lightweight
- Fast
- Configurable
- Rich WASI support
- Compliant to broad range of standards.
Wasmtime project is hosted by Bytecode Alliance.
Wasmer
Wasmer defines itself as “a fast and secure WebAssembly runtime that enables super lightweight containers to run anywhere: from Desktop to the Cloud, Edge and IoT devices”.
It is strong in:
- Secure by default. No file, network, or environment access, unless explicitly enabled.
- Supports WASI and Emscripten out of the box.
- Fast. Run WebAssembly at near-native speeds.
- Embeddable in multiple programming languages
- Compliant with latest WebAssembly Proposals
An interesting article regarding the performance comparison between wasmer and wasmtime is seen in wasmer website. It concluded that wasmer overwhelms wasmtime in startup speed, execution speed, size and supported languages.
WasmEdge
WasmEdge is previously known as SSVM. The official self-introduction says it is “a lightweight, high-performance, and extensible WebAssembly runtime for cloud native, edge, and decentralized applications”.
In a paper, WasmEdge was compared against another 2 kinds of WASM runtime: Lucet and WAVM. Among them, WasmEdge performed the best.
WasmEdge is an official sandbox project hosted by the CNCF.
WebAssembly Micro Runtime
WebAssembly Micro Runtime is yet another runtime hosted by Bytecode Alliance.
WebAssembly Micro Runtime (WAMR) simplifies its identification as “a standalone WebAssembly (WASM) runtime with a small footprint”.
More WebAssembly Runtimes
You can see a long list of them here. At the bottom of this page also mentioned some kinds of runtime.
Containerization
Build-and-run is not the cloud-native way of deploying workloads. The trend for modern workloads is containerization.
Instead of configuring, making and installing a software package, you can easily execute software by pulling an image and starting an application container. Another advantage of using container is your operating system can keep clean.
To align the specification of application containers, Open Container Initiative (OCI) was setup. It was established in June 2015 by Docker and other leaders in the container industry, the OCI currently contains mainly two specifications: the Runtime Specification (runtime-spec) and the Image Specification (image-spec).
However, these two specs are not proper to WASM. For the application containers, the binaries in the container image can be executed directly. But WASM program requires a runtime to work with it.
Happily there was further development in OCI on general-purposed image spec. Besides the Image Specification, a new Distribution Specification was proposed.
OCI Distribution Specification
The OCI Distribution Spec project defined an API protocol to facilitate and standardize the distribution of content.
The OCI Distribution Spec is closely related to the OCI Image Format Specification project, the OCI Runtime Specification project, and the OCI Artifacts project:
- “The OCI Image Format Specification strictly defines the requirements for an OCI Image (container image), which consists of a manifest, an optional image index, a set of filesystem layers, and a configuration. The schema for OCI Image components is fully supported by the APIs defined in the OCI Distribution Specification.
- “The OCI Distribution Specification is also designed generically enough to be leveraged as a distribution mechanism for any type of content. The format of uploaded manifests, for example, need not necessarily adhere to the OCI Image Format Specification so long as it references the blobs which comprise a given artifact.
- “The OCI Artifacts project is an effort to provide guidance on how to properly define and distribute content using the OCI Distribution Specification for artifacts which are not container filesystem bundles, in a way that is mostly compatible with the existing schemas defined in the OCI Image Format Specification.
Working with an OCI Artifacts Spec
Now there is already open-source projects working with Artifacts spec. And some registries are also beginning to support the new-defined spec.
Wasm-to-oci is a project that proposes an implementation of storing WebAssembly modules in OCI registries. It can convert your WASM binaries into OCI Artifacts image and push it to registry.
Shown below is an example of convert a WASM and pushing to Azure registry. (Now Docker Hub does not support Artifacts type.)
Push the WASM file to the registry:
$ wasm-to-oci push hello.wasm <oci-registry>.azurecr.io/wasm-to-oci:v1
Pushed: <oci-registry>.azurecr.io/wasm-to-oci:v1 Size: 1624962 Digest: sha256:4c7915b4c1f9b0c13f962998e4199ceb00db39a4a7fa4554f40ae0bed83d9510
Pull the file back and run it with wasmtime:
$ wasm-to-oci pull <oci-registry>.azurecr.io/wasm-to-oci:v1 - out test.wasm
Pulled: <oci-registry>.azurecr.io/wasm-to-oci:v1
Size: 1624962
Digest: sha256:4c7915b4c1f9b0c13f962998e4199ceb00db39a4a7fa4554f40ae0bed83d9510$ wasmtime test.wasm
Hello from WebAssembly!
Orchestration
Containerization pave the way to orchestration. Now that WASM can be containerized, is it possible to schedule and deploy WASM workloads with Kubernetes? Yes, but you need something to work as an agent on the cluster worker node and handle the Artifacts images.
One such project has come around, that is Krustlet.
Krustlet, as its name suggests (“Kubernetes RUST kubeLET”), is a Kubelet in Rust for running WASM.
Krustlet listens for the architecture wasm32-wasi and schedules those workloads to run in a wasmtime-based runtime instead of a container runtime.
With Krustlet, you can deploy WASM workloads with Kubernetes.
Before continuing to follow a demo to deploy WASM with Krustlet, you need to have a running Kubernetes cluster, and install Krustlet.
Updating the WASM Program
At first, let’s update the hello-world program written in Rust a little bit to make it long-running, that would we be useful when we deploy it with Kubernetes.
use std::time::Duration;
use std::thread::sleep;fn main() {
loop {
println!("Hello, World!");
sleep(Duration::from_secs(5));
}
}
Build the code like what we have done, and run the program:
$ wasmtime demo.wasm
Hello, World!
Hello, World!
Hello, World!
^C
The WASM program will keep printing greetings until you press “Ctrl + C” key to stop it.
Preparing Image
Next, you need to containerize the WASM program and push it to some registry.
Now Docker hub doesn’t support the image of Artifacts type, you need to look for some registry that can accommodate your WASM image. The Krustlet guide demonstrates the detailed steps to create a registry with Azure. In the following tests, I simply assume you have followed that guide and have made your registry ready.
Next you need to package the WASM program into a Artifacts image and then push it to your registry. The two steps can be done within one command by using wasm-to-oci tool which we have introduced:
$ wasm-to-oci push demo.wasm mycontainerregistry007.azurecr.io/krustlet-tutorial:v1.0.0
Creating Pod
Now you are ready to deploy the WASM program with Kubernetes. Create a YAML file (krustlet-tutorial.yaml) to define a Pod:
apiVersion: v1
kind: Pod
metadata:
name: krustlet-tutorial
spec:
containers:
- name: krustlet-tutorial
image: mycontainerregistry007.azurecr.io/krustlet-tutorial:v1.0.0
imagePullSecrets:
- name: <acr-secret>
tolerations:
- key: "kubernetes.io/arch"
operator: "Equal"
value: "wasm32-wasi"
effect: "NoExecute"
- key: "kubernetes.io/arch"
operator: "Equal"
value: "wasm32-wasi"
effect: "NoSchedule"
A “ACR-Secret” is required in the configuration file, refer the original page of this demo for detail.
Now it’s time to create the pod:
$ kubectl create -f krustlet-tutorial.yaml
After issuing the command above, leave all the remaining works to Krustlet. The Artifact image will be pulled by Kubernetes, then Krustlet will work with the image to start the workload inside.
Check the status of the pod. If it is in “Running” state, everything should work well.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
krustlet-tutorial 1/1 Running 0 42s
To observe what’s happening inside the pod:
$ kubectl logs krustlet-tutorial
Hello, World!
Hello, World!
Hello, World!
Hello, World!
Hello, World!
The WASM program was successfully deployed!
Summary
WebAssembly does not have to run on web, it also has bright future in cloud and server use cases. Because of its speed, portability and compatibility with a wide range of programming languages, it could be the best choice for many scenarios like Server-less and Edge.
But before WASM is widely applied on servers, there is a way to go. On the road, some milestones are seen:
- Runtime: The runtime is the first step, it makes generic-purposed WASM possible to the servers. And a critical task here is creating a specification for WASM interface. Currently, WASI could be the best candidate.
- OCI: Having a specification for containerization is a must step. When there is a spec, there are registries; when there are registries, there is a community and ecosystem, and millions of images will be created and shared by developers. Happily we have Artifacts spec now.
- Orchestrator: Finally, an orchestrator puts everything together. It schedules, obtains artifacts from remote registries and manages the workload by leveraging the runtime. Now in this area Krustlet is doing the job.
Reference
(I like to use MindMap to build knowledge, of course I put the links after it.)
https://www.secondstate.io/articles/getting-started-with-rust-function/
https://juejin.cn/post/6844903661982728200
https://webassembly.org/
https://webassembly.org/specs/
http://webassembly.org.cn/roadmap/
https://webassembly.org/getting-started/developers-guide/
https://www.tutorialspoint.com/webassembly/index.htm
https://developer.mozilla.org/en-US/docs/WebAssembly
https://github.com/WasmEdge/WasmEdge
https://wasmedge.org/
https://community.arm.com/developer/research/b/articles/posts/making-faas-awsm-an-efficient-serverless-wasm-runtime-for-the-edge
https://github.com/gwsystems/sledge-serverless-framework
https://github.com/bytecodealliance/wasmtime
https://github.com/WasmEdge/WasmEdge
https://github.com/WasmEdge/WasmEdge/blob/master/docs/use_cases.md
https://www.secondstate.io/articles/manage-webassembly-apps-in-wasmedge-using-docker-tools/
https://github.com/second-state/crunw
https://github.com/WasmEdge/WasmEdge/blob/master/docs/highlights.md
https://github.com/bytecodealliance/wasm-micro-runtime
https://wasmer.io/
https://github.com/wasmerio/wasmer
https://github.com/mbasso/awesome-wasm#non-web-embeddings
https://wasmer.io/wasmer-vs-wasmtime
https://www.libhunt.com/compare-SSVM-vs-wasmer
https://medium.com/wasm/cloud-native-webassembly-90b5ed782ea2
https://www.cncf.io/blog/2021/08/05/cloud-native-webassembly/
https://thenewstack.io/webassembly-the-future-of-cloud-native-distributed-computing
https://rustwasm.github.io/docs/book/
https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format
https://github.com/WebAssembly/WASI
https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/
https://www.youtube.com/watch?v=ggtEJC0Jv8A
https://cloudblogs.microsoft.com/uploads/prod/sites/37/2020/04/Solomon-Hykes-WASM-WASI-tweet.png
https://www.youtube.com/watch?v=QdWaQOgvd-g
https://github.com/WasmEdge/WasmEdge/blob/master/docs/use_cases.md
https://www.infoq.com/articles/arm-vs-x86-cloud-performance/
https://radu-matei.com/blog/wasm-to-oci/
https://radu-matei.com/blog/wasm-oci-tuf/
https://github.com/opencontainers/artifacts
https://github.com/engineerd/wasm-to-oci
https://github.com/oras-project/oras
https://docs.krustlet.dev/
https://github.com/krustlet/krustlet
https://cloudblogs.microsoft.com/opensource/2020/04/07/announcing-krustlet-kubernetes-rust-kubelet-webassembly-wasm/
https://deislabs.io/posts/introducing-krustlet/
https://www.youtube.com/watch?v=pEEdJlH-nWo
https://www.infoq.com/news/2020/06/krustlet-kubelet-rust/
https://docs.krustlet.dev/intro/intro/
https://www.youtube.com/c/wasmCloud
https://github.com/wasmCloud/wasmCloud
https://github.com/emscripten-core/emsdk
https://github.com/engineerd/wasm-to-oci
https://bytecodealliance.org/
https://github.com/bytecodealliance