Ajeet Raina Docker Captain, ARM Innovator & Docker Bangalore Community Leader.

Docker and Wasm Containers – Better Together

6 min read



WebAssembly 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

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

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.

Major benefits of using WebAssembly includes:

  • Efficient and fast – Wasm 
    bytecode is designed to be encoded in a size- and load-time-efficient 
    binary format
  • It’s safe: WebAssembly describes a 
    memory-safe, sandboxed 
    execution environment that may even be implemented inside existing JavaScript virtual machines. When 
    embedded in the web, WebAssembly will enforce the same-origin and permissions security policies of the browser.
  • It’s debuggable: WebAssembly is designed to be pretty-printed in a 
    textual format for debugging, testing, experimenting, optimizing, learning, teaching, and writing programs by hand.
  • It’s part of open web platform: WebAssembly is designed to maintain the versionless, feature-tested, and backwards-compatible 
    nature of the web.
  • Platform-independent – It can help execute code efficiently and limit the risks of untrusted code being used within the ecosystem.

What’s WASI?

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.

 


Image5


Source ~ 
https://github.com/bytecodealliance/wasmtime/blob/main/docs/WASI-overview.md#wasi-software-architecture

 

WASI is a modular system interface for WebAssembly. It’s 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 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 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 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 updocker 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

Docker collaborated with 
WasmEdge 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


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:


Image2


Image3

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 runwasm 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:

A Curated List of Wasm and Docker – Better Together

Click Here to Access

Getting Help

Have a question about Docker + Wasm Integration? Visit our 
Community Forum and post your queries under our new 
Docker+Wasm category.

Please follow and like us:

Have Queries? Join https://launchpass.com/collabnix

Ajeet Raina Docker Captain, ARM Innovator & Docker Bangalore Community Leader.

Leave a Reply

Your email address will not be published. Required fields are marked *

© Copyright Collabnix Inc

Built for Collabnix Community, by Community