Azure Functions を利用した BLOB トリガーの実装例
Azure Functions について相談を受ける場面が出てきたので、自分の復習も兼ねて簡単なサンプル例も含めながら簡単にまとめておきたいと思います。
Azure Functions について
Azure Functions は一般的には “FaaS (Function as a Service)” として知られる Azure のサービスの1つになります。
類似の例でいうと AWS Lambda や、Google Cloud Run Functions (旧 Cloud Functions) などの同列のサービスになります。
用途としては “なにか” とトリガーに特定の処理を実行させる場合や、スケジュールでの定期実行、API の実装 などなど、比較的シンプルなコードベースの関数をマネージドな環境で実行できるというイメージで良いと思います。
Azure Functions のプランについて
正確な情報については、下記の公式サイトを参照してください。
プラン選択のポイントとしては、下記のような点が挙げられると思います。
- Linux / Windows 、コード または コンテナ
- コードの実行時間 (従量課金) 、コールドスタート または ウォームアップ済みか。
- vNET統合 や プライベートエンドポイント を用いるか否か
初手は "従量課金プラン" を選ぶ方が多いと思いますが、vNET統合/プライベートエンドポイントによる内部での実行や、処理内容に応じてプラン変更を要する場合もあると思うので、ポイントを抑えつつ選ぶのが良いと思います。
サポートしている言語
記事時点では下記表が掲載されていました。 .NET9 までのサポートで主要な言語と、意外なところでは PowerShell などもサポートしているようです。
言語 | ランタイムスタック | Linux | Windows | ポータルでの編集 |
---|---|---|---|---|
C# (分離ワーカー モデル) | .NET | ✓ | ✓ | |
C# (インプロセス モデル) | .NET | ✓ | ✓ | |
C# スクリプト | .NET | ✓ | ✓ | ✓ |
JavaScript | Node.js | ✓ | ✓ | ✓ |
Python | Python | ✓ | x | ✓ |
Java | Java | ✓ | ✓ | |
PowerShell | PowerShell Core | ✓ | ✓ | ✓ |
TypeScript | Node.js | ✓ | ✓ | |
Go/Rust/その他 | カスタム ハンドラー | ✓ | ✓ |
やりたいこと
- ゴールは Blob ストレージのアップロードを起点に、Azure Functions を実行させたい。
- ローカルの開発環境を整えて、ローカル環境で開発・テストをしてから Azure Functions にデプロイしたい。
- KeyVault などを用いて安全に Azure Functions に情報を渡すところまで実装したい。
ローカルの開発環境を整える
Azure Functions および 今回目的としている BLOB = Azure Storage にはローカルで開発をするためのツールが用意されています。 みんな大好き(?) Visual Studio Code を利用する事で、ローカルで動くコードの検証を行う事ができます。
主に利用するのは、Visual Studio Code の拡張機能も含めて6つあります。
- Visual Studio Code
- Python の拡張機能
- Azure Functions の拡張機能
- Azure Functions Core Tools
- Azure Storage Explorer
- Azurite (Azure Storage エミュレータ)
- 以前は別に "Azure Storage Emulator" がありましたが、今は非推奨になっています。
Visual Studio Code のインストール
- 割愛します。ネット上で探せばいくらでも情報があると思うのでそちらを見てください。
https://code.visualstudio.com/ - Visual Studio Code のインストール後、拡張機能として "Python" "Azure Functions" を導入します。
(他の拡張機能についても Zenn / Qiita で沢山おすすめされていると思うので入れましょう)
ローカルでの開発環境については、下記の公式ドキュメントも参照してください。
Azure Storage Explorer のインストール
端的に言うと Azure Storage に GUI でアクセスするためのツールです。
下記からダウンロードしてインストールします。
Azure Function Core Tools のインストール
下記公式ドキュメントにあるリンクからダウンロードできるのでインストールしましょう。
ドキュメントに注釈されていますが、Visual Studio Code でのデバッグは 64bit版 が必要です。
Azurite のインストール
次に Azurite エミュレータ をインストールします。
これは Azure Storage をエミュレートしてくれるもので Azure Blob、Queue Storage、Table Storage をローカルで試す事ができます。
インストール方法は公式ドキュメントに幾つか掲載されていますが、今回は Visual Studio Code の拡張機能でインストールしています。 これは Visual Studio Code のコマンドパレットから操作する形になるので、もしコマンドラインで実行・操作したいという方はドキュメントを見てください。
コマンドパレットから見た状態
コードの実装とテスト
Azure Function Core Tools を用いて、Functions のコードを準備する。
- 公式の手順だと VSCode のコマンドパレットを開いてプロジェクトの作成~となっているが、下図の通りアイコンからでも作成できるので、まずはプロジェクトを作成する。
- 基本的にウィザードに従うだけだが、今回は Python と、最初の関数テンプレートには Blob trigger を選択
- 最後に Azure アカウントへのサインインを求められるで対応した (複数テナント/サブスクを利用している場合は一度キャンセルし、サブスクを選択しなおしてからやると良い)
正常に作成されると、下図のように関数テンプレートが展開される。これを元に Azure Functions のコードを実装していく。
展開されたコードについて
本記事を書いている時点では、以下のフォルダとコード類が展開されました。
このうちメインとなるのは function_app.py, host.json, requirements.txt の3つになります。
ファイル/フォルダ | 内容 |
---|---|
.venv | Python Virtualenv の設定、詳細は触れません |
.vscode | プロジェクトフォルダの VScode の設定、詳細は触れません |
.funcignore | Azure 上にアップロードしないファイル群の指定するファイル |
.gitignore | GitHub 等にアップロードしないファイル群の指定するファイル |
function_app.py | Azure Functions のメインコード |
host.json | ラインタイムの動作、ログ、Functions の拡張機能設定ファイル |
local.settings.json | ローカルで実行する際の設定ファイル |
requirements.txt | Python で利用する追加モジュールを記載する設定ファイル |
function_app.py
最初に展開されている function_app.py が下記コードですが、これ自体は BLOB にアクセスがあったものを記録するだけのものなのであっさり動かす事が出来ます。
import azure.functions as func
import logging
app = func.FunctionApp()
@app.blob_trigger(arg_name="myblob", path="mycontainer",
connection="d23ce5_STORAGE")
def blob_trigger(myblob: func.InputStream):
logging.info(f"Python blob trigger function processed blob"
f"Name: {myblob.name}"
f"Blob Size: {myblob.length} bytes")
local.settings.json (要編集)
まず local.settings.json の "AzureWebJobsStorage" の値に "UseDevelopmentStorage=true" を入力します。 ローカルの Azurite に対して操作する際のストレージのアクセスキーに相当します。
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "python",
"d23ce5_STORAGE": "UseDevelopmentStorage=true"
}
}
Azurite の起動
次に Azurite を起動します。
- Visual Studio Code で [CTRL]+[SHIFT]+[P] でコマンドレットを表示し Azurite で検索します。
- 検索した中にある "Azurite: Start" を選択するとサービスが起動します。
起動後は Visual Studio Code のステータスバーでも把握できます。
Azure Storage Explorer の起動とコンテナの作成
起動した Azurite の環境に Azure Storage Explorer で接続します。 最初は function_app.py で指定している "mycontainer" というコンテナが存在していないので手動で作成します。
動作テスト
Visual Studio Code に戻ります。 実際にコードを実行してトリガーが動作するか試してみます。
[CTRL]+[@] で TERMINAL を開き func host start
と実行します (VS Code の拡張機能の「デバッグボタン」からでも実行できます)
これで Azure Functions として "待ち" の状態になっているので Azure Storage Explorer から先程作成した "mycontainer" にファイルをアップロードしてみましょう。
正しく動作すれば、アップロードをトリガーにした処理が実行され TERMINAL 上でメッセージを確認する事ができます。
ここまでが Azure Functions をローカルで実行するための基礎になります。
ローカル開発とデバッグの Tips
ハマりやすいポイント
接続文字列の設定
ローカル実行時は local.settings.json で Azure Functions が利用する接続文字列(例えば、AzureWebJobsStorage やカスタムキー)を正しく設定しませう。 特に、Azurite を利用する場合は "UseDevelopmentStorage=true" と設定する必要があり、スペルミスや空文字になっていると、関数の起動や Blob トリガー時にエラーになるので気をつけましょう。
ポートの競合
Azurite や Azure Functions Core Tools がデフォルトで使用するポート(Blob: 10000、Queue: 10001、Table: 10002 等)が他のプロセスと競合すると、接続エラーが発生する場合があるのでローカルで実行しているものに注意しませう。
ローカルでは再現できない機能
Premium プラン固有の機能
ローカル環境は、あくまでもコード中心の確認になりま。 Premium プランで提供されるプリウォーム済みインスタンスや、より高度なスケーリング機能は当然再現できないので、Premium プラン固有の機能のテストは、実際に Azure 上にデプロイして確認する必要があります。
VNet 統合などのネットワーク機能
当然ですがローカル開発環境では、仮想ネットワーク (VNet) 統合やプライベートエンドポイントなど、クラウド環境特有のネットワーク構成をシミュレーションすることは難しいです。こうした機能に依存するシナリオは、最終的に Azure 環境でのテストを行い、動作を確認する必要があります。
本番環境(Azure)へのデプロイ
リソースの作成
以下3つのリソースを Azure Portal 上で作成します。
- Azure Functions
- Azure Storage
- Azure KeyVault
Azure Functions の作成
Visual Studio Code の Azure Functions の拡張機能からでも作成できると思いますが、一応 Azure Portal 上で先にリソースとしては作成しておきます。
- Azure Portal から 関数アプリ を選択し、従量課金でリソースを作成
- ランタイムスタックは Python を選択
Azure Storage の作成
次にトリガーとするための Azure Storage を作成します。
任意の名称でストレージアカウントと、BLOBコンテナを作成して大丈夫ですが、あとでコードを編集する際に必要になるので覚えておきましょう。
またこちらも次の項目である KeyVault で利用するため、作成したストレージアカウントの接続文字列をメモしておきます。
Azure KeyVault の作成
Azure KeyVault リソースを作成します。
- Azure Portal -> キーコンテナー -> キーコンテナーの作成 を選択します。
- リソース名は任意で、アクセス許可モデルは RBAC (推奨) のままで作成します。
- リソース作成後 "アクセス制御 (IAM)" から "キーコンテナー管理者" の役割を付与します。
"3" までの工程を終えると "シークレット" 等の作成が行えるようになるのでシークレットとして、前段で作成していた Azure Storage の接続文字列を登録します。
作成後は各シークレットの "シークレット識別子" をメモしておきます。
Azure Functions のマネージドID作成
Azure Functions から KeyVault を参照する際に マネージドID を用いて KeyVault からシークレットを取得します。 そのため Azure Functions でマネージドIDを有効にします。
上記の "オブジェクト (プリンシパル) ID" を用いて KeyVault の読み取りを行うので KeyVault に戻り、ロールの割当から "キーコンテナー シークレットユーザー" のロールを割り当てる。
Azure Functions の環境変数設定
ローカルで実行していた際は "local.settings.json" に基づいてローカルの Azurite に書き込みをしていたが、Azure 上では Azure Functions の環境変数から KeyVault の接続文字列を取得し、Azure Storage にアクセスする形になる。 その情報を渡すために Azure Functions に環境変数を設定する。
今回は Visual Studio Code で作成されていた変数が "d23ce5_STORAGE" だったのでこの名称で環境変数を作成します (変数名はコードに合わせたら良いので適宜お好みで変更しませう)
また作成する環境変数の値下記のようになります。
@Microsoft.KeyVault(SecretUri=<KeyVaultのシークレット識別子>
環境変数を追加したので、このタイミングで Azure Functions のリソースを再起動しておきましょう。 正しく反映・認識されると下図のようになります。
コードのデプロイ
ここまでで Azure 側のリソースを準備できたので Visual Studio Code からコードをデプロイします。 Visual Studo Code の Azure Functions 拡張機能 にある雲のマークを選択します。
するとサブスクリプションの選択や、デプロイ先の Functions リソース名を聞かれるので選択すればデプロイできます。
正常にデプロイが完了すると、下図のように Azure Portal 上からデプロイされたコードを見る事ができます。
動作テスト
Azure Storage で作成していた BLOBコンテナ "mycontainer" にファイルをアップロードしましょう。 正しくトリガーが発動していれば、Azure Functions から選択できる関数の詳細で動作している事が確認できます。
ここまでの一連の流れが Azure Functions の基本となるので、あとはローカルで目的のコードを作成しつつ、適宜テスト・デバッグを実施していく事になります。
ログとデバッグについて
Application Insights は、Azure Functions と連携して各種ログやメトリックを収集できるサービスで、トレースログや例外情報の収集、関数が実行されるたびに、ログや例外情報がリアルタイムで可視化されます。
ローカルでの開発・テスト段階では、Visual Studio Code のターミナルやデバッグコンソールでログを確認し、本番環境にデプロイした後は Application Insights で本格的なモニタリングを行う形になります。 詳細は公式ドキュメントを見てください。
参考情報・備忘メモ
vNet 統合を利用するケースやプライベートリンク
企業のセキュリティ要件によっては、Azure Functions を仮想ネットワーク (VNet) に統合し、プライベートリンク経由でリソースにアクセスするケースがあります。この場合、追加の設定やネットワーク構成が必要になるため、公式ドキュメント を確認のうえ、適切に設計を行ってください。
またその際はプランとして Premium にする必要があるなど、料金面での影響もあるので、事前に料金計算ツールなどでも予測しておく事をおすすめします。
公式ドキュメント (ベストプラクティス・FAQ など)
Microsoft の公式ドキュメントには、Azure Functions のベストプラクティスや、よくある質問への回答が充実しています。運用中に疑問点やトラブルが発生した際は、まずは公式ドキュメントを参照してみると、解決の糸口が見つかると思います。
Discussion