container2wasm Converter: Running Linux-Based Containers on WASM and Browser

Kohei Tokunaga
nttlabs
Published in
4 min readMar 7, 2023

Though more and more tools and programming languages start to support WebAssembly (WASM), porting existing applications to WASM isn’t easy and costs extra time for development.

To solve this issue, we’re working on a container-to-wasm image converter “container2wasm” that enables to run Linux-based containers on WASM(WASI) runtimes and browser.

$ c2w riscv64/ubuntu:22.04 out.wasm
$ wasmtime out.wasm uname -a
Linux localhost 6.1.0 #1 Wed Feb 15 04:09:09 UTC 2023 riscv64 riscv64 riscv64 GNU/Linux
container on browser

What’s WebAssembly (WASM)?

WASM is a binary format for executable programs. The WASM-compiled application runs anywhere the VM is available, including on-browser to the cloud. Its execution is sandboxed and has limited access to the host.

Though more and more tools and programming languages start to support WASM, porting existing non-WASM applications like Linux-based containers to WASM isn’t easy. WASM doesn’t provide the kernel APIs so platform-dependent codes need to be re-implemented or re-compiled for WASM, which costs extra time for development.

container2wasm: Container to WASM converter

container2wasm is an experimental container-to-wasm converter for running Linux-based containers on WASM.

The converter receives a container image and creates a WASM image that runs the container and Linux kernel on the emulated CPU. The converted WASM image runs on WASI (WebAssembly System Interface) runtimes like wasmtime and on browser. Sharing directories on the host to the container is possible for WASI images. Networking is available since v0.5 (Edited November 30, 2023).

x86_64 (since v0.3.0, edited June 26, 2023) or RISC-V 64-bit container images are recommended as the source image. Other architecture’s containers (e.g. arch64) work but are slow because of additional emulation.

Update (June 26, 2023): container2wasm v0.3.0 now supports running x86_64 containers on Wasm levaraging Bochs emulator.

How does container2wasm work?

The following shows the technical details, for those who are interested:

  • Builder: BuildKit runs the conversion steps written in Dockerfile.
  • Emulator: Bochs emulates x86_64 CPU (since v0.3.0, edited June 26, 2023) and TinyEMU emulates RISC-V CPU on WASM. It’s compiled to WASM using wasi-sdk (for WASI) and emscripten (for on-browser).
  • Guest OS: Linux runs on the emulated CPU. runc starts the container. Non-x86_64 and non-RISC-V containers run with additional emulation by QEMU installed via tonistiigi/binfmt.
  • Directory Mapping: WASI filesystem API makes host directories visible to emulators. Emulators mount them to the guest Linux via virtio-9p (Update(August 3, 2023): Directory mapping is available on both of x86_64 and riscv containers since v0.4.0.).
  • Packaging: wasi-vfs (for WASI) and emscripten (for on-browser) package the dependencies including the kernel. wizer pre-initializes the emulator to minimize the startup latency (for WASI only as of now).
  • Security: The converted container runs in the sandboxed WASM (WASI) VM with limited access to the host.

Getting Started

Docker and Docker Buildx v0.8+ (recommended) or docker build (w/ DOCKER_BUILDKIT=1) is needed on your host.

The converter command c2w is available from https://github.com/ktock/container2wasm/releases . Extract the tarball and put the binary somewhere under $PATH.

Update (June 26, 2023): You can also convert x86_64 containers to Wasm since container2wasm v0.3.0. Refer to the README for examples with ubuntu:22.04 image.

Container Image to WASM (WASI)

c2w command converts a container to WASM as shown in the following:

$ c2w riscv64/ubuntu:22.04 out.wasm

This converts riscv64/ubuntu:22.04 container image to WASI image (out.wasm).

The generated image runs on WASI runtimes like wasmtime:

$ wasmtime out.wasm uname -a
Linux localhost 6.1.0 #1 Wed Feb 15 04:09:09 UTC 2023 riscv64 riscv64 riscv64 GNU/Linux

Directory on the host can be available on the container as well.

$ mkdir -p /tmp/share/ && echo hi > /tmp/share/hi
$ wasmtime --mapdir /test/dir/share::/tmp/share -- out.wasm --entrypoint=cat -- /test/dir/share/hi
hi

Container on Browser

The following generates a WASM image and a JS file runnable on browser.

$ c2w --to-js riscv64/ubuntu:22.04 /tmp/out-js/htdocs/

The following serves them on localhost:8080 . Run this at the root directory of container2wasm repo.

$ cp -R ./examples/emscripten/* /tmp/out-js/ && chmod 755 /tmp/out-js/htdocs
$ docker run --rm -p 8080:80 \
-v "/tmp/out-js/htdocs:/usr/local/apache2/htdocs/:ro" \
-v "/tmp/out-js/xterm-pty.conf:/usr/local/apache2/conf/extra/xterm-pty.conf:ro" \
--entrypoint=/bin/sh httpd -c 'echo "Include conf/extra/xterm-pty.conf" >> /usr/local/apache2/conf/httpd.conf && httpd-foreground'

You can run the container on browser via localhost:8080.

container on browser

For further information, please refer to the documentation.

NTT is hiring!

We NTT is looking for engineers who work in Open Source communities like containerd, Docker/Moby, Kubernetes and WebAssembly. Visit https://www.rd.ntt/e/sic/recruit/ to see how to join us.

--

--