WASM+Docker Hello World

Mohammad-Ali A'RÂBI - Jan 27 '23 - - Dev Community

WASM Hello World App with Rust and Docker Desktop

WebAssembly (WASM) is a binary instruction format for a stack-based virtual machine that is designed to be fast and efficient. It is a low-level assembly-like language that runs in the browser and provides a way to execute code at near-native speeds. WASM is supported by all major web browsers, including Chrome, Firefox, Safari, and Edge.

WebAssembly System Interface (WASI) is an interface that allows WebAssembly code to access the underlying operating system and file system. It provides a standardized set of system calls for WebAssembly modules to interact with the host environment. This allows WebAssembly code to be run in the backend.

In short, if WASM is JavaScript, WASI is Node.js.

Another important aspect of WASM is that it is language-agnostic, which means that code written in a variety of programming languages, such as Rust, C++, or C can be compiled to WASM and run in the browser. This provides developers with more options for building web applications and allows them to take advantage of the strengths of different languages.

TL;DR

In this piece, we’re going to create a Hello World app using Rust, compile it into a WASM binary, and run it using Docker Desktop.

WASM + Docker Hello World!

Install Rust and WASM Package

To get started, you’ll need to have the Rust programming language installed on your computer. You can install Rust by following the instructions on the official website:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Enter fullscreen mode Exit fullscreen mode

It installs Rust together with its package manager, Cargo. After installation, I had to run the following command to update the $PATH variable:

source "$HOME/.cargo/env"
Enter fullscreen mode Exit fullscreen mode

Now you can verify Rust is installed:

rustc --version
Enter fullscreen mode Exit fullscreen mode

My output was the following:

rustc 1.66.1 (90743e729 2023-01-10)
Enter fullscreen mode Exit fullscreen mode

Create the Project

Once you have everything set up, you can create a new Rust project. First, change to a directory where you would gather your Rust projects, and then run the following command:

cargo new hello-wasm
Enter fullscreen mode Exit fullscreen mode

This will create a new directory called “hello-wasm” with the basic structure of a Rust library. Git is already initialized there, but there is no commit yet.

The src/lib.rs already has a Hello World code:

fn main() {
    println!("Hello, world!");
}
Enter fullscreen mode Exit fullscreen mode

You can build this app normally using:

cargo build
Enter fullscreen mode Exit fullscreen mode

This will create a binary file and put it under target/dev. You can execute it directly:

./target/debug/hello-wasm
Enter fullscreen mode Exit fullscreen mode

This binary file is built for your machine and is platform-dependent.

Build WASM Binary

Now, to build the project for a WASM runtime, we need to add a new target:

rustup target add wasm32-wasi
Enter fullscreen mode Exit fullscreen mode

Then we can use this target in the build command:

cargo build --target wasm32-wasi
Enter fullscreen mode Exit fullscreen mode

This command will create the WASM binary and put it under target/wasm32-wasi:

target
├── CACHEDIR.TAG
├── debug
│   ├── build
│   ├── deps
│   ├── examples
│   ├── hello-wasm
│   ├── hello-wasm.d
│   └── incremental
└── wasm32-wasi
    ├── CACHEDIR.TAG
    └── debug
        ├── build
        ├── deps
        ├── examples
        ├── hello-wasm.d
        ├── hello-wasm.wasm
        └── incremental
Enter fullscreen mode Exit fullscreen mode

Create Docker Image

Note that this is currently a preview feature and is only available on Docker Desktop. To be able to build or run WASM containers with your Docker Desktop, you first need to enable the “containerd pulling and storing feature” from the settings.

First, create a Dockerfile with the following content:

# syntax=docker/dockerfile:1
FROM scratch
COPY ./target/wasm32-wasi/debug/hello-wasm.wasm /hello.wasm
ENTRYPOINT [ "hello.wasm" ]
Enter fullscreen mode Exit fullscreen mode

Now build it using the following command:

docker buildx build --platform wasi/wasm32 -t hello-wasm .
Enter fullscreen mode Exit fullscreen mode

Let’s check the Docker images currently available:

docker image ls
Enter fullscreen mode Exit fullscreen mode

The output has this line:

hello-wasm    latest    e2f29c7ab88a    2 minutes ago    520kB
Enter fullscreen mode Exit fullscreen mode

The image is created and is half a megabyte in size. Let’s run it using the following command:

docker run \ 
  --runtime=io.containerd.wasmedge.v1 \
  --platform=wasi/wasm32 \
  hello-wasm
Enter fullscreen mode Exit fullscreen mode

It should say:

Hello, world!
Enter fullscreen mode Exit fullscreen mode

Final Words

WebAssembly offers a near-native performance and is platform-independent. Docker Desktop comes with WasmEdge runtime and allows one to wrap a WASM app into a Docker container and probably run it in a Docker Compose setup alongside non-WASM containers.

This article was originally published on Medium.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .