KubernetesでWASMを動かそう #k0s #kubernetes #k8s #webassembly #wasm #wasi
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
以前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 について調査していきたいと思います。