• Docker和Wasm集成带来的可能性
  • 发布于 2个月前
  • 195 热度
    0 评论
在这篇文章中,我们将构建一个Rust应用程序,它给出两个数字的和。我们将在浏览器中以WebAssembly应用程序的形式运行应用程序,并将其打包为docker容器。

WASM
很长一段时间以来,开发人员一直在使用Javascript来提供web上的定制体验,也有一些其他的web脚本语言,但它们都有局限性。为了增强体验,开发人员开始使用针对不同浏览器的二进制插件,尽管如此,它们在执行具有高级功能的Web应用程序时还很欠缺。这就是WebAssembly的用处所在,现在开发人员可以用C/C++/Rust等语言开发代码,并使用WebAssembly编译来创建可以在web浏览器中运行的本地字节码代码。

WebAssembly不能自己工作,它仍然需要Javascript。但它可以取代Javascript中的缓慢计算部分,并提供接近本机的速度。它的工作方式是,当开发人员用本地语言编写代码时,他们可以使用WebAssembly作为编译目标。WebAssembly生成的字节码可以在浏览器提供的WebAssembly运行时中运行。一些例子是像《末日3》这样的游戏,以及像Autocad和Figma这样的web应用程序,它们现在可以通过任何浏览器作为WebApp使用。这里最大的优势是应用程序现在是独立于主机的,即相同的应用程序不受操作系统和CPU架构的影响。

除了浏览器,WebAssembly字节码也可以被容器化并作为docker容器执行。这开启了一个充满可能性的全新世界。让我们看看下面的内容。

docker与WebAssembly的比较:

Docker提供了一种将应用程序及其依赖项(OS依赖项和库)打包到映像中的方法,开发人员可以将该映像的各种实例作为容器运行。这是由容器运行时启用的,可以是Docker engine, runc, containd等。所以基本上容器运行时可以启动应用程序的不同实例作为不同的容器,它还允许与主机操作系统资源通信。

在WebAssembly的情况下,WebAssembly运行时启用代码执行,所有现代浏览器都提供这个运行时。WebAssembly Runtime的其他例子有Wasmedge, NodeJs等。与系统资源的通信是通过WebAssembly系统接口实现的,如图所示。

Containerd -是一个流行的docker容器运行时环境,目前Docker和Kubernetes都支持它。Docker的工作人员正在为Wasmedge运行时环境启用容器进行努力,这将允许WebAssembly应用程序作为docker容器执行。

将WebAssembly应用程序作为docker容器运行的优点:
1.不需要基本映像,因此容器的大小非常小,基本上相当于编译后的字节代码本身的大小
2.接近本地容器的启动和执行

构建应用程序
让我们先从安装开始
1,安装Rust - https://www.rust-lang.org/learn/get-started
2,安装Wasm pack - https://rustwasm.github.io/wasm-pack/installer/
3,可选安装cargo-generate -启动模板项目
4,可选安装npm -测试/运行javascript应用程序
5,安装Docker桌面-启用容器提取和存储图像,也启用实验功能(如果没有启用)

WebApp
让我们先从创建WebApp开始,当你必须将应用程序创建为Docker容器时,有一个小的区别,我将在下一节告诉你。
使用cargo创建一个作为lib模块的新项目:
cargo init --lib rust-wasm-docker-hello-world
Cargo.toml文件如下:
[package]
name = "rust-wasm-docker-hello-world"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wasm-bindgen = "0.2.63"

[lib]
crate-type = ["cdylib"]
在lib.rs文件中写入如下代码:
use wasm_bindgen::prelude::*; 

#[wasm_bindgen] 
pub fn add(left: usize, right: usize) -> usize {
    left + right
}
使用wasm-pack进行构建:
wasm-pack build --target web
你会注意到一个pkg文件夹,里边有Javascript和wasm文件。

在项目根目录下创建一个html文件夹,并在文件夹中创建一个index.html文件,使用Javascript配置Wasm应用程序,如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>堆代码 duidaima.com</title>
</head>
<body>
<script type="module">
    import init, { add } from '../pkg/rust_wasm_docker_hello_world.js'
    await init()
    console.log(add(1,3))
</script>
</body>
</html>
在这里我们使用Javascript导入在Wasm应用程序中创建的“add”函数并调用。正如我上面提到的,wasm-bindgen支持Javascript和wasm字节码之间的通信。你可以使用NodeJs或任何其他服务器来托管你的应用程序,并使用web浏览器打开它。如下所示,控制台正在打印输出:

Docker
现在要对这个应用程序进行容器化,我们需要构建可以承载wasm文件的映像。在此之前,我们需要一个main.rs文件。

Docker只能通过main函数进入应用程序,Docker将使用Wasmedge环境来执行main函数中的代码。
mod lib;
use std::env;
fn main() {
    let args: Vec<String> = env::args().collect();
    let num1 = &args[1];
    let num2 = &args[2];
    let sum = lib::add(num1.parse::<usize>().unwrap(), num2.parse::<usize>().unwrap());
    println!("Sum of 2 numbers is {}", sum);
}
执行如下命令测试一下代码:
cargo run 1 2

Finished dev [unoptimized + debuginfo] target(s) in 0.03s
     Running `target/debug/rust-wasm-docker-hello-world 1 2`
Sum of 2 numbers is 3
在构建应用程序之前还需要修改Cargo.toml和lib.rs文件,如下:
Cargo.toml
[dependencies]
# wasm-bindgen = "0.2.63"

[lib]
# crate-type = ["cdylib"]
lib.rs
// use wasm_bindgen::prelude::*; 

// #[wasm_bindgen] 
pub fn add(left: usize, right: usize) -> usize {
    left + right
}
完成之后,为WASM编译/构建应用程序:
cargo build --target wasm32-wasi --release
在项目根目录下创建Dockerfile文件:
FROM scratch
COPY ./target/wasm32-wasi/release/rust-wasm-docker-hello-world.wasm /rust-wasm-docker-hello-world.wasm
ENTRYPOINT [ "rust-wasm-docker-hello-world.wasm" ]
我们使用的是scratch,这意味着没有提供基本镜像。因此这个镜像只包含应用程序字节码。

构建镜像:
docker buildx build --platform wasi/wasm32 -t paras301/docker-wasm:latest .
注意,镜像的大小只有522Kb,镜像的操作系统是WASI,即WebAssembly系统接口。

运行docker镜像:
docker run --rm --name=docker-wasm --runtime=io.containerd.wasmedge.v1 --platform=wasi/wasm32 paras301/docker-wasm:latest 1 2

Sum of 2 numbers is 3
在运行docker镜像时,需要传递运行时和平台,因此docker会理解使用wasmedge作为这个特定容器的运行时环境。

现在你看到了Docker和Wasm集成带来的可能性,由于镜像大小只有几mb,开发人员可以开始创建容器,为每个请求提供接近本机的速度,并且预热时间也接近0。此外,相同负载的资源需求也会减少很多。到目前为止,该特性的唯一缺点是仍处于测试阶段,我相信Wasm Apps和Wasm Docker容器会有一个美好的未来。
用户评论