かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Visual Studio Code のリモート開発がどれくらいけるのか試すために Azure Functions を Kubernetes クラスター (AKS) にデプロイしてみた

Visual Studio Code の Insider 版じゃなくてもリモート開発(リモート開発拡張機能自体はまだプレビューです)出来るようになったので何か試してみたいと思います。

私は Windows がメインで Linux(Ubuntu) の仮想マシンを Azure 上に立てて、そこに SSH で接続するような感じで設定しています。Windows でやるよりも Linux でやったほうが捗る系のものとしてはコンテナ系のものがあるかなぁと思ったので、今回は Kubernetes のクラスターに Azure Functions をデプロイするというのをしてみたいと思います。

書きながらやってるので、最終的にうまくいきませんでしたという落ちが待ってる可能性もあります。 チュートリアルはこちら。

github.com

Azure Functions の開発環境を整える

Ubuntu に VS Code で繋いでターミナルで以下のページを参考に従って Azure Functions Core Tools と .NET Core 2.x SDK を入れます。

Azure Functions Core Tools の操作 | Microsoft Docs

Azure CLI を入れる

下の手順で入れました。

docs.microsoft.com

az login でログインしておきます。

kubectl を入れる

コマンドでぽちっと

az aks install-cli

Docker を入れる

Ubuntu に docker を入れておきます。

docs.docker.com

こんなコマンドで

$ sudo apt-get update
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$  sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

関数の作成

適当なフォルダーで --docker オプションをつけて関数を作りましょう

func init . --docker

チュートリアルでは node を選ぶように書いてあるのですが、私は dotnet で作りました。 そして、QueueTrigger の関数を作ります。

生成された関数の QueueTrigger のキューの名前を dotnet-queue-items にして Connection は消します。

using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;

namespace AzureFunctionKubernatesHelloWorld
{
    public static class SampleFunction
    {
        [FunctionName("SampleFunction")]
        public static void Run([QueueTrigger("dotnet-queue-items")]string myQueueItem, ILogger log)
        {
            log.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
        }
    }
}

次はクラウドシェルか Azure CLI でストレージとか作ります。Visual Studio Code のコマンドパレットからクラウドシェル開けますね。便利。

f:id:okazuki:20190607125359p:plain

とりあえず、こんな感じでうってみました。

az group create -l japaneast -n hello-keda
az storage account create --sku Standard_LRS --location japaneast -g hello-keda -n kaotahellokedastorage(ここは各自変える)
CONNECTION_STRING=$(az storage account show-connection-string --name kaotahellokedastorage(ここは各自変える) --query connectionString)
az storage queue create -n dotnet-queue-items --connection-string $CONNECTION_STRING

こんなコマンドで接続文字列を取得して、local.settings.json に書き足します。

az storage account show-connection-string --name kaotahellokedastorage(ここは各自変える) --query connectionString

local.settings.json に AzureWebJobsStorage を追加します。以下のような感じで

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "ここにさっき取得した接続文字列",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet"
    }
}

F5 を押してデバッグ実行をします。先ほどリソースを作成したクラウドシェルで以下のコマンドを打ってキューにメッセージを追加してみましょう。

$ echo 'Hello world from Azure' | base64
SGVsbG8gd29ybGQgZnJvbSBBenVyZQo=
$ az storage message put --account-name kaotahellokedastorage -q dotnet-queue-items --content SGVsbG8gd29ybGQgZnJvbSBBenVyZQo=

そうすると、トリガーが動いて以下のような出力があるはずです。

[6/7/19 4:21:22 AM] Executing 'SampleFunction' (Reason='New queue message detected on 'dotnet-queue-items'.', Id=7947ab10-9840-4b13-a605-0b40856d3a78)
[6/7/19 4:21:22 AM] Trigger Details: MessageId: d3a381d6-a19b-438d-9110-b0e66a4aba56, DequeueCount: 1, InsertionTime: 6/7/19 4:21:21 AM +00:00
[6/7/19 4:21:22 AM] C# Queue trigger function processed: Hello world from Azure
[6/7/19 4:21:22 AM] 
[6/7/19 4:21:22 AM] Executed 'SampleFunction' (Succeeded, Id=7947ab10-9840-4b13-a605-0b40856d3a78)

デプロイ先の作成

Azure Kubernetes Service を作ります。 名前を適当に入れてリージョンをストレージに合わせて東日本にします。

f:id:okazuki:20190607132619p:plain

あとはそのまま作成。あと、作成した Docker イメージ格納するために Azure Container Registry も作りましょう。そうしよう。

f:id:okazuki:20190607132930p:plain

デプロイしてみよう

作った AKS に繋ぐ情報をゲットします。

az aks get-credentials --resource-group hello-keda --name kaota-kuber

動いてるか確認してみましょう。

$ kubectl get nodes
NAME                       STATUS   ROLES   AGE     VERSION
aks-agentpool-26255978-0   Ready    agent   9m36s   v1.12.8
aks-agentpool-26255978-1   Ready    agent   9m49s   v1.12.8
aks-agentpool-26255978-2   Ready    agent   9m55s   v1.12.8

ノード数 3 で作成したのでいい感じっぽいです。

keda 入れます。

func kubernetes install --namespace keda

このコマンド実行するとうまくいってるかわかるみたい。

$ kubectl get customresourcedefinition
NAME                        CREATED AT
scaledobjects.keda.k8s.io   2019-06-07T04:44:05Z

語弊力が下がってきてるのは、そろそろ何してるのかわからなくなってきたからです。KEDA は調べてみると

japan.zdnet.com

MicrosoftはRed Hatと共同で、オープンソースの「Kubernetes Event-driven Autoscaling」(KEDA)サービスを開発した。
同社の関係者によると、開発者はKEDAを使い、パブリッククラウドやプライベートクラウド、そしてオンプレミスで、
Kubernetes上にサーバーレスでコンテナーをデプロイできる。
KEDAは、Microsoftの「Azure Kubernetes Service」(AKS)、そしてRed Hatの「OpenShift」でも動作する。

あと、AKS から ACR にアクセスできるように設定しておきます。

docs.microsoft.com

上記ページに従って以下のようなシェルスクリプトを走らせました。

#!/bin/bash

AKS_RESOURCE_GROUP=hello-keda
AKS_CLUSTER_NAME=kaota-kuber
ACR_RESOURCE_GROUP=hello-keda
ACR_NAME=kaota

# Get the id of the service principal configured for AKS
CLIENT_ID=$(az aks show --resource-group $AKS_RESOURCE_GROUP --name $AKS_CLUSTER_NAME --query "servicePrincipalProfile.clientId" --output tsv)

# Get the ACR registry resource id
ACR_ID=$(az acr show --name $ACR_NAME --resource-group $ACR_RESOURCE_GROUP --query "id" --output tsv)

# Create role assignment
az role assignment create --assignee $CLIENT_ID --role acrpull --scope $ACR_ID

ACR へのログインもローカルでしておきます。私は kaota という名前で ACR を作ったので以下のようなコマンドで。

sudo az acr login --name kaota

ここまで出来たら以下のような感じでデプロイ!

$ sudo func kubernetes deploy --name hello-keda --registry kaota.azurecr.io
Running 'docker build -t kaota.azurecr.io/hello-keda /home/okazuki/repos/AzureFunctionKubernatesHelloWorld'......................................................................................................................................................................................................................................................done
Running 'docker push kaota.azurecr.io/hello-keda'..................done
secret/hello-keda created
deployment.apps/hello-keda created
scaledobject.keda.k8s.io/hello-keda created

なんか乗ってる…

$ kubectl get deploy
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-keda   0         0         0            0           42s

ローカル実行のときにやったように以下のコマンドで Queue にメッセージを投げ込みます。

$ az storage message put --account-name kaotahellokedastorage -q dotnet-queue-items --content SGVsbG8gd29ybGQgZnJvbSBBenVyZQo=

暫く待ってると以下のように動いてる素振りを見せます。

$ kubectl get deploy
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-keda   1         1         1            1           3m31s
$ kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
hello-keda-6c84bcdd8-hdg5w   1/1     Running   0          110s

標準出力を表示してみると、ちゃんと動いてるっぽいです。

$ kubectl logs hello-keda-6c84bcdd8-hdg5w
info: Host.Startup[0]
# ...省略...
info: Function.SampleFunction[0]
      Executing 'SampleFunction' (Reason='New queue message detected on 'dotnet-queue-items'.', Id=2089247e-add1-400a-bd74-691283a3bc64)
info: Function.SampleFunction[0]
      Trigger Details: MessageId: 0c54a208-a849-4ea1-a78c-15c617ef81cd, DequeueCount: 1, InsertionTime: 06/07/2019 05:15:42 +00:00
info: Function.SampleFunction.User[0]
      C# Queue trigger function processed: Hello world from Azure
# ...省略...

まとめ

はじめて Kubernetes 触ったけど動いてよかった。docker やらなんやらの環境構築が凄く簡単だったので Linux 系 OS も便利だと思った(使い込んでいくとまた違う感想を持つかもしれませんが)