Join our Discord Server
Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 570+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 8900+ members and discord server close to 2200+ members. You can follow him on Twitter(@ajeetsraina).

Docker and Wasm Containers – Better Together

8 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.

How does Wasm work in browsers?

Browser engines, such as Google Chrome’s V8 engine and Mozilla Firefox’s SpiderMonkey, include a WebAssembly (Wasm) virtual machine or runtime. This runtime is responsible for executing the Wasm binary instructions within the browser environment.

To enable running existing applications or codebases in the browser, compiler toolchains like Emscripten come into play. Emscripten is a popular toolchain that can compile source code written in languages like C, C++, or Rust into the Wasm target. It translates the code into a format that can be understood and executed by the Wasm runtime in the browser.

By using Emscripten or similar tools, developers can port legacy applications, libraries, or game engines written in languages like C or C++ to run in the browser. This allows them to leverage the power of native languages and reuse existing codebases while seamlessly integrating with client-side JavaScript code in web applications.

The Wasm runtime provides an interface that enables communication between the Wasm module and the JavaScript code running in the browser. This allows bidirectional data exchange, function calls, and interactions between the Wasm module and the surrounding JavaScript environment.

Overall, WebAssembly provides a standardized and efficient format for running code in the browser, allowing developers to leverage existing codebases and bring powerful applications to the web platform.

n addition to running within the browser, WebAssembly (Wasm) can also be executed outside of the browser environment. This is made possible by Wasm runtimes that are designed to function on traditional operating systems like Linux, Windows, and macOS.

When running Wasm applications outside of the browser, the Wasm runtime needs to communicate with the host system using interfaces other than the JavaScript engine. One such interface is the WebAssembly System Interface (WASI). WASI provides a standardized way for Wasm modules to interact with the host system, similar to how applications interact with the operating system through POSIX interfaces.

WASI allows Wasm modules to perform various system-related operations, such as file I/O, network access, and interacting with system resources. By leveraging WASI, Wasm runtimes enable Wasm applications to communicate with the host system in a secure and controlled manner.

To facilitate the porting of existing POSIX-compliant applications to WebAssembly, projects like WASI SDK and wasi-libc have been developed. WASI SDK provides a toolchain and set of development tools for compiling POSIX applications to the Wasm target, while wasi-libc is a C library implementation that provides the necessary POSIX-compatible functions and system calls for Wasm modules.

By using WASI SDK and wasi-libc, developers can compile their existing applications, written in languages compatible with POSIX standards, to WebAssembly. This allows them to take advantage of the cross-platform nature of WebAssembly while reusing their existing codebases and benefiting from the performance and security advantages offered by WebAssembly.

In summary, Wasm runtimes that operate outside of the browser, coupled with the WASI interface and supporting tools like WASI SDK and wasi-libc, enable Wasm applications to interact with the host system and bring the power of WebAssembly to traditional operating systems in a portable and efficient manner.

server

How does Wasm works on Server?

In addition to running within the browser, WebAssembly (Wasm) can also be executed outside of the browser environment. This is made possible by Wasm runtimes that are designed to function on traditional operating systems like Linux, Windows, and macOS. When running Wasm applications outside of the browser, the Wasm runtime needs to communicate with the host system using interfaces other than the JavaScript engine. One such interface is the WebAssembly System Interface (WASI). WASI provides a standardized way for Wasm modules to interact with the host system, similar to how applications interact with the operating system through POSIX interfaces.

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)

Creating a Dockerfile

Here’s a Dockerfile that you can use to containerize your “Hello, Wasm” C program:

FROM scratch
COPY --chmod=755 hello-world.wasm /hello-world.wasm
ENTRYPOINT [ "/hello-world.wasm" 

Building the Image

docker build --platform=wasi/wasm --provenance=false -t hello-world-wasm --load .

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

Running the container

docker run --platform=wasi/wasm --rm -i --runtime=io.containerd.wasmedge.v1 hello-world-wasm

image

 

Running the Wasm-based Docker Image

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

Comparing Wasm Vs Linux Containers

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.

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

Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 570+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 8900+ members and discord server close to 2200+ members. You can follow him on Twitter(@ajeetsraina).
Join our Discord Server
Index