CL LAB

HOME > CL LAB > KubernetesでWASMを動かそう #k0s #kubernetes #k8s #webassembly #wasm #wasi

KubernetesでWASMを動かそう #k0s #kubernetes #k8s #webassembly #wasm #wasi

 ★ 3

以前DockerでWASMを動かしてみましたが、本稿ではKubernetes(k0s)でWASMを動かしてみます。KubernetesはDocker同様、コンテナランタイムとして containerd を利用しているので、ほぼ同じような手順で実現できるはずです。早速やってみましょう。

注意: 本稿の内容は実験であり、本番環境では利用できません。また、開発中のソフトウェアを多数利用しているため、今後動作が変更される可能性があります。

仮想マシン環境の準備

まず仮想マシン環境をVagrant + VirtualBoxで準備しましょう。コントロールプレーン用VMを1つ、ワーカーノード用VMを2つです。

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "rockylinux/9"
  config.vm.box_check_update = false
  
  config.vm.define "main" do |cf|
    cf.vm.hostname = "main"
    cf.vm.network "private_network", ip: "192.168.56.101"
    cf.vm.provider "virtualbox" do |vb|
      vb.memory = 4096
    end
  end

  ( 1..2 ).each do |i|
    config.vm.define "node0#{i}" do |cf|
      cf.vm.hostname = "node0#{i}"
      cf.vm.network "private_network", ip: "192.168.56.20#{i}"
      cf.vm.provider "virtualbox" do |vb|
        vb.memory = 4096
      end
    end
  end
end

k0sによるKubernetesのインストール

k0sとは、軽量かつ使いやすい、100%オープンソースのKubernetesディストリビューションです。主な特徴としては、

  • フル機能のKubernetesを構築するために必要なすべてを単一バイナリに同梱
  •  k0s特有の改変を加えていない、CNCF認定の純正なKubernetesをデプロイ
  • 最低必要リソース1vCPU・1GBメモリ・2GBストレージのシングルノードから、HA構成の大規模クラスタまでサポート
  • Konnectivityをデフォルトで有効化

などが挙げられます。より詳しい情報はホワイトペーパーや「5分でわかるk0s」動画シリーズをご覧ください。

コントロールプレーン側

公式ドキュメントをもとにk0s v1.27.1をコントロールプレーン用VMにインストールします。

[vagrant@main ~]$ curl -sSLf https://get.k0s.sh | sudo sh
Downloading k0s from URL: https://github.com/k0sproject/k0s/releases/download/v1.27.1+k0s.0/k0s-v1.27.1+k0s.0-amd64
k0s is now executable in /usr/local/bin
[vagrant@main ~]$ k0s version
v1.27.1+k0s.0
[vagrant@main ~]$ 

k0s設定ファイルを作成します。ここではIPアドレスの変更のみを行っており、他はデフォルト設定です。

[vagrant@main ~]$ k0s config create > k0s.yaml.orig
[vagrant@main ~]$ cp -a k0s.yaml.orig k0s.yaml
[vagrant@main ~]$ vi k0s.yaml
[vagrant@main ~]$ diff -u k0s.yaml.orig k0s.yaml
--- k0s.yaml.orig	2023-04-27 08:16:32.898589360 +0000
+++ k0s.yaml	2023-04-27 08:17:41.367440655 +0000
@@ -5,11 +5,10 @@
   name: k0s
 spec:
   api:
-    address: 10.0.2.15
+    address: 192.168.56.101
     k0sApiPort: 9443
     port: 6443
     sans:
-    - 10.0.2.15
     - 192.168.56.101
     - fe80::a00:27ff:fefc:e996
     - fe80::a00:27ff:fee4:c9e9
@@ -72,7 +71,7 @@
   storage:
     etcd:
       externalCluster: null
-      peerAddress: 10.0.2.15
+      peerAddress: 192.168.56.101
     type: etcd
   telemetry:
     enabled: true
[vagrant@main ~]$ 

この設定ファイルをもとに、コントロールプレーン用VMにKubernetesをインストールします。

[vagrant@main ~]$ sudo mkdir /etc/k0s
[vagrant@main ~]$ sudo mv k0s.yaml /etc/k0s/
[vagrant@main ~]$ sudo /usr/local/bin/k0s install controller -c /etc/k0s/k0s.yaml 
[vagrant@main ~]$ sudo /usr/local/bin/k0s start
[vagrant@main ~]$ sudo /usr/local/bin/k0s status
Version: v1.27.1+k0s.0
Process ID: 4094
Role: controller
Workloads: false
SingleNode: false
[vagrant@main ~]$ 

ワーカーノード参加用トークンを払い出します。

[vagrant@main ~]$ sudo /usr/local/bin/k0s token create --role=worker /etc/k0s/k0s.yaml > join-token
[vagrant@main ~]$ 

この join-token ファイルをワーカーノード用VMにコピーします。

ワーカーノード側

コントロールプレーン用VMからコピーした join-token ファイルをもとにクラスタに参加させます。node01 と node02 で --node-ip オプションに与えるIPアドレスが異なることに注意しましょう。それぞれのVMのIPアドレスになります。

[vagrant@node01 ~]$ curl -sSLf https://get.k0s.sh | sudo sh
Downloading k0s from URL: https://github.com/k0sproject/k0s/releases/download/v1.27.1+k0s.0/k0s-v1.27.1+k0s.0-amd64
k0s is now executable in /usr/local/bin
[vagrant@node01 ~]$ sudo mkdir /etc/k0s
[vagrant@node01 ~]$ sudo mv join-token /etc/k0s/
[vagrant@node01 ~]$ sudo /usr/local/bin/k0s install worker --token-file /etc/k0s/join-token --kubelet-extra-args '--node-ip=192.168.56.201'
[vagrant@node01 ~]$ sudo /usr/local/bin/k0s start
[vagrant@node01 ~]$ sudo /usr/local/bin/k0s status
Version: v1.27.1+k0s.0
Process ID: 3992
Role: worker
Workloads: true
SingleNode: false
Kube-api probing successful: true
Kube-api probing last error:  
[vagrant@node01 ~]$ 
[vagrant@node02 ~]$ curl -sSLf https://get.k0s.sh | sudo sh
Downloading k0s from URL: https://github.com/k0sproject/k0s/releases/download/v1.27.1+k0s.0/k0s-v1.27.1+k0s.0-amd64
k0s is now executable in /usr/local/bin
[vagrant@node02 ~]$ sudo mkdir /etc/k0s
[vagrant@node02 ~]$ sudo mv join-token /etc/k0s/
[vagrant@node02 ~]$ sudo /usr/local/bin/k0s install worker --token-file /etc/k0s/join-token --kubelet-extra-args '--node-ip=192.168.56.202'
[vagrant@node02 ~]$ sudo /usr/local/bin/k0s start
[vagrant@node02 ~]$ sudo /usr/local/bin/k0s status
Version: v1.27.1+k0s.0
Process ID: 3993
Role: worker
Workloads: true
SingleNode: false
Kube-api probing successful: true
Kube-api probing last error:  
[vagrant@node02 ~]$ 

クラスタの確認

コントロールプレーン用VMでクラスタの状態を確認します。

[vagrant@main ~]$ sudo /usr/local/bin/k0s kubectl get nodes
NAME     STATUS   ROLES    AGE     VERSION
node01   Ready    <none>   4m14s   v1.27.1+k0s
node02   Ready    <none>   110s    v1.27.1+k0s
[vagrant@main ~]$ 

これでk0sによるKubernetesクラスタが準備できました。

WasmEdgeとrunwasiのインストール

WasmEdgeのインストール

ではワーカーノード用VMに WasmEdge をインストールしましょう。WasmEdge とは、WASI アプリケーションを実行できるスタンドアローンランタイムの一種です。

注意点として、本稿執筆時点でのWasmEdge最新版 0.12.0 ではうまく動作しません(参考:failed to start shim: start failed: terminate called after throwing an instance of 'std::out_of_range')。1つバージョンの古い 0.11.2 をインストールします。

[vagrant@node01 ~]$ curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.11.2
(中略)
[vagrant@node01 ~]$ sudo cp -a .wasmedge/lib/libwasmedge.so* /usr/local/lib/
[vagrant@node01 ~]$ sudo -E sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/libwasmedge.conf'
[vagrant@node01 ~]$ sudo ldconfig
[vagrant@node01 ~]$ 

runwasiのインストール

引き続き runwasiをインストールします。これは containerd から WASI アプリケーションを実行するための仕組みです。ここでは過去記事「DockerでWASMを動かそう」で作成したバイナリを再利用します。インストール先ディレクトリは /var/lib/k0s/bin になります。

[vagrant@node01 ~]$ sudo cp containerd-* /var/lib/k0s/bin/
[vagrant@node01 ~]$ sudo ls -l /var/lib/k0s/bin/containerd-*
-r-xr-x---. 1 root root  6557696 Apr 27 08:21 /var/lib/k0s/bin/containerd-shim
-r-xr-x---. 1 root root  8265728 Apr 27 08:21 /var/lib/k0s/bin/containerd-shim-runc-v1
-r-xr-x---. 1 root root 12009472 Apr 27 08:21 /var/lib/k0s/bin/containerd-shim-runc-v2
-rwxr-xr-x. 1 root root  6809232 Apr 27 08:29 /var/lib/k0s/bin/containerd-shim-wasmedged-v1
-rwxr-xr-x. 1 root root  9048000 Apr 27 08:29 /var/lib/k0s/bin/containerd-shim-wasmedge-v1
-rwxr-xr-x. 1 root root  9449304 Apr 27 08:29 /var/lib/k0s/bin/containerd-wasmedged
[vagrant@node01 ~]$ 

containerdの設定変更

containerd の設定ファイルを変更し、 runwasi と連携します。

[vagrant@node01 ~]$ sudo /var/lib/k0s/bin/containerd config default > containerd.toml.orig
[vagrant@node01 ~]$ cp -a containerd.toml.orig containerd.toml
[vagrant@node01 ~]$ vi containerd.toml
[vagrant@node01 ~]$ diff -u containerd.toml.orig containerd.toml
--- containerd.toml.orig	2023-04-27 08:38:44.110896751 +0000
+++ containerd.toml	2023-04-27 08:42:51.521164921 +0000
@@ -3,8 +3,8 @@
 oom_score = 0
 plugin_dir = ""
 required_plugins = []
-root = "/var/lib/containerd"
-state = "/run/containerd"
+root = "/var/lib/k0s/containerd"
+state = "/run/k0s/containerd"
 temp = ""
 version = 2
 
@@ -19,7 +19,7 @@
   uid = 0
 
 [grpc]
-  address = "/run/containerd/containerd.sock"
+  address = "/run/k0s/containerd.sock"
   gid = 0
   max_recv_message_size = 16777216
   max_send_message_size = 16777216
@@ -108,6 +108,9 @@
 
       [plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
 
+        [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.wasmedge]
+           runtime_type = "io.containerd.wasmedge.v1"
+
         [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
           base_runtime_spec = ""
           cni_conf_dir = ""
[vagrant@node01 ~]$ sudo cp -a containerd.toml /etc/k0s/
[vagrant@node01 ~]$ sudo /usr/local/bin/k0s stop
[vagrant@node01 ~]$ sudo /usr/local/bin/k0s start
[vagrant@node01 ~]$ sudo /usr/local/bin/k0s status
Version: v1.27.1+k0s.0
Process ID: 28179
Role: worker
Workloads: true
SingleNode: false
Kube-api probing successful: true
Kube-api probing last error:  
[vagrant@node01 ~]$ 

containerd + runwasi + WasmEdgeのテスト

containerd のテストをしてみましょう。

[vagrant@node01 ~]$ sudo /usr/local/bin/k0s ctr image pull --platform=wasi/wasm32 docker.io/michaelirwin244/wasm-example:latest
(中略)
[vagrant@node01 ~]$ sudo /usr/local/bin/k0s ctr run --rm --runtime=io.containerd.wasmedge.v1 docker.io/michaelirwin244/wasm-example:latest wasm-example
[2023-05-08 05:38:50.926] [info] loading failed: malformed section id, Code: 0x25
[2023-05-08 05:38:50.926] [info]     AOT arch type unmatched.
[2023-05-08 05:38:50.927] [info]     Load AOT section failed. Use interpreter mode instead.
Server is now running

「Server is now running」と表示されたら成功です。CTRL+C で終了しましょう。もし、

[vagrant@node01 ~]$ sudo /usr/local/bin/k0s ctr run --rm --runtime=io.containerd.wasmedge.v1 docker.io/michaelirwin244/wasm-example:latest wasm-example
Error: failed to start shim: start failed: terminate called after throwing an instance of 'std::out_of_range'
  what():  bitset::reset: __position (which is 1) >= _Nb (which is 1)
: signal: aborted (core dumped): unknown
Usage:
  k0s ctr [flags]

Flags:
  -h, --help   help for ctr

[vagrant@node01 ~]$

のようなエラーとなったら、WasmEdge 0.12.0 をインストールしている可能性があります。1つ古いWasmEdge 0.11.2 をインストールし直してください(参考:failed to start shim: start failed: terminate called after throwing an instance of 'std::out_of_range')。

WasmEdge と runwasi をもう1つのワーカーノード用VMでもインストールしましょう。ここでは手順は省略します。

KubernetesにWASIアプリケーションをデプロイ

それではいよいよKubernetesでWASIアプリケーションを動かしてみましょう。まずWasmEdge用のRuntimeClassを設定します。

[vagrant@main ~]$ vi wasmedge.yaml 
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: wasmedge
handler: wasmedge
[vagrant@main ~]$ sudo /usr/local/bin/k0s kubectl apply -f wasmedge.yaml 
runtimeclass.node.k8s.io/wasmedge created
[vagrant@main ~]$

サンプルアプリをDeploymentで配置し、NodePortで到達できるようにします。

[vagrant@main ~]$ vi wasm-example-deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: wasm-example-svc
spec:
  type: NodePort
  ports:
  - port: 8080
  selector:
    app: wasm-example
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wasm-example
spec:
  replicas: 2
  selector:
    matchLabels:
      app: wasm-example
  template:
    metadata:
      labels:
        app: wasm-example
    spec:
      runtimeClassName: wasmedge
      containers:
      - name: wasm-example
        image: michaelirwin244/wasm-example
        ports:
        - containerPort: 8080
[vagrant@main ~]$ sudo /usr/local/bin/k0s kubectl apply -f wasm-example-deployment.yaml 
service/wasm-example-svc created
deployment.apps/wasm-example created
[vagrant@main ~]$ 

確認してみます。

[vagrant@main ~]$ sudo /usr/local/bin/k0s kubectl get svc
NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kubernetes         ClusterIP   10.96.0.1       <none>        443/TCP          10d
wasm-example-svc   NodePort    10.105.207.55   <none>        8080:31037/TCP   97s
[vagrant@main ~]$ sudo /usr/local/bin/k0s kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
wasm-example-6dd64b8fb6-c95mn   1/1     Running   0          112s
wasm-example-6dd64b8fb6-ksckw   1/1     Running   0          112s
[vagrant@main ~]$

起動しているようです。アクセスしてみましょう。

[vagrant@main ~]$ curl 192.168.56.202:31037 ; echo
Hello world from Rust running with Wasm! Send POST data to /echo to have it echoed back to you
[vagrant@main ~]$

応答が返ってきました! 指示通りにしてみます。

[vagrant@main ~]$ curl --data 'Hello, World!' 192.168.56.202:31037/echo ; echo
Hello, World!
[vagrant@main ~]$ 

こちらも意図通りに動作しました!

まとめ

本稿では Vagrant + Virtualbox でテスト環境を準備し、k0s で Kubernetes クラスタを作成し、WasmEdge + runwasi でWASIアプリケーションをデプロイできるように設定しました。
まだまだベータ版・開発中のソフトウェアや機能ばかりで構築するのも一苦労ですが、成熟が進めんで手軽になればWASMが動いているKubernetes環境というのも増えていくと思います。クリエーションラインでは引き続き WebAssmbly と Kubernetes について調査していきたいと思います。

CL LAB Mail Magazine

CL LABの情報を逃さずチェックしよう!

メールアドレスを登録すると記事が投稿されるとメールで通知します。

メールアドレス: 登録

※登録後メールに記載しているリンクをクリックして認証してください。

Related post

Neo4j[ホワイトペーパー]CCPA