はじめに
こんにちは、ACS事業部の吉川です。
本記事はQiitaのAzure Advent Calendar 2022の12日目が空いていたので書きました。
先日、以下のアップデートが発表されたのをご存知でしょうか。
Azure Kubernetes Service(AKS)で、コンテナではなく WebAssembly(WASM)が動く というものです。
最近社内でもWebAssemblyが話題に挙がることが多いので、これを機に入門してみることにします。
AKSでWASMを動かすしくみ
私のぼんやりした認識では「WASMはブラウザ上で動くもの」と理解していたのですが、WASI(WebAssembly System Interface)というインターフェースが整備されておりOS上でもWASMが動くようになっているそうです。この仕組みを使ってAKS上でサーバーサイドのアプリケーションとして稼働させるわけですね。
冒頭紹介したアップデート情報では、Kubernetes上でのWASMの実行に Krustlet を利用するとの記載があったのですが、最新のドキュメントを見ると Containerd Wasm Shimsを利用するように変更したようです。
昨年の10月に発表された機能ですが、実行環境がガラッと変更になるなどまだまだ安定してなさそうです。この記事は2022年12月21日時点の状態で確認していますが、今後同じ手順では動かない可能性もあるのでご注意ください。 (まだプレビューの機能ですので…)
Containerd Wasm Shimsの制約として、実行するWASMアプリケーションは
のどちらかのフレームワークを使って作成する必要があります。今回は Spin を利用したアプリケーションを例として説明します。
Azure上の環境作成
チュートリアルとしてAzure上に環境を作成していきます。
作成するリソースは AKSクラスターとAzure Container Registry(ACR) の2つです。
# リソース名/リージョンの定義 RG_NAME=rg-sample AKS_NAME=aks-sample ACR_NAME=acrwasmsample LOCATION=japaneast # リソースグループ作成 az group create --location $LOCATION --name $RG_NAME # AKSクラスター作成 az aks create -g $RG_NAME -n $AKS_NAME -l $LOCATION \ --node-count 1 # ACR作成 az acr create -g $RG_NAME -n $ACR_NAME -l $LOCATION --sku Basic # kubectlのインストール sudo az aks install-cli # AKSの認証情報取得 az aks get-credentials -g $RG_NAME -n $AKS_NAME
作成したAKSクラスターにWASM用のノードプールを追加します。
# サブスクリプションでプレビュー機能を有効化する az feature register --namespace "Microsoft.ContainerService" --name "WasmNodePoolPreview" # 数分待ってから以下を実行し、StateがRegisteredになったことを確認する az feature list -o table --query "[?contains(name, 'Microsoft.ContainerService/WasmNodePoolPreview')].{Name:name,State:properties.state}" # リソースプロバイダーの更新を行う az provider register --namespace Microsoft.ContainerService # Azure CLIの拡張機能を追加する az extension add --name aks-preview # 過去に拡張機能を追加済みの場合は以下コマンドで更新する az extension update --name aks-preview # AKSクラスターにWASM用ノードプールを追加する az aks nodepool add -g $RG_NAME --cluster-name $AKS_NAME \ --node-count 1 --name mywasipool \ --workload-runtime WasmWasi
WASMアプリケーションの作成
AKS上で動かすWASMアプリケーションを準備していきます。
まずはSpinをインストールします。インストールスクリプトが公開されているのでそれを利用します。
# インストールスクリプトの実行 curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash # カレントディレクトリに置かれた spin バイナリを /usr/local/bin 配下に移動 sudo mv ./spin /usr/local/bin/spin
Spinではアプリケーション作成のためのテンプレートが準備されています。これを利用しましょう。
# テンプレートのインストール spin templates install --git https://github.com/fermyon/spin
Spinはイベントドリブンなアプリケーションを作るためのフレームワークです。
プログラム言語はRustとGo、イベントトリガーとしてHTTPとRedisに対応しています。
今回はGo言語/HTTPトリガーのテンプレートを使用します。
# hello-world ディレクトリにhttp-go テンプレートを使って新規作成する spin new http-go hello-world --accept-defaults cd hello-world
Goのビルド環境を準備してテンプレートをそのままビルドしてみます。
# GoとTinyGoのインストール curl -sL https://go.dev/dl/go1.17.9.linux-amd64.tar.gz | sudo tar -xzf - -C /usr/local curl -sL https://github.com/tinygo-org/tinygo/releases/download/v0.22.0/tinygo_0.22.0_amd64.deb -o tinygo_amd64.deb \ && sudo dpkg -i tinygo_amd64.deb && rm tinygo_amd64.deb # ビルド tinygo build -wasm-abi=generic -target=wasi -no-debug -o main.wasm main.go
ビルドが完了したら以下のコマンドで起動してみましょう。
spin up
3000番ポートでListenする形で起動します。リクエストを投げてみると以下のように Hello Fermyon!
というレスポンスが返ってきます。
curl -v http://127.0.0.1:3000
* Trying 127.0.0.1:3000... * Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0) > GET / HTTP/1.1 > Host: 127.0.0.1:3000 > User-Agent: curl/7.74.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < content-type: text/plain < content-length: 15 < date: Wed, 21 Dec 2022 08:15:45 GMT < Hello Fermyon! * Connection #0 to host 127.0.0.1 left intact
OCIイメージの作成
AKS上で起動するためには、WASMをイメージ化する必要があります。
以下のような Dockerfile を準備します。
FROM --platform=${BUILDPLATFORM} tinygo/tinygo:0.22.0 AS build WORKDIR /opt/build COPY . . RUN tinygo build -wasm-abi=generic -target=wasi -no-debug -o main.wasm main.go FROM scratch COPY --from=build /opt/build/main.wasm . COPY --from=build /opt/build/spin.toml .
通常のDockerはWASMイメージのビルドには対応していません。
そこで今回は img というツールを使用してビルドしました。
# img に必要なパッケージのインストール sudo apt install uidmap libseccomp-dev # imgのインストール export IMG_SHA256="cc9bf08794353ef57b400d32cd1065765253166b0a09fba360d927cfbd158088" sudo curl -fSL "https://github.com/genuinetools/img/releases/download/v0.5.11/img-linux-amd64" -o "/usr/local/bin/img" \ && echo "${IMG_SHA256} /usr/local/bin/img" | sha256sum -c - \ && sudo chmod a+x "/usr/local/bin/img" # ビルドしたwasmファイルを削除 rm main.wasm # イメージのビルド img build --platform=wasi/wasm -t ${ACR_NAME}.azurecr.io/spin-hello-world:0.0.1 . # ACRにPush az acr login -n $ACR_NAME --expose-token --output tsv --query accessToken | \ img login ${ACR_NAME}.azurecr.io --username 00000000-0000-0000-0000-000000000000 --password-stdin img push ${ACR_NAME}.azurecr.io/spin-hello-world:0.0.1
ビルドしたイメージはwasmファイルとspinの設定を記したtomlファイルしか含んでいないため、わずか100KBちょっとでとっても軽量です。
img ls
NAME SIZE CREATED AT UPDATED AT DIGEST acrwasmsample.azurecr.io/spin-hello-world:0.0.1 109KiB 16 minutes ago 16 minutes ago sha256:…
AKS上でWASMを起動する
ビルドしたイメージをAKS上で起動してみましょう。
WASMを利用する場合、RuntimeClass
というCRDの定義が必要です。Spinの場合マニフェストは以下のようになります。
apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: "wasmtime-spin-v1" handler: "spin" scheduling: nodeSelector: "kubernetes.azure.com/wasmtime-spin-v1": "true"
kubectl apply -f runtimeclass.yaml
Deployment/Serviceのマニフェストは以下のとおりです。
ビルドしたWASMをローカルで稼働させた際のポート番号は3000番でしたが、Containerd Wasm ShimsのSpin部分のソースを見ると80番ポート決め打ちでListenするようです。
apiVersion: apps/v1 kind: Deployment metadata: name: spin-hello-world spec: replicas: 1 selector: matchLabels: app: spin-hello-world template: metadata: labels: app: spin-hello-world spec: runtimeClassName: wasmtime-spin-v1 containers: - name: spin-hello-world image: acrwasmsample.azurecr.io/spin-hello-world:0.0.1 command: ["/"] --- apiVersion: v1 kind: Service metadata: name: spin-hello-world spec: type: LoadBalancer ports: - protocol: TCP port: 80 targetPort: 80 selector: app: spin-hello-world
これをAKSクラスターにデプロイすると…
kubectl apply -f spin-hello-world.yaml
WASM用ノードの上でPodが起動します。
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES spin-hello-world-974cf8789-blz4n 1/1 Running 0 72s 10.244.1.5 aks-mywasipool-33908649-vmss000000 <none> <none>
ServiceのIPアドレスを確認し、
kubectl get svc spin-hello-world
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE spin-hello-world LoadBalancer 10.0.139.244 203.0.113.0 80:30514/TCP 2m28s
リクエストを投げると、ビルドしたWASMからレスポンスが返ってくることが確認できます。
curl http://203.0.113.0
Hello Fermyon!
おわりに
AKS上でWASMのサンプルアプリケーションを起動させてみました。
開発環境のエコシステムを考えると業務アプリケーションがすぐすぐWASMに変わることはないと思いますが、サイドカーのような形でAKS上で従来のコンテナとWASMを一緒に動かすという未来は近いかもしれませんね。
私達ACS事業部はAzure・AKSを活用した内製化のご支援をしております。ご相談等ありましたらぜひご連絡ください。
また、一緒に働いていただける仲間も募集中です!
切磋琢磨しながらスキルを向上できる、エンジニアには良い環境だと思います。ご興味を持っていただけたら嬉しく思います。