ktock / container2wasm

Container to WASM converter
https://ktock.github.io/container2wasm-demo/
Apache License 2.0
1.97k stars 72 forks source link
containers docker wasm webassembly

[⬇️Download] [📖 Command reference] [📚 Additional Documents] [▶️Demo]

container2wasm: Container to WASM converter

container2wasm is a container-to-wasm image converter that enables to run the container on WASM.

This is an experimental software.

Demo page of containers on browser (debian,python,node,vim): https://ktock.github.io/container2wasm-demo/

Examples

Container Image to WASM (WASI)

$ c2w ubuntu:22.04 out.wasm

The above command converts ubuntu:22.04 container image to WASI image (out.wasm).

NOTE1: For selecting the container image's architecture other than amd64, use --target-arch flag of c2w (e.g. c2w --target-arch=riscv64 riscv64/ubuntu:22.04 out.wasm).

NOTE2: x86_64 or riscv64 container is recommended. Other platform's containers should work but slow because of additional emulation.

The generated image runs on WASI runtimes:

$ wasmtime out.wasm uname -a
Linux localhost 6.1.0 #1 PREEMPT_DYNAMIC Mon Jun  5 11:57:09 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
$ wasmtime out.wasm ls /
bin   dev  home  lib32  libx32  mnt  proc  run   srv  tmp  var
boot  etc  lib   lib64  media   opt  root  sbin  sys  usr

Directory mapped from the host is accessible on the container.

$ mkdir -p /tmp/share/ && echo hi > /tmp/share/from-host
$ wasmtime --mapdir /mnt/share::/tmp/share out.wasm cat /mnt/share/from-host
hi

Please refer to ./examples/networking/wasi/ for enabling networking

Container on Browser

Container on browser

You can run the container on browser as well. There are two methods for running the container on browser.

Please also refer to ./examples/wasi-browser (WASI-on-browser example) and ./examples/emscripten (emscripten example).

Please refer to ./examples/networking/ for details about enabling networking.

WASI on browser

This example converts the container to WASI and runs it on browser.

The following command generates a WASI image.

$ c2w ubuntu:22.04 /tmp/out-js2/htdocs/out.wasm

The following is an example of running the image on browser relying on xterm-pty and browser_wasi_shim. This example serves the image on localhost:8080 using apache http server.

$ cp -R ./examples/wasi-browser/* /tmp/out-js2/ && chmod 755 /tmp/out-js2/htdocs
$ docker run --rm -p 8080:80 \
         -v "/tmp/out-js2/htdocs:/usr/local/apache2/htdocs/:ro" \
         -v "/tmp/out-js2/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.

WASI on browser with networking

Debian container on browser with browser networking

Container can also perform networking. This section is the demo of using curl command in the container.

Tested only on Chrome. The example might not work on other browsers.

$ cat <<EOF | docker build -t debian-curl -
FROM debian:sid-slim
RUN apt-get update && apt-get install -y curl
EOF
$ c2w debian-curl /tmp/out-js2/htdocs/out.wasm

This example serves the image on localhost:8080 using apache http server. The following also puts the network stack runnable on browser to the document root.

$ cp -R ./examples/wasi-browser/* /tmp/out-js2/ && chmod 755 /tmp/out-js2/htdocs
$ wget -O /tmp/out-js2/htdocs/c2w-net-proxy.wasm https://github.com/ktock/container2wasm/releases/download/v0.5.0/c2w-net-proxy.wasm
$ docker run --rm -p 8080:80 \
         -v "/tmp/out-js2/htdocs:/usr/local/apache2/htdocs/:ro" \
         -v "/tmp/out-js2/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 with several types of configurations:

emscripten on browser

This example uses emscripten for converting the container to WASM.

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

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

The following is an example of running the image on browser relying on xterm-pty. This example serves the image on localhost:8080 using apache http server.

$ 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.

NOTE: It can take some time to load and start the container.

Networking can also be enabled using the user-space network stack c2w-net implemented based on gvisor-tap-vsock serving over WebSocket on the host (outside of browser). See also ./examples/networking/websocket for detalis.

Getting Started

You can install the converter command c2w using one of the following methods.

NOTE: The output binary also contains c2w-net which a command usable for controlling networking feature (please see also ./examples/networking for details).

Release binaries

Binaries are available from https://github.com/ktock/container2wasm/releases Extract the tarball and put the binary somewhere under $PATH.

Building binaries using make

Go 1.19+ is needed.

make
sudo make install

Command reference

c2w

Converts a container image into a WASM image and writes it to the specified path (default: out.wasm at the current directory).

Usage: c2w [options] image-name [output file]

Sub commands

Options

Run-time flags for WASM image

You can specify run-time flags to the generated wasm image for configuring the execution (e.g. for changing command to run in the container).

Usage: out.wasm [options] [COMMAND] [ARG...]

Options

Example:

The following changes the container's entrypoint to echo and pass hello to the arguments.

wasmtime -- /app/out.wasm --entrypoint=echo hello

Directory mapping

Directory mapped from the host is accessible on the container.

$ mkdir -p /tmp/share/ && echo hi > /tmp/share/hi
$ wasmtime --mapdir /test/dir/share::/tmp/share /app/out.wasm ls /test/dir/share/
hi

Motivation

Though more and more programming languages start to support WASM, it's not easy to run the existing programs on WASM. This sometimes requires re-implementing and re-compiling them and costs extra time for development. This is a PoC converter tries to solve it by enabling running unmodified containers on WASM.

How does it work

contaienr2wasm creates a WASM image that runs the container and the Linux kernel on the emulated CPU.

The following shows the techniqual details:

WASI Runtimes Integration Status

x86_64 containers

runtime stdio mapdir networking note
wasmtime :heavy_check_mark: :heavy_check_mark: :heavy_check_mark: (w/ host-side network stack)
wamr(wasm-micro-runtime) :heavy_check_mark: :heavy_check_mark: :construction:
wazero :heavy_check_mark: :heavy_check_mark: :heavy_check_mark: (w/ host-side network stack
wasmer :construction: (stdin unsupported) :heavy_check_mark: :construction: non-blocking stdin doesn't seem to work
wasmedge :construction: (stdin unsupported) :heavy_check_mark: :construction: non-blocking stdin doesn't seem to work

risc-v and other architecutre's containers

runtime stdio mapdir networking note
wasmtime :heavy_check_mark: :heavy_check_mark: :heavy_check_mark: (w/ host-side network stack)
wamr(wasm-micro-runtime) :heavy_check_mark: :heavy_check_mark: :construction:
wazero :heavy_check_mark: :heavy_check_mark: :heavy_check_mark: (w/ host-side network stack)
wasmer :construction: (stdin unsupported) :heavy_check_mark: :construction: non-blocking stdin doesn't seem to work
wasmedge :construction: (stdin unsupported) :heavy_check_mark: :construction: non-blocking stdin doesn't seem to work

Similar projects

There are several container runtimes support running WASM applications, but they don't run containers on WASM.

There are emulators that support running linux on WASM, but they don't support WASI.

Some WASM API specs provides applications access to the host system. Re-compilation (and possibe re-implementation) of the application is needed.

Additional Resources

Acknowledgement