“网红” WebAssembly 与 K8s 如何实现双剑合璧?

1.png

做者 | 易立  阿里巴巴资深技术专家前端

导读:WebAssembly 技术已经走出浏览器,让计算无处不在。本文利用 containerd 的扩展机制,能够为 WebAssembly 应用提供与其余容器应用一致的、抽象的、应用分发、交付和运维模型,能够在 Kubernetes 集群中进行统一调度和管理。node

无处不在的 WebAssembly

若是评选 2019 年编程技术的“网红”,不管是前端圈仍是后端圈,WebAssembly (WASM) 都绝对可以高票入选。然而,若是评选最被“低估”的技术,我以为 WebAssembly 也能够轻松入围。linux

借用伏尔泰曾评价神圣罗马帝国的句式 “既不神圣,也不罗马,更非帝国”,咱们也能够说WebAssembly “既不限于 Web,更不是 Assembly(汇编语言)”。nginx

在 2019 年 12 月,万维网联盟 (World Wide Web Consortium  - W3C) 宣布 WebAssembly 核心规范正式成为 Web 标准,  这使得 WebAssembly 成为互联网上与 HTML, CSS, and JavaScript 并列的第四种官方语言,能够原生的运行在浏览器上。而更加剧要的是,WebAssembly 做为一个安全的、可移植、高效率的虚拟机沙箱,能够在 Internet 的任何地方、任何平台(不一样操做系统,不一样 CPU 体系架构下)安全运行应用。WebAssembly 已获得了全部主流浏览器厂商的普遍支持(Google Chrome, Microsoft Edge, Apple Safari, Mozilla Firefox 等),然而它的影响已经远超 Web。git

WebAssembly 的设计初衷之一是为了解决 JavaScript 的性能问题,使得 Web 网页应用有接近本机原生应用的性能。做为一个通用、开放、高效的底层虚拟机抽象,众多编程语言(如 C/C++, Rust 等)能够将现有应用编译成为 WASM 的目标代码,运行在浏览器中 。这让应用开发技术与运行时技术解耦,极大促进了代码复用。github

Mozilla 在 2019 年 3 月推出了 WebAssembly System Interface(WASI),来标准化 WebAssembly 应用与系统资源的交互抽象,好比文件系统访问,内存管理,网络链接等,相似 POSIX 这样的标准 API。WASI 规范大大拓展了 WASM 应用的场景,可让其能够超越浏览器环境,做为一个独立的虚拟机运行各类类型的应用。同时,平台开发商能够针对具体的操做系统和运行环境提供 WASI 接口不一样的实现,能够在不一样设备和操做系统上运行跨平台的 WebAssembly 应用。这可让应用执行与具体平台环境实现解耦。这一切使得“Build Once, Run Anywhere”的理想逐渐造成现实。WASI 的示意图以下所示。2019 年 11 月,为了进一步推进模块化 WebAssembly 生态系统,Mozilla、Fastly、英特尔和红帽公司携手成立了字节码联盟(Bytecode Alliance),共同领导 WASI 标准、 WebAssembly 运行时、语言工具等工做。web

2.png

图片来源:https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/docker

WASM 与容器相爱相杀

WebAssembly 是否会取代容器?

正由于 WebAssembly 所具有的的安全、可移植、高效率,轻量化的特色,很是适于应用安全沙箱场景。WASM 获得了容器、函数计算、IoT / 边缘计算等社区的普遍关注。Docker 创始人 Solomon Hykes 在 WASI 发布之际的一句 Twitter,更是成为了去年容器和 WebAssembly 社区引用频率最高的一句话之一。编程

3.png

Fastly, Cloudflare 等 CDN 厂商基于 WebAssembly 技术实现了更加轻量化的应用安全沙箱,能够在一个进程内部运行多个独立的用户应用。阿里云 CDN 团队 EdgeRoutine 也实现了相似技术。与容器技术相比,WASM 能够实现毫秒级冷启动时间和极低的资源消耗。json

4.png

原图:https://blog.cloudflare.com/cloud-computing-without-containers/

固然,世界上没有完美的技术。任何沙箱技术不可能同时知足执行效率、安全隔离性和通用性这三个维度的要求。WASM 在安全隔离和通用性等方面与 Docker Container 等存在差距。虽然如此,咱们仍是看到了 WebAssembly 技术巨大的潜力。

WebAssembly 容器

个人理解是 WebAssmebly 能够成为一种容器类型,相似 Linux Container 或者 Windows Container 同样。成为一个跨平台的标准应用分发方式和运行时环境。

应用分发

Docker 容器的一个重要贡献是其标准化了容器化应用打包规范 Docker Image,并且它已经成为开放容器计划 (Open Container Initiative - OCI) 的镜像格式标准。Docker 镜像提供了自包含、自描述的镜像格式。它能够将应用以及其依赖的环境信息打包在一块儿,从而实现应用与运行环境解耦,让容器应用能够轻松运行在从本地开发环境到云端生产环境的不一样场景中。而且社区围绕 Docker 镜像构建了繁荣的工具链生态,如 Docker Hub 能够进行应用分发和 CI / CD 协同,Nortary / TUF 项目能够保障应用可信地分发、交付。

对与 WebAssembly,目前社区提供了相似 NPM 的包管理实现 WAPM,能够较好地支持应用的分发。 为 WebAssembly 应用构建 Docker 镜像,能够实现共赢的局面。

  • WebAssembly 开发者能够彻底复用 Docker/OCI 镜像规范和工具链,进一步简化应用分发和交付。好比,咱们能够将 Nginx 的 WASM 镜像做为基础镜像,基于这个镜像能够构建包含不一样 Web 内容的应用镜像;咱们能够利用 tag 对应用版本进行追踪;利用 Docker Registry 进行应用分发;在这个过程咱们还能够进一步利用数字签名来保障安全的软件供应链;
  • Docker 镜像规范支持 Multi-Arch 镜像,能够简化不一样 CPU 体系架构(如 x86, ARM, RISC-V 等)的应用镜像的构建与分发。而 WebAssembly 天生具有可移植性,大大简化了跨平台 Docker 应用镜像的构建和分发。参考:利用 Docker 加速 ARM 容器应用开发和测试流程

我提供了一个技术原型示例项目,你们能够参考其中的例子来构建 WASM 容器镜像。因为 WebAssembly 应用采用紧凑的二进制格式,并且没有任何操做系统依赖,WASM 应用能够构建出很是小的容器镜像。你们能够自行感觉一下:

$ sudo ctr image ls
REF                                                           TYPE                                                 DIGEST                                                                  SIZE      PLATFORMS   LABELS
docker.io/denverdino/c-http-server-wasm:latest                application/vnd.docker.distribution.manifest.v2+json sha256:2efa759f46f901cda2e6a9b4228c423b17a960c06e957964e72c21dc5b42408f 29.2 KiB  linux/amd64 -
docker.io/denverdino/hellowasm:latest                         application/vnd.docker.distribution.manifest.v2+json sha256:cadcc8b07eb82b18db2c8f500fa2b11e5ebf2e9054cfa687e4ffe44861860132 8.2 KiB   linux/amd64 -
docker.io/denverdino/nginxwasm:latest                         application/vnd.docker.distribution.manifest.v2+json sha256:8735c82524a463b842b7c79f2c1be8094ee1c57cfd34154f68752fbe79c25998 582.7 KiB linux/amd64 -

安全隔离

WebAssembly 的最初设计目标是让应用能够安全运行在浏览器中。WASM 虚拟机提供的沙箱和内存隔离机制,能够有效减小安全攻击面。而当 WebAssembly 走出浏览器,面向更加通用的场景。WASM 也面对更加复杂的安全挑战。

WASI 提供了基于能力的安全模型。WASI 应用遵循最小权限原则,应用只能访问其执行所需的确切资源。传统上,若是应用须要打开文件,它会带路径名字符串调用系统操做 open。而后系统调用会检查应用是否具备访问该文件的相关权限,好比 Linux 实现了基于用户/组的权限模型。这样隐式的安全模型,依赖于正确的安全管理配置,好比一旦特权用户执行了一个恶意应用,它就能够访问系统中任意的资源。而对于 WASI 应用而言,若是它须要须要访问指定文件等系统资源,须要从外部显式传入加有权限的文件描述符引用,而不能访问任何其余未受权资源。这中依赖注入的方式能够避免传统安全模型的潜在风险。

一个示意图以下:

5.png

原图:https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/

咱们能够看到 WASI 的安全模型与传统操做系统安全模型很是不一样,并且还在持续演进中。好比字节码联盟提出了 nanoprocess 来解决应用模块间的安全协同和信任传递。

WebAssembly/WASI 的安全模型依然存在不足,好比:

  • 资源隔离

对于内存资源,WebAssembly 实现了线性内存模型。WebAssembly 应用只能利用索引访问传入的一段逻辑线性内存。而 WASM 虚拟机负责肯定内存的实际物理地址,WASM 应用没法获知内存的真实地址,也没法经过越界访问等方式发动攻击。因此理论上,能够对 WASM 应用进行资源容量限制。可是目前部分 WASM 虚拟机还没法对内存进行精确的隔离限制。

对于 CPU 资源,部分的 WASM 虚拟机实现能够对应用使用的 CPU 资源进行计量,可是大多没法实现精确的配额限制、优先级和抢占式调度。

I/O 资源,好比 IOPS 等,WASM 目前彻底没有相关的隔离能力。

  • 网络安全

WASI 的 Capability 模型对于文件系统访问相对比较容易保护。可是这个静态的安全模型没法适用于动态的网络应用场景。在微服务架构中,应用常常经过 Service Registry 进行服务发现,为服务的调用者和提供者实现动态的调用绑定。这个语义是没法用静态的 capability 模型描述和注入的。这也致使了 WASI 的网络部分 API 还处于讨论之中。现有的 WASI 网络安全模型,以及相关讨论

Linux 操做系统和容器技术已经提供了很是完备的资源隔离和安全隔离实现。与 WebAssembly 结合在一块儿能够应对不一样场景对不一样隔离级别的需求。

  • 共享进程资源 - 多个 WASM 应用模块运行在一个 WASM 虚拟机进程内部,依赖 WASM 运行时进行隔离。隔离级别低,控制粒度比较粗,资源开销极小。能够以较小代价保障系统安全。适合受限问题域的应用安全隔离;

  • 独立进程资源 - 不一样 WASM 应用模块运行在不一样的 WASM 虚拟机进程中,能够复用操做系统的进程级隔离能力,好比 CGroup。此外,还能够利用相似 Kubernetes 中的 Network Policy (网络策略),或者服务网格(如Istio)等技术,对进程的网络访问进行细粒度的控制,甚至实现零信任网络。隔离级别比较高,控制粒度比较细,资源开销适中。能够应用于更加通用的场景。

注:固然利用安全沙箱如虚拟化等技术,结合 WebAssembly,能够进一步最小化安全攻击面,可是 ROI 不高。

调度与编排

在云时代,Kubernetes 已经成为分布式环境下资源调度和应用编排的事实标准。Kubernetes 能够屏蔽底层设施的差别性。能够在同一个 K8s 集群中包含 x8六、ARM 等不一样体系架构的节点,能够支持 Linux,Windows 等不一样的操做系统。Kubernetes 和 WebAssembly 相结合能够进一步提高应用的可移植性。

微软的 Deis Labs 年初发布了一个实验项目,来利用 Virtual Kubelet 相似的架构调度 WebAssembly 应用。可是这个方式有不少局限,没法借助容器方式进行应用分发,也没法利用 K8s 的语义进行资源编排。 

可贵有一个春节假期能够宅在家里,在此期间我基于 Derek McGowan 去年的一个实验性项目,完善了 containerd 的 WASM shim 实现。可让 containerd 支持 WASM container,而且能够利用 Kubernetes 集群管理和调度 WASM container。

项目的代码实现: https://github.com/denverdino/containerd-wasm

注:这个项目更可能是概念验证,进程管理、资源限制,性能优化等的细节并没未完整实现。

整个系统的架构设计以下,“container-shim-wasm-v1”做为 Containerd 的扩展,利用 wasmer 做为 WASM 应用运行时环境,能够实现与 runc 容器一致的用户体验。

6.png

咱们还会将其注册为 K8s 的一个 RuntimeClass ,容许用户利用 K8s 来交付和运维 WASM 应用。

注:RuntimeClass 是 Kubernetes v1.12 引入的新概念,可让 Kubernetes 支持多种不一样的容器运行时,好比 runc 容器、或者 Kata Containers,gVisor 等安全沙箱容器。更多细节能够参考:containerd 与安全沙箱的 Kubernetes 初体验

Talk is Cheap, 放码过来

首先,咱们将利用 Minikube 建立一个 K8s 测试环境,并将 Containerd 做为 Kubernetes 集群的容器运行时。

建立虚拟机测试环境

建立 Minikube K8s 集群,并将 Containerd 做为 Kubernetes 集群容器运行时。

minikube start --image-mirror-country cn \
    --iso-url=https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.6.0.iso \
    --registry-mirror=https://tgtsuwdg.mirror.aliyuncs.com \
    --container-runtime=containerd

进入 Minikube 虚拟机:

$ minikube ssh
                         _             _
            _         _ ( )           ( )
  ___ ___  (_)  ___  (_)| |/')  _   _ | |_      __
/' _ ` _ `\| |/' _ `\| || , <  ( ) ( )| '_`\  /'__`\
| ( ) ( ) || || ( ) || || |\`\ | (_) || |_) )(  ___/
(_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____)

配置环境所需依赖:

  • wasmer 0.13;
  • minikube 缺省安装了 container 1.2.x,须要升级 containerd 1.3.x;
  • 我提供了一个预编译的 containerd-wasm-shim-v1,也可本身编译一个版本。
cd ~
# Install Wasmer 0.13.1
curl -L -O https://github.com/wasmerio/wasmer/releases/download/0.13.1/wasmer-linux-amd64.tar.gz
gunzip wasmer-linux-amd64.tar.gz
tar xvf wasmer-linux-amd64.tar
sudo cp bin/* /usr/bin/
# Upgrade containerd to v1.3.2
curl -L -O https://github.com/containerd/containerd/releases/download/v1.3.2/containerd-1.3.2.linux-amd64.tar.gz
gunzip containerd-1.3.2.linux-amd64.tar.gz
tar xvf containerd-1.3.2.linux-amd64.tar
sudo systemctl stop containerd
sudo cp bin/* /usr/bin/
sudo systemctl restart containerd
# Install containerd-wasm-shim
wget http://kubernetes.oss-cn-hangzhou.aliyuncs.com/containerd-wasm/containerd-shim-wasm-v1
chmod +x containerd-shim-wasm-v1
sudo mv containerd-shim-wasm-v1 /usr/bin/

配置 containerd 支持 WASM shim

在 containerd 配置文件中添加 wasm shim 相关配置,并重启 containerd。

$ cat <<EOF | sudo tee -a /etc/containerd/config.toml
disabled_plugins = ["restart"]
[plugins.cri.containerd.runtimes.wasm]
  runtime_type = "io.containerd.wasm.v1"
EOF
$ sudo systemctl restart containerd

测试 Hello World WASM 容器应用:

$ sudo ctr image pull docker.io/denverdino/hellowasm:latest
docker.io/denverdino/hellowasm:latest:                                            resolved       |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:cadcc8b07eb82b18db2c8f500fa2b11e5ebf2e9054cfa687e4ffe44861860132: done           |++++++++++++++++++++++++++++++++++++++|
layer-sha256:ecda28441283ecf01d35bca0361f2c1ef26a203454a06789ee5ce71ba1e32ca3:    done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:57974480d640c8d60d254a8b0fa4606b2c7107fe169bc3ddd455091277c3a5e4:   done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 3.0 s                                                                    total:   0.0 B (0.0 B/s)
unpacking linux/amd64 sha256:cadcc8b07eb82b18db2c8f500fa2b11e5ebf2e9054cfa687e4ffe44861860132...
done
$ sudo ctr run --rm --runtime io.containerd.wasm.v1 docker.io/denverdino/hellowasm:latest test1
Hello world

测试 Nginx 的 WASM 容器应用:

$ sudo ctr image pull docker.io/denverdino/nginxwasm:latest
docker.io/denverdino/nginxwasm:latest:                                            resolved       |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:8735c82524a463b842b7c79f2c1be8094ee1c57cfd34154f68752fbe79c25998: exists         |++++++++++++++++++++++++++++++++++++++|
layer-sha256:27f4d8ad067fbb709d18ea5acd7a5ddfb85851e5d9f030636e9da3d16cc4bd07:    done           |++++++++++++++++++++++++++++++++++++++|
config-sha256:a55bd3bdb9d00fdac5ee2f64bfc1856e58e8bb90587943969ad3d8115f4ced70:   done           |++++++++++++++++++++++++++++++++++++++|
elapsed: 3.0 s                                                                    total:   0.0 B (0.0 B/s)
unpacking linux/amd64 sha256:8735c82524a463b842b7c79f2c1be8094ee1c57cfd34154f68752fbe79c25998...
done
$ sudo ctr run --rm --runtime io.containerd.wasm.v1 docker.io/denverdino/nginxwasm:latest test2
2020/02/01 07:01:21 [notice] 30672#0: using the "select" event method
2020/02/01 07:01:21 [notice] 30672#0: nginx/1.15.3
2020/02/01 07:01:21 [notice] 30672#0: built by clang 6.0.1  (emscripten 1.38.11 : 1.38.11)
2020/02/01 07:01:21 [notice] 30672#0: OS: Linux 4.19.81
2020/02/01 07:01:21 [notice] 30672#0: getrlimit(RLIMIT_NOFILE): 1024:1024

在 Minikube 外部,能够用以下方式得到 nginx 应用的访问地址:

$ echo http://$(minikube ip):8080
http://192.168.64.13:8080

利用浏览器打开上述地址,显示以下:

7.png

建立 WASM 容器的 RuntimeClass CRD

为了 WASM 容器能够被 Kubernetes 所调度,咱们须要建立一个 RuntimeClass CRD。

下载示例文件:

$ git clone https://github.com/denverdino/wasm-container-samples
$ cd wasm-container-samples

注册 RuntimeClass “wasm”这个值:

$ cat wasm-runtimeclass.yaml
apiVersion: node.k8s.io/v1beta1
kind: RuntimeClass
metadata:
  name: wasm
handler: wasm
$ kubectl apply -f wasm-runtimeclass.yaml
runtimeclass.node.k8s.io/wasm created
$ kubectl get runtimeclass
kubectl get runtimeclass
NAME   CREATED AT
wasm   2020-02-01T06:24:12Z

在 K8s 中运行 WASM 容器应用

在 K8s 应用的 yaml manifest 中,咱们能够在 Pod Spec 上指明所需 runtimeClassName。下面咱们就用 K8s 来部署一个 nginx 的 WASM 容器。

$ cat nginx-wasm.yaml
apiVersion: v1
kind: Pod
metadata:
 name: nginx-wasm
spec:
 runtimeClassName: wasm
 containers:
 - name: nginx
   image: denverdino/nginxwasm
   ports:
     - containerPort: 8080
$ kubectl apply -f nginx-wasm.yaml
pod/nginx-wasm created
$ kubectl get pod
NAME         READY   STATUS    RESTARTS   AGE
nginx-wasm   1/1     Running   0          9s

新机遇、新但愿

目前为止,WebAssembly 技术仍处于初期阶段,WASI 也有不少局限性。可是社区的进展很是快,SIMD 指令支持,多线程处理等规范也正在快速演进中。WebAssembly 已经打破次元壁,将高性能的计算能力带领到 Web 浏览器端,愈来愈多的计算密集型的游戏、AI 模型预测、和数据处理应用被移植到浏览器端,能够为应用提供更加优化的用户体验。

WebAssembly 更广阔的空间在云计算领域、区块链等分布式计算领域。WebAssembly 轻量、敏捷、安全的特性,能够有效下降 Serverless 应用启动速度和资源消耗。同时 WebAssembly 的可移植,可让应用一致运行在从云端服务器到边缘 IoT 设备等不一样平台环境中,让计算无处不在。

利用 containerd 的扩展机制,能够为 WebAssembly 应用提供与其余容器应用一致的、抽象的、应用分发、交付和运维模型,能够在 Kubernetes 集群中进行统一调度和管理。但愿经过相似的探索能够简化基于 WebAssembly 的分布式应用管理和运维。

关于做者

易立,阿里云资深技术专家,阿里云容器服务的研发负责人。以前曾在 IBM 中国开发中心工做,担任资深技术专员;做为架构师和主要开发人员负责或参与了一系列在云计算、区块链、Web 2.0,SOA 领域的产品研发和创新。阿里云容器平台团队求贤若渴!社招技术专家 / 高级技术专家,base 杭州 / 北京 / 深圳。欢迎发简历到 jiaxu.ljx@alibaba-inc.com

8.png

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,作最懂云原生开发者的技术圈。”

相关文章
相关标签/搜索