8 breaking releases

Uses new Rust 2024

0.10.0 Mar 5, 2025
0.8.0 Dec 4, 2024
0.7.0 Oct 7, 2024
0.6.0 May 23, 2024
0.1.2 Mar 7, 2023

#102 in WebAssembly

Download history 155/week @ 2024-12-04 69/week @ 2024-12-11 3/week @ 2024-12-18 29/week @ 2025-01-08 2/week @ 2025-01-15 32/week @ 2025-01-22 101/week @ 2025-01-29 28/week @ 2025-02-05 23/week @ 2025-02-12 7/week @ 2025-02-19 5/week @ 2025-02-26 159/week @ 2025-03-05 8/week @ 2025-03-12

181 downloads per month

Apache-2.0

355KB
5K SLoC

runwasi logo

containerd-shim-wasm

A library to help build containerd shims for Wasm workloads.

Usage

There are two ways to implement a shim:

  1. Using the Instance trait
  2. Using the Engine trait

What trait to use depends on how much control you need over the container lifecycle and the level of sandboxing you want to provide. The main difference is that the Engine trait uses Youki's libcontainer crate to manage the container lifecycle, such as creating the container, starting it, and deleting it, and youki handles container sandbox for you. The Instance trait gives you more control over the container lifecycle.

Using the Engine trait

Implement the Engine trait for a simpler integration:

use containerd_shim_wasm::{
    container::{Instance, Engine, RuntimeContext},
    sandbox::cli::{revision, shim_main, version},
    Config,
};
use anyhow::Result;

#[derive(Clone, Default)]
struct MyEngine;

impl Engine for MyEngine {
    fn name() -> &'static str {
        "my-engine"
    }

    fn run_wasi(&self, ctx: &impl RuntimeContext) -> Result<i32> {
        // Implement your Wasm runtime logic here
        Ok(0)
    }
}

shim_main::<Instance<MyEngine>>(
    "my-engine",
    version!(),
    revision!(),
    "v1",
    None,
);

The Engine trait provides optional methods you can override:

  • can_handle() - Validates that the runtime can run the container (checks Wasm file headers by default)
  • supported_layers_types() - Returns supported OCI layer types
  • precompile() - Allows precompilation of Wasm modules
  • can_precompile() - Indicates if the runtime supports precompilation

Using the Instance trait directly

For more control, implement the Instance trait:

use containerd_shim_wasm::sandbox::{Instance, InstanceConfig, Error};
use containerd_shim_wasm::container::{Engine, RuntimeContext};
use chrono::{DateTime, Utc};
use std::time::Duration;
use anyhow::Result;

#[derive(Clone, Default)]
struct MyEngine;

impl Engine for MyEngine {
    fn name() -> &'static str {
        "my-engine"
    }

    fn run_wasi(&self, ctx: &impl RuntimeContext) -> Result<i32> {
        Ok(0)
    }
}

struct MyInstance {
    engine: MyEngine,
}

impl Instance for MyInstance {
    async fn new(id: String, cfg: &InstanceConfig) -> Result<Self, Error> {
        Ok(MyInstance { engine: MyEngine })
    }

    async fn start(&self) -> Result<u32, Error> {
        Ok(1)
    }

    async fn kill(&self, signal: u32) -> Result<(), Error> {
        Ok(())
    }

    async fn delete(&self) -> Result<(), Error> {
        Ok(())
    }

    async fn wait(&self) -> (u32, DateTime<Utc>) {
        (0, Utc::now())
    }
}

Running the shim

containerd expects the shim binary to be installed into $PATH (as seen by the containerd process) with a binary name like containerd-shim-myshim-v1 which maps to the io.containerd.myshim.v1 runtime. It can be configured in containerd.

This crate is not tied to any specific wasm engine.

Check out these projects that build on top of runwasi:

Dependencies

~37–57MB
~1M SLoC