Skip to main content

Simple server-side WASM app in Rust on Docker Desktop

· 3 min read

The title already says it all: I wanted to go through all the steps to run a server-side WASM app on the new Docker Desktop+WASM Tech Preview.

Install Docker Desktop Tech Preview

First of all you need to install the Docker Desktop Tech Preview, download links can be found here. Please note that this is still in beta so all the caveats apply :)

Prepare for compilation from Rust to WASM

Next step is to get all the tooling in place to compile Rust to WASM:

  1. Download WasmEdge runtime:

    curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash

    Note that there are more runtimes to choose from, like SSVM, Wasmer and Wasmtime. I have done no research yet on the pros and cons of any of these.

    To make the WasmEdge binaries available on the path and set some additional env variables, run source $HOME/.wasmedge/env.

  2. Add the wasm32-wasi compilation target to Rust:

    rustup target add wasm32-wasi

    WASI is the WebAssembly System Interface. It provides access to operating system features like the file system and sockets.

Create and build a (really simple) Rust app

For now, I'm just gonna do a hello world, just to see if stuff works. Next step would be a tiny web server. So we do:

cargo new rust_wasm_hello_world

This results in a small Rust program that just prints Hello, world!:

fn main() {
println!("Hello, world!");
}

Next I'm gonna compile that to the wasm32-wasi target:

cargo build --target wasm32-wasi --release

which results in a target/wasm32-wasi/release folder that contains our rust_wasm_hello_world.wasm.

The wasm file we have now is a WebAssembly bytecode file, targeted to WASI. If you convert it to WebAssembly text format using wasm2wat, you'll see a large .wat file that has the 'hello world' program plus a lot of WASI code.

This wasm file can be compiled to native code using the wasmedgec AOT (Ahead-Of-Time) compiler:

wasmedgec target/wasm32-wasi/release/rust_wasm_hello_world.wasm rust_wasm_hello_world.cwasm

And now we have a rust_wasm_hello_world.cwasm executable that will run on a WASM runtime. This is where the Docker Desktop preview comes in.

Dockerize and run it

Let's first define our Dockerfile:

FROM scratch

ENTRYPOINT [ "/rust_wasm_hello_world.cwasm" ]

COPY rust_wasm_hello_world.cwasm /rust_wasm_hello_world.cwasm

and build an image:

docker build -t rust-wasm-hello-world .

We can run the image directly using docker now:

docker run --name=rust-wasm-hello-world \
--runtime=io.containerd.wasmedge.v1 \
--platform=wasi/wasm32 \
rust-wasm-hello-world

And finally check whether it ran successfully (since this container will exit once it printed Hello, world!):

docker logs rust-wasm-hello-world

docker logs

Next steps

I think this was the most basic stuff I could build with server-side WASM on Docker Desktop. A next step would be to actually run a WASM web server inside a container.

Another next step I'm curious about is whether I can simply replace wasmedgec with any other WASM AOT compiler. I guess in theory this should work as well, using wasmtime:

wasmtime compile target/wasm32-wasi/release/rust_wasm_hello_world.wasm