在kubernetes上執行WASM負載

charlieroro發表於2021-05-07

在kubernetes上執行WASM負載

WASM一般用在前端業務中,但目前有擴充套件到後端服務的趨勢。本文使用Krustlet 將WASM服務部署到kubernetes。

簡介

Krustlet 是一個可以在kubernetes本地執行WebAssembly負載的工具。Krustlet作為kubernetes叢集中的節點。當使用者使用特定node tolerations來排程Pod時,kubernetes API會將該負載排程到一個Krustlet節點,Krustlet會拉取並執行模組。

為了在Krustlet 節點上執行一個應用,首先必須將該應用編譯為WebAssembly 格式,並推送到映象倉庫中。

準備

首先使用kind安裝一個kubernetes叢集(minikube要求使用virtualBox驅動)。

安裝Krustlet

安裝二進位制檔案

首先從官網下載安裝Krustlet,拷貝到一個系統可識別的路徑即可(如/usr/local/bin)

生成bootstrap檔案

Krustlet和kubelet的初始化流程類似,執行如下命令生成Krustlet的bootstrap.conf檔案,預設路徑為/root/.krustlet/config

$ bash <(curl https://raw.githubusercontent.com/deislabs/krustlet/master/docs/howto/assets/bootstrap.sh)

執行Krustlet

找到kind使用的預設閘道器地址:

# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
...
b48010373347   kind      bridge    local

# docker network inspect b48010373347|grep "Gateway"
                    "Gateway": "172.18.0.1"

執行Krustlet:

$ export KUBECONFIG=~/.krustlet/config/kubeconfig
$ krustlet-wasi --node-ip 172.18.0.1 --bootstrap-file=/root/.krustlet/config/bootstrap.conf

執行介面如下,提示需要審批CSR:

# krustlet-wasi --node-ip 172.18.0.1 --bootstrap-file=~/.krustlet/config/bootstrap.conf
BOOTSTRAP: TLS certificate requires manual approval. Run kubectl certificate approve ubuntu-tls

審批CSR

$ kubectl certificate approve <hostname>-tls

校驗

執行kubectl get nodes -o wide,可以看到新增了一個節點ubuntu,在該節點上可以執行WebAssembly負載:

# kubectl get node -owide
NAME                 STATUS   ROLES    AGE     VERSION   INTERNAL-IP   EXTERNAL-IP  
kind-control-plane   Ready    master   16m     v1.19.1   172.18.0.2    <none>       
ubuntu               Ready    <none>   8m37s   0.7.0     172.18.0.1    <none>       

部署應用

下面安裝官方的一個例子/demos/wasi/simpleserver/。執行如下命令即可:

# kubectl apply -f simpleserver.yaml

該pod會啟動一個偽服務,程式碼如下:

use std::thread::sleep;
use std::time::Duration;

fn main() {
    loop {
        println!("Hello, World!");
        sleep(Duration::from_secs(5));
    }
}

需要注意的是,在k8s.yaml中映象欄位為webassembly.azurecr.io/simpleserver:v1.0.0,但它並不是一個標準的容器映象,而是WASM的module,預設會放到/root/.krustlet/.oci/modules目錄下。在/root/.krustlet/.oci/modules/webassembly.azurecr.io/simpleserver/v1.0.0目錄下檢視拉取到的module

# ll
-rw-r--r-- 1 root root      71 May  6 22:34 digest.txt
-rw-r--r-- 1 root root 1998989 May  6 22:34 module.wasm

可以看到module.wasm的大小隻有約2M,是一個支援跨平臺執行的二進位制檔案,由此可以看出WASM和容器的區別:容器是需要基礎映象的,而WASM則不需要,它是一個可以跨平臺執行的二進位制檔案,且需要特定的runtime工具執行。

# file module.wasm
module.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)

可以使用wasmtime執行.wasm檔案,wasmtime的下載方式如下:

curl https://wasmtime.dev/install.sh -sSf | bash

執行如下:

# wasmtime module.wasm
Hello, World!
Hello, World!
Hello, World!
...

WASM POD分析

檢視該Pod,可以看到它就是一個正常執行的pod

# kubectl get pod
NAME           READY   STATUS    RESTARTS   AGE
simpleserver   1/1     Running   0          7m59s

執行kubectl describe pod simpleserver檢視該pod資訊

apiVersion: v1
kind: Pod
metadata:
  name: simpleserver
  labels:
    app: simpleserver
spec:
  containers:
    - image: webassembly.azurecr.io/simpleserver:v1.0.0
      imagePullPolicy: Always
      name: simpleserver
  tolerations:
    - key: "node.kubernetes.io/network-unavailable"
      operator: "Exists"
      effect: "NoSchedule"
    - key: "kubernetes.io/arch"
      operator: "Equal"
      value: "wasm32-wasi"
      effect: "NoExecute"
    - key: "kubernetes.io/arch"
      operator: "Equal"
      value: "wasm32-wasi"
      effect: "NoSchedule"

原始碼編譯執行

編譯

由於上例的程式碼是rust編寫的,因此需要安裝rust套件:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

在rust工具鏈中新增wasm:

$ rustup target add wasm32-wasi

生成可執行檔案:

$ cargo build --target wasm32-wasi --release

推送module

由於生成的二進位制並不是標準的映象,因此無法直接推送到OCI倉庫中,可以使用wasm-to-oci將module推送到OCI 倉庫。

但需要注意的是,並不是所有的映象倉庫都支援推送WASM module,目前支援的映象倉庫為:

PS: 我使用了harbor映象庫,但無論使用http(報token無法解析)還是https(ca issuer無法識別),krustlet-wasi都無法成功拉取映象。因此,建議有條件的話使用Azure或Google的映象倉庫

參考這篇文章搭建harbor映象倉庫(使用https方式)。搭建成功後,登入倉庫,並執行如下命令,將WASM module推送到倉庫中:

# wasm-to-oci push simpleserver.wasm registry.harbor.com/library/wasm-hello-world:v1 --use-http

在harbor倉庫中可以看到剛上傳的module。

image

執行自己的module

將k8s.yml中的image修改為自己的module地址:

image: registry.harbor.com/library/simpleserver:v1

總結

WASM本身支援多種語言,因此可以方便地將市面上已有的服務轉換為WASM格式。後續WebAssemble有可能成為一種新的容器型別,類似Linux容器或Windows容器。
WASM由WASM虛擬機器實現隔離性,但目前的隔離程度有限(如CPU、mem、network、共享儲存等),且WASM虛擬機器實現各異。這裡給出了一系列WebAssembly Runtimes。

可以參考一下這篇文章Using WebAssembly and Kubernetes in Combination,裡面詳細講解了WASM的現狀。WASM目前還處於早期,WASI標準後續也需要進行迭代更新。但由於其本身具有的輕量級以及可移植的優點,相信前途會一片光明。

PS:對服務端的WASM支援最多最好的語言是RUST,是否是時候撿起來了?

相關文章