[:arrow_down: Download] [:book: Command reference] [:books: Additional Documents] [:arrow_forward: Demo]
container2wasm is a container-to-wasm image converter that enables to run the container on WASM.
- Converts a container to WASM with TinyEMU-based emulation
- Runs on WASI runtimes (e.g. wasmtime, wamr, wasmer, wasmedge, wazero)
- Runs on browser
- riscv64 containers are recommended. Other platforms (e.g. amd64 and arm64) also work (but slow).
This is an experimental software.
Demo page of containers on browser (debian,python,node,vim): https://ktock.github.io/container2wasm-demo/
$ c2w riscv64/ubuntu:22.04 out.wasm
The above command converts riscv64/ubuntu:22.04
container image to WASI image (out.wasm
).
NOTE: 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 Wed Feb 15 04:09:09 UTC 2023 riscv64 riscv64 riscv64 GNU/Linux
$ wasmtime out.wasm ls /
bin dev home media opt root sbin sys usr
boot etc lib mnt proc run srv tmp var
Directories on the host can be available on the container using --mapdir
:
$ 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
NOTE: Other WASI features untested. Future version will support more WASI features.
The following command generates a WASM image and a JS file runnable on browser.
$ c2w --to-js riscv64/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
.
This feature is currently for demo only.
- requirements
- Docker 18.09+ (w/
DOCKER_BUILDKIT=1
) - Docker Buildx v0.8+ (recommended) or
docker build
(w/DOCKER_BUILDKIT=1
)
- Docker 18.09+ (w/
You can install the converter command c2w
using one of the following methods:
Binaries are available from https://github.com/ktock/container2wasm/releases
Extract the tarball and put the binary somewhere under $PATH
.
Go 1.19+ is needed.
make
sudo make install
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]
image-name
: container image name (will be pulled from the registry if it doesn't exist in Docker)[output file]
: path to the result WASM file.
Sub commands
help, h
: Shows a list of commands or help for one command
Options
--assets value
: Custom location of build assets.--dockerfile value
: Custom location of Dockerfile (default: embedded to this command)--builder value
: Bulider command to use (default: "docker")--target-arch value
: target architecture of the source image to use (default: "riscv64")--build-arg value
: Additional build arguments (please see Dockerfile for available build args)--to-js
: output JS files runnable on the browsers using emscripten--debug-image
: Enable debug print in the output image--show-dockerfile
: Show default Dockerfile--legacy
: Use "docker build" instead of buildx (no support for assets flag) (default:false)--help, -h
: show help--version, -v:
print the version
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...]
[COMMAND] [ARG...]
: command to run in the container. (default: commands specified in the image config)
Options
-entrypoint <command>
: entrypoint command. (default: entrypoint specified in the image config)-no-stdin
: disable stdin. (default: false)
Example:
The following changes the container's entrypoint to echo
and pass hello
to the arguments.
wasmtime -- /app/out.wasm --entrypoint=echo hello
Directories mapped to the WASM program is accessible on the container as well.
$ mkdir -p /tmp/share/ && echo hi > /tmp/share/hi
$ wasmtime --mapdir /test/dir/share::/tmp/share /app/out.wasm ls /test/dir/share/
hi
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.
contaienr2wasm creates a WASM image that runs the container and the Linux kernel on the emulated CPU.
The following shows the techniqual details:
- Builder: BuildKit runs the conversion steps written in Dockerfile.
- Emulator: 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 RISC-V CPU. runc starts the container. Non-RISC-V containers runs with additional emulation by QEMU installed via
tonistiigi/binfmt
. - Directory Mapping: WASI filesystem API makes host directories visible to TinyEMU. TinyEMU mounts them to the guest linux via virtio-9p.
- Packaging: wasi-vfs (for WASI) and emscripten (for on-browser) are used for packaging the dependencies. The kernel is pre-booted during the build using wizer to minimize the startup latency (for WASI only as of now).
- Security: The converted container runs in the sandboxed WASM (WASI) VM with the limited access to the host system.
runtime | stdio | mapdir | note |
---|---|---|---|
wasmtime | ✔️ | ✔️ | |
wamr(wasm-micro-runtime) | ✔️ | ✔️ | |
wazero | 🚧 (stdin unsupported) | ✔️ | non-blocking stdin doesn't seem to work |
wasmer | 🚧 (stdin unsupported) | ✔️ | non-blocking stdin doesn't seem to work |
wasmedge | 🚧 (stdin unsupported) | ✔️ | non-blocking stdin doesn't seem to work |
-
✔️ : supported
-
🚧 : WIP
-
NOTE: WASI features other than above is untested (future version will support more features)
There are several container runtimes support running WASM applications, but they don't run containers on WASM.
- WASM on container runtimes
- Docker+Wasm integration: https://docs.docker.com/desktop/wasm/
- runwasi: https://github.com/containerd/runwasi
- youki: https://github.com/containers/youki
- crun: https://github.com/containers/crun
- krustlet: https://github.com/krustlet/krustlet
There are emulators that support running linux on WASM, but they don't support WASI.
-
x86 on WASM
-
RISCV on WASM
- TinyEMU: https://bellard.org/tinyemu/
./examples/
: Examples (python, php, non-riscv64 image, etc.)
-
container2wasi itself is licensed under Apache 2.0 but the generated WASM image will include third-pirty softwares:
- TinyEMU (MIT License) https://bellard.org/tinyemu/
- Source code is contained in (
./patches
). TinyEMU is modified by our project for making it work with containers
- Source code is contained in (
- BBL(riscv-pk) (license): https://github.com/riscv-software-src/riscv-pk
- Linux (GNU General Public License version 2): https://github.com/torvalds/linux/
- tini (MIT License): https://github.com/krallin/tini
- runc (Apache License 2.0): https://github.com/opencontainers/runc
- Binfmt (MIT License): https://github.com/tonistiigi/binfmt
- QEMU (license): https://github.com/qemu/qemu
- vmtouch (license): https://github.com/hoytech/vmtouch
- BusyBox (GNU General Public License version 2): https://git.busybox.net/busybox
- TinyEMU (MIT License) https://bellard.org/tinyemu/
-
Emscripten integration example relies on xterm-pty for IO management
- xterm-pty (MIT License): https://github.com/mame/xterm-pty