A simple WebAssembly example

In this article, I will show you how to build a container image for a WebAssembly application. It can then be started and managed by Kubernetes ecosystem tools, such as CRI-O, Docker, crun, and Kubernetes.

Prerequisites

If you simply want a wasm bytecode file to test as a container image, you can skip the building process and just download the wasm file here.

If you have not done so already, follow these simple instructions to install Rust.

Download example code

  1. git clone https://github.com/second-state/wasm-learning
  2. cd wasm-learning/cli/wasi

Build the WASM bytecode

  1. rustup target add wasm32-wasi
  2. cargo build --target wasm32-wasi --release

The wasm bytecode application is in the target/wasm32-wasi/release/wasi_example_main.wasm file. You can now publish and use it as a container image.

Apply executable permission on the Wasm bytecode

  1. chmod +x target/wasm32-wasi/release/wasi_example_main.wasm

Create Dockerfile

Create a file called Dockerfile in the target/wasm32-wasi/release/ folder with the following content:

  1. FROM scratch
  2. ADD wasi_example_main.wasm /
  3. CMD ["/wasi_example_main.wasm"]

Create container image with annotations

Please note that adding self-defined annotation is still a new feature in buildah.

The crun container runtime can start the above WebAssembly-based container image. But it requires the module.wasm.image/variant=compat annotation on the container image to indicate that it is a WebAssembly application without a guest OS. You can find the details in Official crun repo.

To add module.wasm.image/variant=compat annotation in the container image, you will need the latest buildah. Currently, Docker does not support this feature. Please follow the install instructions of buildah to build the latest buildah binary.

Build and install the latest buildah on Ubuntu

On Ubuntu zesty and xenial, use these commands to prepare for buildah.

  1. sudo apt-get -y install software-properties-common
  2. export OS="xUbuntu_20.04"
  3. sudo bash -c "echo \"deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /\" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
  4. sudo bash -c "curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -"
  5. sudo add-apt-repository -y ppa:alexlarsson/flatpak
  6. sudo apt-get -y -qq update
  7. sudo apt-get -y install bats git libapparmor-dev libdevmapper-dev libglib2.0-dev libgpgme-dev libseccomp-dev libselinux1-dev skopeo-containers go-md2man containers-common
  8. sudo apt-get -y install golang-1.16 make

Then, follow these steps to build and install buildah on Ubuntu.

  1. mkdir -p ~/buildah
  2. cd ~/buildah
  3. export GOPATH=`pwd`
  4. git clone https://github.com/containers/buildah ./src/github.com/containers/buildah
  5. cd ./src/github.com/containers/buildah
  6. PATH=/usr/lib/go-1.16/bin:$PATH make
  7. cp bin/buildah /usr/bin/buildah
  8. buildah --help

Create and publish a container image with buildah

In the target/wasm32-wasi/release/ folder, do the following.

  1. $ sudo buildah build --annotation "module.wasm.image/variant=compat" -t wasm-wasi-example .
  2. # make sure docker is install and running
  3. # systemctl status docker
  4. # to make sure regular user can use docker
  5. # sudo usermod -aG docker $USER
  6. # newgrp docker
  7. # You may need to use docker login to create the `~/.docker/config.json` for auth.
  8. $ sudo buildah push --authfile ~/.docker/config.json wasm-wasi-example docker://docker.io/hydai/wasm-wasi-example:with-wasm-annotation

That’s it! Now you can try to run it in CRI-O or Kubernetes!