Manage WebAssembly Apps with Docker Tools in WasmEdge

About the author: Michael Yuan is a WasmEdge Maintainer of the CNCF sandbox project. He has many years of experience in open source software development and has published 5 technical books.

This post will demonstrate how to deploy, manage, and run lightweight WebAssembly applications in WasmEdge by leveraging Docker tools like DockerHub and CRI-O.

WasmEdge , a WebAssembly runtime hosted by CNCF (Cloud Native Computing Foundation) , is an execution sandbox for edge computing applications.

While WebAssembly was originally invented as a runtime for browser applications, its lightweight and high-performance sandbox design makes it an attractive choice for general-purpose application containers.

If we had WASM + WASI in 2008, we wouldn't have started the Docker project at all. — Solomon Hykes, co-founder of Docker

Compared to Docker, WebAssembly is a hundred times faster at startup , takes up less memory and disk space, and has a better-defined security sandbox. The downside, however, is that WebAssembly requires its own language SDK and compiler toolchain, making it more limited as a developer environment than Docker. WebAssembly is increasingly used in edge computing scenarios where deploying Docker is difficult or where application performance is critical.

One of Docker's great strengths is its rich ecosystem of tools. We want to bring Docker-like tools to WasmEdge developers. To achieve this, we created an alternative runner for CRI-O called runw to load and run WebAssembly bytecode programs as if they were Docker images.

Install the WebAssembly runner in CRI-O

To support WebAssembly in CRI-O, all you need to do is download the runwbinary distribution and install it into your CRI-O.

runwBecause WasmEdge is already included in the binaries, there is no need to install WasmEdge or any other WebAssembly VM separately.

First, make sure you're using Ubuntu 20.04 with LLVM-10 installed. If you are using a different platform, see How to create a runwproject .

sudo apt install -y llvm-10-dev liblld-10-dev

Make sure you have cri-o , crictl , containernetworking-plugins and buildah or docker installed .

Next, download the runwbinary build

wget https://github.com/second-state/runw/releases/download/0.1.0/runw

Now, you can install runwinto CRI-O as an alternative to WebAssembly.

# Get the wasm-pause utility
sudo crictl pull docker.io/beststeve/wasm-pause

# Install runw into cri-o
sudo cp -v runw /usr/lib/cri-o-runc/sbin/runw
sudo chmod +x /usr/lib/cri-o-runc/sbin/runw
sudo sed -i -e 's@default_runtime = "runc"@default_runtime = "runw"@' /etc/crio/crio.conf
sudo sed -i -e 's@pause_image = "k8s.gcr.io/pause:3.2"@pause_image = "docker.io/beststeve/wasm-pause"@' /etc/crio/crio.conf
sudo sed -i -e 's@pause_command = "/pause"@pause_command = "pause.wasm"@' /etc/crio/crio.conf
sudo tee -a /etc/crio/crio.conf.d/01-crio-runc.conf <<EOF
[crio.runtime.runtimes.runw]
runtime_path = "/usr/lib/cri-o-runc/sbin/runw"
runtime_type = "oci"
runtime_root = "/run/runw"
EOF

Finally, reboot cri-oso the new WebAssembly runner takes effect.

sudo systemctl restart crio

Building Wasm Applications with Rust

The Wasm application in the example below is written in Rust. For these programs to work, make sure you have Rust and the rustwasmc toolchain installed.

You need the Rust compiler and rustwasmc to build Rust sources into wasm bytecode files. If you already have a wasm bytecode program and just want to run it with cri-o, you can skip this section.

The application source code is only one main.rsfunction . here. This application demonstrates how to access the filesystem and other operating system resources from WasmEdge using standard Rust APIs.

fn main() {
  println!("Random number: {}", get_random_i32());
  println!("Random bytes: {:?}", get_random_bytes());
  println!("{}", echo("This is from a main function"));
  print_env();
  create_file("/tmp.txt", "This is in a file");
  println!("File content is {}", read_file("/tmp.txt"));
  del_file("/tmp.txt");
}

pub fn get_random_i32() -> i32 {
  let x: i32 = random();
  return x;
}

pub fn get_random_bytes() -> Vec<u8> {
  let mut rng = thread_rng();
  let mut arr = [0u8; 128];
  rng.fill(&mut arr[..]);
  return arr.to_vec();
}

pub fn echo(content: &str) -> String {
  println!("Printed from wasi: {}", content);
  return content.to_string();
}

pub fn print_env() {
  println!("The env vars are as follows.");
  for (key, value) in env::vars() {
    println!("{}: {}", key, value);
  }

  println!("The args are as follows.");
  for argument in env::args() {
    println!("{}", argument);
  }
}

pub fn create_file(path: &str, content: &str) {
  let mut output = File::create(path).unwrap();
  output.write_all(content.as_bytes()).unwrap();
}

pub fn read_file(path: &str) -> String {
  let mut f = File::open(path).unwrap();
  let mut s = String::new();
  match f.read_to_string(&mut s) {
    Ok(_) => s,
    Err(e) => e.to_string(),
  }
}

pub fn del_file(path: &str) {
  fs::remove_file(path).expect("Unable to delete");
}

You can build your application into a wasm bytecode file with the command line below.

rustwasmc build

The wasm bytecode file is here.

Build and publish a Docker Hub image for the Wasm app

You can now publish the entire wasm bytecode file to Docker hub as if it were a Docker image.

First, create a Dockerfile in the pkg/directory as shown below.

FROM scratch
ADD wasi_example_main.wasm .
CMD ["wasi_example_main.wasm"]

Create an image and publish to Docker hub.

sudo buildah bud -f Dockerfile -t wasm-wasi-example
sudo buildah push wasm-wasi-example docker://registry.example.com/repository:tag

# Example: the following command publishes the wasm image to the public Docker hub under user account "hydai"
sudo buildah push wasm-wasi-example docker://docker.io/hydai/wasm-wasi-example:latest

crictlYou can now pull the published wasm file into an image using Docker tools (for example ). Below is an example of the wasm file image we publish.

sudo crictl pull docker.io/hydai/wasm-wasi-example

Start the Wasm app with CRI-O

To get the wasm file up and running, you need to create two configuration files for CRI-O. Create a container_wasi.jsonfile as shown below. It tells the CRI-O runtime where to pull the wasm file image from the Docker repository.

{
  "metadata": {
    "name": "podsandbox1-wasm-wasi"
  },
  "image": {
    "image": "hydai/wasm-wasi-example:latest"
  },
  "args": [
    "wasi_example_main.wasm", "50000000"
  ],
  "working_dir": "/",
  "envs": [],
  "labels": {
    "tier": "backend"
  },
  "annotations": {
    "pod": "podsandbox1"
  },
  "log_path": "",
  "stdin": false,
  "stdin_once": false,
  "tty": false,
  "linux": {
    "resources": {
      "memory_limit_in_bytes": 209715200,
      "cpu_period": 10000,
      "cpu_quota": 20000,
      "cpu_shares": 512,
      "oom_score_adj": 30,
      "cpuset_cpus": "0",
      "cpuset_mems": "0"
    },
    "security_context": {
      "namespace_options": {
        "pid": 1
      },
      "readonly_rootfs": false,
      "capabilities": {
        "add_capabilities": [
          "sys_admin"
        ]
      }
    }
  }
}

Next, create a sandbox_config.jsonfile as shown below. It defines a sandbox environment for running wasm applications.

{
  "metadata": {
    "name": "podsandbox12",
    "uid": "redhat-test-crio",
    "namespace": "redhat.test.crio",
    "attempt": 1
  },
  "hostname": "crictl_host",
  "log_directory": "",
  "dns_config": {
    "searches": [
      "8.8.8.8"
    ]
  },
  "port_mappings": [],
  "resources": {
    "cpu": {
      "limits": 3,
      "requests": 2
    },
    "memory": {
      "limits": 50000000,
      "requests": 2000000
    }
  },
  "labels": {
    "group": "test"
  },
  "annotations": {
    "owner": "hmeng",
    "security.alpha.kubernetes.io/seccomp/pod": "unconfined"
  },
  "linux": {
    "cgroup_parent": "pod_123-456.slice",
    "security_context": {
      "namespace_options": {
        "network": 0,
        "pid": 1,
        "ipc": 0
      },
      "selinux_options": {
        "user": "system_u",
        "role": "system_r",
        "type": "svirt_lxc_net_t",
        "level": "s0:c4,c5"
      }
    }
  }
}

A CRI-O pod can now be created as follows:

# 创建 POD,输出将会和示例不同。
sudo crictl runp sandbox_config.json
7992e75df00cc1cf4bff8bff660718139e3ad973c7180baceb9c84d074b516a4

# 设置一个辅助变量供以后使用。
POD_ID=7992e75df00cc1cf4bff8bff660718139e3ad973c7180baceb9c84d074b516a4

From pods, you can create a container to run wasm bytecode programs in isolation.

# 创建容器实例,输出将会和示例不同。
sudo crictl create $POD_ID container_wasi.json sandbox_config.json
1d056e4a8a168f0c76af122d42c98510670255b16242e81f8e8bce8bd3a4476f

Finally, start the container and see the output of the wasm application.

# 列出容器,状态应该是 `Created`
sudo crictl ps -a

CONTAINER           IMAGE                           CREATED              STATE               NAME                     ATTEMPT             POD ID
1d056e4a8a168       hydai/wasm-wasi-example:latest   About a minute ago   Created             podsandbox1-wasm-wasi   0                   7992e75df00cc

# 启动容器
sudo crictl start 1d056e4a8a168f0c76af122d42c98510670255b16242e81f8e8bce8bd3a4476f
1d056e4a8a168f0c76af122d42c98510670255b16242e81f8e8bce8bd3a4476f

# 再次检查容器状态。#如果容器没有完成工作,你会看到运行状态。 #因为这个例子很小。此时您可能会看到 Exited。
sudo crictl ps -a
CONTAINER           IMAGE                           CREATED              STATE               NAME                     ATTEMPT             POD ID
1d056e4a8a168       hydai/wasm-wasi-example:latest   About a minute ago   Running             podsandbox1-wasm-wasi   0                   7992e75df00cc

# 当容器完成。你能看到状态变为 Exited。
sudo crictl ps -a
CONTAINER           IMAGE                           CREATED              STATE               NAME                     ATTEMPT             POD ID
1d056e4a8a168       hydai/wasm-wasi-example:latest   About a minute ago   Exited              podsandbox1-wasm-wasi   0                   7992e75df00cc

# 查看容器记录 
sudo crictl logs 1d056e4a8a168f0c76af122d42c98510670255b16242e81f8e8bce8bd3a4476f

Test 1: 打印随机数
Random number: 960251471

Test 2: 打印随机字节
Random bytes: [50, 222, 62, 128, 120, 26, 64, 42, 210, 137, 176, 90, 60, 24, 183, 56, 150, 35, 209, 211, 141, 146, 2, 61, 215, 167, 194, 1, 15, 44, 156, 27, 179, 23, 241, 138, 71, 32, 173, 159, 180, 21, 198, 197, 247, 80, 35, 75, 245, 31, 6, 246, 23, 54, 9, 192, 3, 103, 72, 186, 39, 182, 248, 80, 146, 70, 244, 28, 166, 197, 17, 42, 109, 245, 83, 35, 106, 130, 233, 143, 90, 78, 155, 29, 230, 34, 58, 49, 234, 230, 145, 119, 83, 44, 111, 57, 164, 82, 120, 183, 194, 201, 133, 106, 3, 73, 164, 155, 224, 218, 73, 31, 54, 28, 124, 2, 38, 253, 114, 222, 217, 202, 59, 138, 155, 71, 178, 113]

Test 3: 调用 echo 函数
Printed from wasi: This is from a main function
This is from a main function

Test 4: 打印环境变量
The env vars are as follows.
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
TERM: xterm
HOSTNAME: crictl_host
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
The args are as follows.
/var/lib/containers/storage/overlay/006e7cf16e82dc7052994232c436991f429109edea14a8437e74f601b5ee1e83/merged/wasi_example_main.wasm
50000000

Test 5: 创建文件 `/tmp.txt` 包含内容 `This is in a file`

Test 6: 从之前文件读取内容
File content is This is in a file

Test 7: 删除之前文件

what's next

In this article, we saw how to use Docker-like CRI-O tools to start, run, and manage WasmEdge applications.

Our next step is to use Kubernetes to manage WasmEdge containers. To do this, we need to install a runner binary in Kubernetes so that it can support both regular Docker images and wasm bytecode images.

In-stream

On July 10th, WasmEdge will appear at the GTOC Open Source Technology Summit, bringing a keynote speech on "Application of WebAssembly in the Cloud Native Era". Welcome to the live exchange!

The GOTC Global Open Source Technology Summit was initiated by the Open Atomic Open Source Foundation and the Linux Foundation in conjunction with Open Source China. It is a grand open source technology feast for global developers. The conference will bring together leading open source companies and top open source projects, covering cloud native, big data, artificial intelligence, Internet of Things, blockchain, DevOps, open source governance and other technical fields. Developers bring the latest and purest open source technology in the world, and at the same time spread open source culture and ideas, and promote the construction and development of open source ecology. Register directly: https://gotc.oschina.net/

{{o.name}}
{{m.name}}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324067130&siteId=291194637