はじめに
こんにちは、ACS事業部の吉川です。
本記事はQiitaのAzure Advent Calendar 2022の14日目の記事です。
Azure Container Appsには KEDA という仕組みが統合されています
KEDAはKubernetesのPodをイベントドリブンでスケールさせる仕組みです。
これを利用すると、Pod数を普段は0台にして課金を抑え、必要な時だけ起動して処理を実行し、完了したらまた0台に戻す…といった使い方ができます。
今回Azureのメッセージングサービスである Service Bus のキューをトリガーにしたスケーリング方法を解説します。
構成イメージ
以下の構成を例に挙げて説明します。
クライアントはService Busのキューに対してメッセージを追加していきます。
Container AppsのKEDAはそのキューを監視してメッセージの有無・メッセージの量を確認します。
キュー内にメッセージがあればKEDAがPodをスケールアウトさせます。0台の状態から1台起動することもできますし、キュー内のメッセージが多くて処理が滞る場合にはPod数を更に増やしていって処理能力を増大させることも可能です。
起動したPodはキューからメッセージを取り出して処理していきます。すべてのメッセージの処理が終わりキューが空になったらKEDAがPodをスケールインさせます。
このように キューの長さに合わせて処理するPodの数を増減してくれる というのがポイントです。
環境作成
実際にAzure上に環境を作ってみましょう。
Service Busのキューからメッセージを取り出すPythonスクリプトを準備しました。
import os from azure.servicebus import ServiceBusClient, ServiceBusMessage CONNECTION_STR = os.environ["CONNECTION_STRING"] QUEUE_NAME = os.environ["QUEUE_NAME"] servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR, logging_enable=True) with servicebus_client: receiver = servicebus_client.get_queue_receiver(queue_name=QUEUE_NAME) with receiver: for msg in receiver: print("Received: " + str(msg)) receiver.complete_message(msg)
取り出したメッセージの内容を Received:
という文字列と共に標準出力に表示するだけのシンプルなものです。
これをコンテナイメージとしてビルドして、Azure Container RegistryにPushしておきます。
FROM python WORKDIR /usr/src/app RUN pip install azure-servicebus COPY app.py . ENTRYPOINT ["python"] CMD ["app.py"]
ACR_NAME=acrsample docker build -t ${ACR_NAME}.azurecr.io/servicebus-receiver:latest . docker push ${ACR_NAME}.azurecr.io/servicebus-receiver:latest
Service BusとContainer Appsも作成していきます。
# リソース名などの定義 RG_NAME=rg-sample SB_NAME=sb-sample QUEUE_NAME=sbq-sample LOCATION=japaneast CAE_NAME=cae-sample ACA_NAME=aca-sample # リソースグループ作成 az group create --location $LOCATION --name $RG_NAME # Service Bus名前空間作成 az servicebus namespace create -n $SB_NAME -g $RG_NAME -l $LOCATION --sku Basic # Service Busキュー作成 az servicebus queue create -n $QUEUE_NAME -g $RG_NAME --namespace-name $SB_NAME # Service Busの接続文字列を取得 CONNECTION_STRING=$(az servicebus namespace authorization-rule keys list \ --name RootManageSharedAccessKey -g $RG_NAME --namespace-name $SB_NAME \ --query primaryConnectionString --output tsv) # Container Apps環境作成 az containerapp env create -n $CAE_NAME -g $RG_NAME -l $LOCATION # Container Apps作成 az containerapp create -n $ACA_NAME -g $RG_NAME \ --image ${ACR_NAME}.azurecr.io/servicebus-receiver:latest \ --system-assigned \ --registry-server ${ACR_NAME}.azurecr.io \ --registry-identity system \ --environment $CAE_NAME \ --min-replicas 0 --max-replicas 10 \ --secrets connection-string=$CONNECTION_STRING \ --env-vars CONNECTION_STRING=secretref:connection-string QUEUE_NAME=$QUEUE_NAME PYTHONUNBUFFERED=1 \ --scale-rule-name servicebus-queue \ --scale-rule-type azure-servicebus \ --scale-rule-metadata connectionFromEnv=CONNECTION_STRING queueName=$QUEUE_NAME
Container Appsの作成オプションが複雑なのでちょっと解説。
--image ${ACR_NAME}.azurecr.io/servicebus-receiver:latest \ --system-assigned \ --registry-server ${ACR_NAME}.azurecr.io \ --registry-identity system \
コンテナイメージの指定を行うオプションです。
--registry-server
でACRのURLを指定して --registry-identity system
を付けることで、ACRからマネージドIDで認証してイメージをPullできるようになります。
--secrets connection-string=$CONNECTION_STRING \
シークレットとしてService Busの接続文字列を登録しています。
--env-vars CONNECTION_STRING=secretref:connection-string QUEUE_NAME=$QUEUE_NAME PYTHONUNBUFFERED=1 \
Podに渡す環境変数の設定です。CONNECTION_STRING
の値はシークレットの値を参照するように設定しています。
--min-replicas 0 --max-replicas 10 \ --scale-rule-name servicebus-queue \ --scale-rule-type azure-servicebus \ --scale-rule-metadata connectionFromEnv=CONNECTION_STRING queueName=$QUEUE_NAME
ここがKEDAの設定パラメーターです。
最小・最大のレプリカ数とKEDAの type
、metadata
を設定しています。
--scale-rule-name
はContainer Appsの設定に付ける任意の名前なので、好きな値を入れればOKです。
type
、metadata
に何を指定すればよいのかはKEDAのドキュメントを確認します。Azure Service Bus用のドキュメントは以下にあります。
ドキュメント上ではYAML形式で記載されていますが、それぞれの値を上記のコマンドのように設定すればよいです。
typeには azure-servicebus
を指定し、metadataとしてconnectionFromEnv
(Service Busの接続文字列を格納した環境変数) とqueueName
(スケールのトリガーとするService Bus内のキュー) を設定しています。
ポータルからKEDAの設定を行う場合は以下のように記述していきます。
ポータルからの設定では、
- HTTPトリガー(リクエスト数に応じてスケールする)
- Azureキュー(Service Busでなくストレージアカウントのキューストレージを利用する)
以外のトリガーを使う場合、種類
欄を カスタム
に設定するのがポイントです。
スケーリングの動作確認
環境ができあがったら早速動作確認してみましょう。
Service Busのキューにメッセージを登録するPythonスクリプトを準備しました。
import os import sys from azure.servicebus import ServiceBusClient, ServiceBusMessage CONNECTION_STR = os.environ["CONNECTION_STRING"] QUEUE_NAME = os.environ["QUEUE_NAME"] args = sys.argv count = int(args[1]) servicebus_client = ServiceBusClient.from_connection_string(conn_str=CONNECTION_STR, logging_enable=True) with servicebus_client: sender = servicebus_client.get_queue_sender(queue_name=QUEUE_NAME) batch_message = sender.create_message_batch() for _ in range(count): batch_message.add_message(ServiceBusMessage("Sample Message!!!")) sender.send_messages(batch_message) print(f"Sent a batch of {count} messages")
これを手元の環境から実行してメッセージを登録します。
まずは1件登録してみましょう。
python sender.py 1
Container Appsの Replica Count
メトリックを見てみると…
キューに登録したタイミングでレプリカ数が0⇒1にスケールアウトされていることが確認できました。
次にもっと大量のメッセージを登録してみましょう。1000件ほど登録してみます。
python sender.py 1000
最大レプリカ数に設定した10までスケールアウトされていることが確認できます。
そして、しばらく放置してキューにメッセージが無い状態が続くと…
10⇒0にスケールインしたことが確認できます。
おわりに
Azure Container AppsのKEDAによるスケーリングの動作について解説しました。
Container Appsは起動時間に応じた課金体系で、利用していないときに0台にスケールインすることでコストを抑えることができます。
「使った分だけお金を払う」というクラウドのメリットを享受するためにも、ぜひ積極的に活用していきましょう!
私達ACS事業部はAzure・AKSを活用した内製化のご支援をしております。ご相談等ありましたらぜひご連絡ください。
また、一緒に働いていただける仲間も募集中です!
切磋琢磨しながらスキルを向上できる、エンジニアには良い環境だと思います。ご興味を持っていただけたら嬉しく思います。