Word on the Cloud: Keeping you up-to-date on cloud native. Short & sharp!

nigelpoulton_logo_22_colour

WebAssembly and containerd: How it works

containerd runwasi and Kubernetes

containerd shims make it possible to seamlessly run WebAssembly apps on Kubernetes. This article explains the role of containerd shims and how they work.

Kubernetes and containerd primer

Kubernetes is a high-level application orchestrator that relies on lower-level tools such as containerd and runc to execute applications.
 
A typical workflow deploying an application to Kubernetes looks like this:
 
1. Kubernetes schedules work to cluster nodes
2. The kubelet on the node hands the work to containerd
3. containerd asks runc to create the container and start the app
 
This model defines three clear responsibilities. Kubernetes is responsible for scheduling work to appropriate nodes in the cluster. containerd runs on each node and is responsible for managing lifecycle events such as creating, starting, stopping, and deleting containers. runc is responsible for low-level tasks such as creating namespaces, cgroups, and other constructs that make up a container.
 
On the jargon front, containerd is a high-level runtime, whereas runc is a low-level runtime.
 
The architecture is shown in the diagram below.
containerd and runc executing OCI containers

The purpose of containerd shims

containerd shims are helper processes that sit between containerd and the low-level runtime. They can perform many important tasks, one of which is abstracting the detail of low-level runtimes.
 
This architecture means you can write a shim to integrate almost any low-level runtime with containerd.
 
The following diagram shows Kubernetes scheduling OCI containers and WebAssembly apps to a single cluster node running containerd.
 
On the left, containerd is using runc and a shim to manage two OCI containers. On the right, the same containerd instance is using WebAssembly runtimes and shims to manage two WebAssembly workloads.
contianerd managing OCI containers and WebAssembly workloads

This article explains how Kubernetes targets WebAssembly workloads to nodes with the required runtimes and shims.

WebAssembly containerd shims

WebAssembly containerd shims are binary executables that sit between containerd and a Wasm runtime. They have the following three requirements:
 
– They embed the code required to interface with containerd
– They embed the Wasm runtime code
– They must be named according to the containerd binary naming convention
 
The following list shows 4 popular WebAssembly containerd shims. Notice how the binary names include the name of the target runtime and version. 
 
Slight: containerd-shim-slight-v1
Spin: containerd-shim-spin-v1
WasmEdge: containerd-shim-wasmedge-v1
wasmtime: containerd-shim-wasmtime-v1
 
The shim code required to interface with containerd is runwasi. It’s an official containerd project and is designed to be used as a Rust library. The following code snippet shows the spin shim importing runwasi.
				
					use containerd_shim_wasm::sandbox::{
    error::Error,
    instance::{EngineGetter, InstanceConfig},
    oci, Instance, ShimCli,
};
				
			
You can see similar imports for the slight shim, WamEdge shim, and wasmtime shim.
 
The following diagram shows the high-level architecture for WebAssembly containerd shims. Notice how the shim includes the runwasi code and the Wasm runtime code. runwasi handles the interface with containerd, whereas the Wasm runtime code executes the Wasm app.
WebAssembly containerd shim architecture

WebAssembly containerd shims in practice

In the future, most Kubernetes distros will automate the process of installing Wasm shims. However, it’s useful to understand the configuration involved.
 
Installing a WebAssembly containerd shim is a two-step process:
 
1. Copy the shim binary to the node
2. Register the shim with containerd
 
The shim binary must be named appropriately and installed in a directory visible to containerd. This is usually the /bin directory but can be any PATH visible to containerd. A standard installation of the wasmtime shim would be:
				
					/bin/containerd-shim-wasmtime-v1
				
			
The shim also needs registering in the containerd configuration file which is usually located at /etc/containerd/config.toml.
 
The following extract is from a config.toml on a Kubernetes node with shims registered for runc, wasmtime, and spin.
				
					[plugins.cri.containerd.runtimes.runc]
  runtime_type = "io.containerd.runc.v2"

[plugins.cri.containerd.runtimes.wasmtime]
  runtime_type = "io.containerd.wasmtime.v1"

[plugins.cri.containerd.runtimes.spin]
  runtime_type = "io.containerd.spin.v1"
				
			
With the shim installed and registered, the node is ready to execute appropriate Wasm apps. 
 
containerd spawns a shim process for each Wasm app it starts. Each shim process is a long-running daemon process that executes for as long as the Wasm app executes.
 
The shim executes the Wasm app by invoking the embedded Wasm runtime code which creates the Wasm host and executes the Wasm app.
 
The following snippet is from a Kubernetes node running three Wasm apps. Notice that there are three shim processes.
				
					$ ps | grep wasm

PID    USER  COMMAND
<Snip>
2722   0     {containerd-shim}.../bin/containerd-shim-wasmtime-v1 ...
2962   0     {containerd-shim}.../bin/containerd-shim-wasmtime-v1 ...
3367   0     {containerd-shim}.../bin/containerd-shim-wasmtime-v1 ...
				
			

The shim process also interfaces with containerd which includes listening for instructions and reporting back on status and exit codes.

Summary

containerd helping WebAssembly get onto Kubernetes wheel
Kubernetes is a high-level application orchestrator that relies on lower-level tools to execute the apps.
 
containerd is the most widely-used high-level Kubernetes runtime. It implements a shim architecture that lets you mix-and-match low-level runtimes, including WebAssembly runtimes.
 
WebAssembly containerd shims embed the runwasi code that interfaces with containerd. They also embed the Wasm runtime code that creates the Wasm host and executes Wasm apps.
 
This architecture makes it possible to seamlessly execute WebAssembly apps on Kubernetes.
 
This article explains everything you need to know about integrating WebAssembly with Kubernetes.
– This article walks you through the hands-on process of deploying a WebAssembly app to Kubernetes.
 
Feel free to ping me on LinkedIn, Twitter, Mastodon, Insta, and Bluesky (@nigelpoulton.bsky.social). 

Massive thanks to Joe Zhou for fact-checking my early research. Any mistakes in this final article are mine. 

Share this post

Facebook
Twitter
LinkedIn

Books

Special Editions

Contact
Subscribe
Word on the cloud: What's going on in cloud native

Nigel’s Keeping you up-to-date on cloud native. Short & sharp! #Docker #Kubernetes #WebAssembly #Wasm

© 2024 Nigel Poulton – All rights reserved

Search

Looking for something specific?

Try the search facility.