APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

FaaSとしてのAzure Container Apps

はじめに

こんにちは、ACS事業部の吉川です。
AzureのFaaS(Function as a Service)といえば皆様ご存知 Functions ですね。
このFunctions、利用シーンによっては不便なポイントがあると常日頃感じており、本記事でその打開に向けたアプローチとしての Azure Container Apps の活用法をご紹介します。

ここがつらいよFunctions

Azure Functionsのホスティングには以下の種類があります。

  • 従量課金プラン
  • Premium プラン
  • 専用プラン(App Serviceプラン)
  • ASE
  • Kubernetes

小規模に利用し始めるときは 従量課金プラン を選ぶケースが多いでしょう。名前のとおり使った分だけ料金が請求されるプランで、いわゆるサーバーレスとしてわかりやすい料金体系かと思います。
ところがこの従量課金プランは使う上で大きな制約があり、仮想ネットワークへの接続ができません
Functions の処理結果をデータベースやストレージに格納する際には、仮想ネットワークを介したプライベート接続を行いたいのが人情というもの。仮想ネットワーク接続を行うためにはPremiumプラン以上を選択する必要がありますが、Premiumプランですと最低でも1インスタンスは稼働していないといけないので、使用量が少ないシーンでは高くつく場合もあるでしょう。専用プラン・ASEも同様に最低料金が比較的高額となります。
最後の選択肢Kubernetesは、KEDAを利用してKubernetesクラスター上でFunctionsコンテナーを動かすというものです。
KEDAを備えたKubernetesサービスといえば…そう、Azure Container Apps ですね。
Azure Container Appsを利用して、従量課金かつ仮想ネットワーク接続可能なFunctions を作ってみましょう!

Functions on Kubernetes

FunctionsをKubernets上で動かすという内容は、本ブログでも過去にご紹介しています。

techblog.ap-com.co.jp

上記の記事ではAzure Kubernetes Service(AKS)にKEDAを導入し、その上でFunctionsコンテナーを起動するというものでした。
上記記事ではHTTPトリガーでの例を紹介していますが、本記事ではService Busトリガーを例に挙げて紹介します。
なお、Kubernetes上でのFunctionsデプロイにおいて、KEDAが対応しているトリガーは以下のとおりです。

  • Azure Storage キュー
  • Azure Service Bus
  • Azure Event/IoT Hubs
  • Apache Kafka
  • RabbitMQ キュー

通常のFunctionsの全てのトリガーに対応しているわけではないので、使いどころが限定されるという点に注意しましょう。

Azure Container AppsでKEDAを利用したService Busキューのスケーリングについて、先日以下の記事を書きました。

techblog.ap-com.co.jp

本記事で紹介するFunctionsと前回の記事の内容で何が違うのか?端的に言えば「コードをFunctions流に書くか否か」の違いです。
既存のFunctionsを移行する場合、またはFunctionsの開発に習熟しているといった場合には、本記事で紹介するようにFunctionsをホストするパターンを利用するのがいいでしょう。バインディングを利用してリソースへの接続についての処理を簡略化するなど、Functionsでのメリットを生かすことができます。
あまりFunctionsに習熟していない、またはFunctions固有のコードの書き方に依存したくない場合は、前回記事で紹介したようなコードの書き方になります。
どちらがいいかはそれぞれお好みかなと…。Azureにどっぷり染まるなら前者ですし、他のクラウドへの可搬性を考えるなら後者がよいのではと考えます。

構成

以下の構成をベースに考えてみました。前回記事 の構成をちょっと拡張したものです。

Service Busのキュー数に応じてスケールするFunctionsを、仮想ネットワーク内のAzure Container Apps上にデプロイします。FunctionsはService Busキューからデータを取り出し、同じ仮想ネットワーク内のPostgreSQLに保存します。せっかくAzure Container Appsを使うので、DBとの接続にはDaprを使ってみましょう。

Functionsアプリ作成

Functionsアプリを作成する際にはAzure Functions Core Toolsを使用します。
以下コマンドでテンプレートを生成しましょう。せっかくなので新しいV2プログラミングモデルで作ります。

func init --docker --python -m V2

生成された function_app.py を編集します。

import logging
import os
import azure.functions as func
import requests

app = func.FunctionApp()

dapr_port = os.getenv("DAPR_HTTP_PORT", 3500)
state_store_name = "postgres"
dapr_url = "http://localhost:{}/v1.0/state/{}".format(dapr_port, state_store_name)

@app.function_name(name="ServiceBusQueueTrigger1")
@app.service_bus_queue_trigger(arg_name="msg", queue_name="sbq-sample", connection="MyServiceBus")
def test_function(msg: func.ServiceBusMessage):
    servicebus_message_id = msg.message_id    
    servicebus_body = msg.get_body().decode('utf-8')

    payload = [{ "key": servicebus_message_id, "value": servicebus_body }]
    logging.info(payload)
    
    try:
        response = requests.post(dapr_url, json=payload)
        logging.info(response)
    except Exception as e:
        logging.info(e)

Service Busのキューから受け取ったメッセージをDaprのStatestoreに格納するというシンプルなコードです。
Daprサイドカーへのリクエストにrequestsを使うので、requirements.txt にも追記しておきます。

azure-functions
requests

上記の編集が終わったらコンテナイメージをビルドしてAzure Container RegistryにPushします。

ACR_NAME=acr-sample

docker build -t ${ACR_NAME}.azurecr.io/samplefunc:latest .
docker push ${ACR_NAME}.azurecr.io/samplefunc:latest

Functionsアプリ側の準備はこれで完了です。

Azure Container Apps側の設定

Kubernetes上でFunctionsコンテナーを動かす場合、Functions用の環境変数をいくつか設定する必要があります。通常のFunctionsのアプリケーション設定と同様のものです。

設定する値は以下のとおりです。

名前 説明
FUNCTIONS_WORKER_RUNTIME アプリケーションの言語。今回は python を指定する。
AzureWebJobsStorage Functionsの各種情報を保管するストレージアカウントへの接続文字列
AzureWebJobsFeatureFlags Python V2のプログラミングモデルを選択する場合は EnableWorkerIndexing
AzureWebJobsMyServiceBus トリガーとするService Busキューの接続文字列。MyServiceBus という名称はPythonコード内の connection の設定値と一致させる必要がある。

KEDAのスケーリング設定も以下の画像のように設定します。前回記事 と同様の設定です。

あとはContainer Apps環境側でPostgreSQL接続用のDapr設定をこちらのドキュメントを参考にして行います。

※この項の設定、検証用に手抜きで手動エントリを多用してますが、実際に使う際にはシークレットも活用しましょう。

これでService Busキューにデータを登録すると、KEDAによってスケーリングされたFunctionsコンテナがキューからデータを取り出しDBに格納してくれます。

もちろん最小レプリカ数を0にしておけば、キュー内にデータがないときには0スケールで課金を抑えることができます。

おわりに

というわけでAzure Container Apps上でFunctionsを動かせる、という内容でした。

利用できるトリガーの制約などで必ずしも万能ではないですが、Functionsホスト先の一つの選択肢として考えてみてはいかがでしょうか。

私達ACS事業部はAzure・AKSなどのクラウドネイティブ技術を活用した内製化のご支援をしております。ご相談等ありましたらぜひご連絡ください。

www.ap-com.co.jp

また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。

www.ap-com.co.jp

本記事の投稿者: 吉川 俊甫
AKS/ACAをメインにインフラ系のご支援を担当しています。 Shunsuke Yoshikawa - Credly