fbpx

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

以前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 4m14s v1.27.1+k0s
node02 Ready 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 443/TCP 10d
wasm-example-svc NodePort 10.105.207.55 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 について調査していきたいと思います。

Author

Chef・Docker・Mirantis製品などの技術要素に加えて、会議の進め方・文章の書き方などの業務改善にも取り組んでいます。「Chef活用ガイド」共著のほか、Debian Official Developerもやっています。

Daisuke Higuchiの記事一覧

新規CTA