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.
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
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"
Now you can verify Rust is installed:
rustc --version
My output was the following:
rustc 1.66.1 (90743e729 2023-01-10)
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
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!");
}
You can build this app normally using:
cargo build
This will create a binary file and put it under target/dev
. You can execute it directly:
./target/debug/hello-wasm
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
Then we can use this target in the build command:
cargo build --target wasm32-wasi
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
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" ]
Now build it using the following command:
docker buildx build --platform wasi/wasm32 -t hello-wasm .
Let’s check the Docker images currently available:
docker image ls
The output has this line:
hello-wasm latest e2f29c7ab88a 2 minutes ago 520kB
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
It should say:
Hello, world!
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.