A First Look at Wasm and Docker
Published: 2022-11-07 03:28:01

[WebAssembly](https://webassembly.org/) is a portmanteau of two terms - Web and Assembly. The Web is an interconnected system of public web pages accessible through the Internet. On the other hand, an assembly language is a type of low-level programming language that is intended to communicate directly with a computer’s hardware and is designed to be readable by humans.


![Image1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hjg57ju72nv41488l9df.png)



Despite its name, WebAssembly(a.k.a Wasm) is not quite an assembly language. It's not meant for any particular machine. It’s for web browsers, and when you’re delivering code to be executed in the browser, you don’t know what kinds of machines will your code be running on.

WASM is a new binary-based programming language you can run in a web browser. WASM is designed to be faster than JavaScript because it is a low-level language. That means that it is closer to machine code, which processors can execute more quickly.



## What's so unique about Wasm?

![Image2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5u76yn35947t0ujyzjqo.png)

Wasm is faster. Unlike Javascript, WASM is statically typed, which means code optimization occurs far earlier in the compilation process before the code reaches the browser. Its binary files are considerably smaller than JavaScript's, resulting in significantly faster loading times. Interestingly, Wasm is 1.15-1.67 times faster than JavaScript on Google Chrome on a desktop.

Said that, Wasm is not intended to replace JavaScript, but to run alongside it. This way, developers can get a best-of-both-worlds for their applications. 

The other major benefits of using WebAssembly include:

- Lighweight
- Secure
- Easy debugging.
- Open-source.
- Hardware, language, and platform-independent.
- Lightweight.



## What's WASI?


![Image5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/01n1zuoz1ya1n9yj39pr.png)
Source ~ https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-overview.md#wasi-software-architecture


Just as WebAssembly is an assembly language for a conceptual machine, WebAssembly needs a system interface for a conceptual operating system, not any single operating system. This way, it can be run across all different OSs.This is what WASI is — a system interface for the WebAssembly platform. 

[WASI](https://wasi.dev/) is a modular system interface for WebAssembly. We aim to create a system interface that will be a true companion to WebAssembly and last the test of time. This means upholding the key principles of WebAssembly — portability and security.


When WASM was first introduced, it targeted to the Web Browser but developers started to push WebAssembly beyond the browser because it provides a fast, scalable, secure way to run the same code across all machines.



## Why Docker is supporting Wasm?

In 2013, DotCloud(now Docker, Inc.) released Docker as an attempt to build an open platform that lets developers and system administrators deploy self-sufficient application containers in Linux environments. Docker open-sourced three major things that allowed their container tools to be widely adopted:

- A standard container format;
- Tools that allows developers to build containers
- Tools that allows operators to run containers


As companies started using containers to package and deploy their software more and more, Docker's container runtime did not meet all the technical and business needs that engineering teams could have. In response to this, the community started developing new runtimes with different implementations and capabilities. To make sure that all container runtimes could run images produced by any build tool, the community started the [Open Container Initiative](https://www.opencontainers.org/) or OCI to define industry standards around container image formats and runtimes.

Docker's original image format became the OCI Image Specification, and various open-source build tools started supporting it (such as Buildkit, Podman, Buildah etc. ). It was the same time when Docker donated its runtime, [runc](https://github.com/opencontainers/runc) to the OCI to serve as the first implementation of the standard.

In late 2019, the world started talking about "Serverless". AWS Lambda launched support for packaging and deploying functions as container images at reInvent 2020. It was during the same time when WASM community showed interest and was seen investing time in the OCI toolchain. They were busy leveraging popular Docker projects like buildkit, and containerd to create Wasm artifacts and testing them on Docker Desktop. [As Docker Hub already support various artifacts ](https://www.docker.com/blog/announcing-docker-hub-oci-artifacts-support/)like Helm charts, Docker Volumes, SBOMs, OPA bundles and many other custom artifacts, they were all ready to include WebAssembly modules to the list.

## What problems does Docker solve for Wasm developer community?




- Conquer App Complexity 


If you look at the developer tooling today, it is not easy to setup a development environment for Wasm. It ends up with the same "works in a machine" scenario.  “Works on my machine” is a common refrain heard whenever the local environment configuration (from dev to test to production) has drifted from the established baseline and the same is true for Wasm too. It might be a case when you are running a specific version of Rust in your system while your CI infrastructure might be running a different version altogether. The same applies to different runtime or testing tools that you might be using in your development environment. 


- Learn and Develop Faster

Understanding Wasm involves a steep learning curve. Multiple languages, runtimes, frameworks, architectures, and discontinuous interfaces between tools for each lifecycle stage might create enormous complexity. Docker simplifies and accelerates your Wasm-based workload development workflow. With a well-known commands like `docker compose up`, `docker build` and `docker push/run`, developers can easily build Wasm containers and run it alongside Linux containers.It gives web developers the freedom to innovate with their choice of tools, application stacks, and deployment environments for their projects.
  
- Collaborate and Innovate 

By using Docker, developers can now collaborate with their team members and enhance product functionality by easily publishing images to Docker Hub.

In nutshell, Docker Community sees Wasm as a complementary technology to Linux containers. This is where developers can choose which technology they use (or both!) depending on the use case. And as the community explores what’s possible with Wasm, the effort is to make Wasm applications easier to develop, build, and run using the experience and tools you know and love. Docker solves the traditional problem - it works on my machine, works on yours and in production flawlessly. Docker Desktop and CLI can now manage both Linux containers and Wasm containers side by side.

## How does it work?


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r73wg24326w0xo2k72m0.png)



Docker collaborated with [WasmEdge](https://wasmedge.org/) to create a containerd shim. WasmEdge is a lightweight, high-performance, and extensible WebAssembly runtime.The containerd shim extracts the Wasm module from the OCI artifact and runs it using the WasmEdge runtime.


![Image5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbb53mnvdpkudscrnbpl.png)
Source ~ https://www.docker.com/blog/docker-wasm-technical-preview/


## Getting Started


The Docker+Wasm integration currently requires a technical preview build of the Docker Desktop. Download the technical preview build of Docker Desktop:

- [macOS Apple Silicon](https://www.docker.com/download/wasm-preview/macosxsilicon)
- [macOS Intel](https://www.docker.com/download/wasm-preview/macintel)
- [Windows AMD64](https://www.docker.com/download/wasm-preview/windowsamd64)
- [Linux Arm64 (deb)](https://www.docker.com/download/wasm-preview/linuxarm64deb)
- Linux AMD64 ([deb](https://www.docker.com/download/wasm-preview/linuxamd64deb), [rpm](https://www.docker.com/download/wasm-preview/linuxamd64rpm), [tar](https://www.docker.com/download/wasm-preview/linuxamd64tarball))

![Image2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5amftjbvqtz98pr5j57.png)



![Image3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62mmzjkr8140b3x4xxyr.png)

## Steps:

1.  We will packages Wasm module as OCI image using `docker buildx build` with `--platform wasi/wasm32` 
2. Then we will use `docker run` with `--runtime=io.containerd.wasmedge.v1` to execute. The flag tells containerd to use the runwasi shim
3. This allows the `runwasi` extracts Wasm module from the image and passes to `WasmEdge`
4. Finally, WasmEdge executes Wasm module.

## Installing WASI

WASI is a modular system interface for WebAssembly.

First, download wasi from the following URL:

```
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-16/wasi-sdk-16.0-macos.tar.gz
```

Next, Untar the WASI SDK

```
tar xvf wasi-sdk-16.0-macos.tar.gz
```

## Create a simple "Hello, Wasm" C Program.

```
 /* C program to print Hello Wasm! */

#include <stdio.h>

int main() {
   printf("Hello, Wasm!");
   return 0;
}
```

## Create a WASM module using WASI SDK

```
 export WASI_SDK_PATH=`pwd`/wasi-sdk-16.0
CC="${WASI_SDK_PATH}/bin/clang"
$CC hello-world.c -o hello-world.wasm
```

## Verifying the file type

```
file hello-world.wasm 
hello-world.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)
```

## Build a Docker Image

```
docker buildx build . --file=Dockerfile --tag=ajeetraina/hello-wasm-docker --platform wasi/wasm32
```

The `--platform=wasi/wasm32` specifies the architecture of the image we want to use. By leveraging a Wasm architecture, we don’t need to build separate images for the different architectures. The Wasm runtime will do the final step of converting the Wasm binary to machine instructions.


```

[+] Building 0.1s (5/5) FINISHED                                                                                                          
 => [internal] load build definition from Dockerfile                                                                                 0.0s
 => => transferring dockerfile: 125B                                                                                                 0.0s
 => [internal] load .dockerignore                                                                                                    0.0s
 => => transferring context: 2B                                                                                                      0.0s
 => [internal] load build context                                                                                                    0.0s
 => => transferring context: 18.89kB                                                                                                 0.0s
 => [1/1] COPY /hello-world.wasm /hello-world.wasm                                                                                   0.0s
 => exporting to image                                                                                                               0.1s
 => => exporting layers                                                                                                              0.0s
 => => exporting manifest sha256:947cfc124e1207a99141cb5671eb01a404df5b0c9653e37fab5c70e414b2f892                                    0.0s
 => => exporting config sha256:28476f78698df74b5d2fc3ff10770c53891f92d566380c5b7d808ff9ddb7b761                                      0.0s
 => => naming to docker.io/ajeetraina/hello-wasm-docker:latest                                                                       0.0s
 => => unpacking to docker.io/ajeetraina/hello-wasm-docker:latest 
```

## Running the Wasm-based Docker Image

```
docker run --runtime=io.containerd.wasmedge.v1 --platform=wasi/wasm32 ajeetraina/hello-wasm-docker
```



## Comparing the time

The time command is used to determine how long a given command takes to run. It is useful for testing the performance of your scripts and commands. Let's compare hello-world Docker Image Vs Wasm-based Docker Image.

```
time docker run hello-world
...
0.07s user 0.05s system 1% cpu 8.912 total
```

```
time docker run --runtime=io.containerd.wasmedge.v1 --platform=wasi/wasm32 ajeetraina/hello-wasm-docker

0.05s user 0.03s system 19% cpu 0.393 total
```

The `--runtime=io.containerd.wasmedge.v1` informs the Docker engine that we want to use the Wasm containerd shim instead of the standard Linux container runtime.

As you can see that the new Docker+Wasm integration allows you to run a Wasm application alongside your Linux containers at much faster speed. 

In the next blog post,you will see how to run a simple HTTP server, written in rust and compiled to wasm using Docker. Stay tuned! 

## Further References:

- [Introducing the Docker+Wasm Technical Preview](https://www.docker.com/blog/docker-wasm-technical-preview/)
- [WasmEdge](https://wasmedge.org/)
- [Docker+Wasm Getting Started Guide](https://docs.docker.com/desktop/wasm/)


## A Curated List of Wasm and Docker - Better Together

[Click Here to Access](https://github.com/collabnix/wasm-docker-better-together)


## Getting Help

Have a question about Docker + Wasm Integration? Visit our [Community Forum](https://forums.docker.com) and post your queries under our new [Docker+Wasm](https://forums.docker.com/c/docker-wasm/63) category.