普段から C# で Functions をがっつり使ってる私ですが、たまには Python での入門ネタでも整理しようかと思った今日この頃です。
今回は、Python で HTTP リクエストを受けてレスポンスを返す Azure Functions を作ります。簡易な Web API ですね。デバッグ実行からデプロイして動作確認するところをやっていきます。
環境は Windows 10 と VS Code を使っていきます。WSL2 の Ubuntu 上での実行ではなく、素の Windows 上で python を動かす環境という点だけ注意してください。素の Windows 環境と WSL2 / Ubuntu で動作させるときとの違いはツールのインストール方法が異なるくらいだとは思いますが....どうでしょうね。。。
Azure Functions とは
Azure Functions または Function App と言い表していることが多いです。
(日本語に翻訳されて関数アプリとか関数って表現は微妙やなと思っています。)
Azure の Serverless なサービスで、HTTP リクエストをトリガーにしたり Azure の他サービスのイベントをトリガーに動かすことができるバックエンドのサービスです。
似たようなサービスは、AWS の Lambda や GCP のCloud Functions です。
サーバーレスなので、従量課金で使えます。めちゃ安い。検証程度だとほぼ無料で使える従量課金だと、どのサービスでもそうですが当たり前にコールドスタートします。もちろんコールドスタートをしないようにプランを上げるとか工夫するとかの手段はあります。
このブログ書いてる時点では C#、Java、JavaScript、Python、PowerShell での実装ができます。C# が SDK が充実していて使いやすいってのはありますが、JS や Python の対応の勢いを感じる昨今です。
公式ドキュメントの概要はこちら。
Azure Functions の概要 | Microsoft Docs
細かいことはさておきまずは動かしたいので、今回は HTTP Trigger での Function App を作ってみましょう。
開発環境の準備
Node.js
npm のパッケージを使うので必要です。Node の環境なんてないって方向けに、先日私が node の環境を構築したメモが偶然にもあります。
Azure Functions Core Tools
Function App を作ったりデバッグしたりするのに使う開発の中心となるツールです。npm からインストールしましょう。現時点では v3 がデフォルトです。コマンドプロンプトかなにかで以下のコマンドを実行してインストールします。
npm install -g azure-functions-core-tools@3
Azure Functions の VS Code Extension
Azure Functions をデプロイをするのに使います。VS Code の左側のメニュー: Extensions > 「azure functions」と入力すると Microsoft が提供している Azure Functions が出てきます。インストールしましょう。
Azure Storage Emulator
Azure Functions の起動には Azure Storage が必要です。ローカルでデバッグする際は Azure Storage のエミュレーターを使います。
Azure を使った開発をしている人はだいたい入ってるはずですがインストール済みか不明って方は Windows のメニューで「Azure Storage Emulator」と入力してインストールされているか見てみましょう。なければ以下のドキュメントを参考にインストールします。さらに起動についてもドキュメントに書いてあるので忘れず起動しましょう。
開発とテストに Azure Storage Emulator を使用する | Microsoft Docs
Python 環境
Azure Functions Core Tools では、Python の versionは 3.8 を用意しておくと問題ないです。本題じゃないのでここでは書きませんが VS Code で Python が動かすための設定をしてない場合はしておきましょう。
この後からがようやく本題です。
HttpTrigger の Function App をつくる
VS Code の GUI で操作して作る方法と CLI で作る方法があります。GUI がめちゃいいってわけでもないので CLIでやります。
コマンドプロンプトや PowerShell を使っても問題ないですが、せっかくなので VS Code を立ち上げて Ctrl
+ Shift
+ @
キーを押すとターミナルが起動しますので、そこでやりましょうか。ターミナルを立ち上げたら自分の作業用のフォルダに移動しておきましょう。
プロジェクトの Initialize
以下のコマンドを打って HelloFunctionAppProj
という名前のプロジェクトを作ってみます。これで Function App のベース部分だけできます。
func init HelloFunctionAppProj --python
VS Code の Explorer で、今作成した HelloFunctionAppProj
フォルダをルートとして開き直したほうが後々面倒がないので、以下のコマンドを打ちます。
code HelloFunctionAppProj -r
仮想環境の Activate
今開いているはずの HelloFunctionAppProj
のフォルダに対して venv を activate します。
私の今の環境だと以下のように python
ってコマンドでやりますが、環境次第では py
だったりすると思います。ご自身の環境のコマンドで activate すれば大丈夫です。
python -m venv .venv
そして、
.venv\scripts\activate
これで activate できます。
HTTP trigger の function 作成
プロジェクトに HelloHttp って名前の HTTP trigger の function を追加します。以下のコマンドうちます。
func new --name HelloHttp --template "HTTP trigger"
これで以下のフォルダ構成になります。プロジェクトフォルダの直下は functions を構成するファイルがあり、HelloHttp ってフォルダの下に function があります。
プロジェクトの構成
Function App を作るうえで最初に知っておきたいことを2つ紹介します。
functions.json
Function App はデフォルトで __int__.py の main メソッドが呼ばれる構成になっています。こーゆー Function の構成は function.json で定義されています。以下のリンクは function.json のエントリーポイントの変更方法のリンクですが、このリンクのドキュメント全体を見ることで基本的な開発方法の情報を得ることができます。
host.json
host.json は Azure のホスト側の設定を構成するためのものです。ログレベルもここで変更できます。詳細はこちらのドキュメントに記載があります。あとで Azure 上でログを見るのに logLevel を Information
以上で出力するように変えておきます。
(デフォルトで生成されたやつに logLevel の部分を追加しただけです)
{ "version": "2.0", "logging": { "logLevel": { "default": "Information" }, "applicationInsights": { "samplingSettings": { "isEnabled": true, "excludedTypes": "Request" } } }, "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[1.*, 2.0.0)" } }
デバッグ実行
__int__.py を開くと、どんなコードがテンプレートとして用意されているかわかります。HTTP リクエスト受け取ったら適当にレスポンス返してますね。ではデバッグしてこのコードを動かします。このコマンドを実行しましょう。
func start
エラーで動かないときは対処方法を後述してます。
これで、Terminal のメッセージの最後にローカルデバッグ中の Function への URL が表示されます。
__int__.py を見ると GET で name を受け取ったら読んでくれるようなので、上記の URL にクエリパラメーターを付けて、POSTMAN のような REST の Client かブラウザーで URL をたたくと無事に動いていることがわかります。
http://localhost:7071/api/HelloHttp?name=beachside
[:400]
エラーで動かない? Could not find a Python version と表示されたときは...
デバッグ実行して「Could not find a Python version」というエラーが表示されることあるかもしれません。
原因として考えられる一つは Python 自体が認識されていない場合。python --version
とコマンドを打って Python が認識されていることを確認します。
もう一つは .vnev を構成できてないとき。前述したとおりに .venv を構成しましょう。
Azure へのデプロイ
無事にデバッグで動作を確認出来たら Azure にデプロイしてみます。
Azure 上に Function App のインスタンスを作る
Function App のインスタンスの作成は、CLI でもできます (つまり自動化もできる) が初めての方だとわかりにくいと思い、一番わかりやすいと個人的に感じている Azure ポータルからやります。
Azure ポータルから作成する手順は以下のドキュメントの通りにやれば問題ないのでここでは書きません。
初めての方向けの情報として補足しておきたい点は、
- リソースグループ: 超雑に説明するとプロジェクトの管理単位でフォルダみたいなものです。リソースグループを削除することでその中も一括で削除できたりしますので、とりあえずの検証で使うようなときは後で一括で削除する際の単位だと思ってもよいです。
- リージョン: インスタンスを作るデータセンターの選択です。検証するだけなら「日本にいるから日本に」とか気にする必要ありません。私はほぼ West US 2 に作ります。同じサービスでもリージョンで料金が安かったりしますし(料金はあまり気にしないですが)、Preview 中のサービスとか日本の東西リージョンはリリースされないものもあるので。場合によりますがレイテンシーも気にするほどのものはありません。
他のポイントとして今回は Python の3.8 の Function App を作りたいので以下を選択します。
- 発行:
コード
- ランタイムスタック:
Python
- バージョン:
3.8
余談ですが、Application Insights の設定も途中で出てきます。ここではさほど気にしなくてよいですが、Azure Monitor というサービス群の中の1サービスです。この Azure Monitor がログをリアルタイムに見たりアプリだけでなく Azure のインフラ側のログまでいい感じに収集したり、検索できたり異常発生時に通知を容易にしてくれる機能です。超便利で有用なので「そんな便利機能がある」程度に覚えておきましょう。
作成したらデプロイのプロセスが表示されますので、おわるまでしばし待ちます(1-2分くらいかなと)。
リソースグループを確認
作成が終わったら、リソースを見てみましょう。
Function App のリソースが開きます。まだデプロイしてないので何もないですがとりあえずブラウザはこのままにして VS Code に戻ります。
デプロイと動作確認
VS Code からデプロイ
プロダクションレベルのコードは、GitHub Action や Azure DevOps の CI/CD ツールを使ってデプロイを自動化するのが常識ではありますが、お試しレベルであればサクッと VS Code からデプロイしましょう。
VS Code の左側のメニューで Azure tools のアイコンをクリックします。
サインインしてないとこんな画面がでるので、サインインします。
FUNCTIONS を展開すると、先ほど作成した Azure の サブスクリプションの配下に Functions のリソースの名前が出てきます。不明の場合は前述で開いてた Azure ポータルの Function App のリソースを見ると、サブスクリプションや function App の名前が確認できます。対象の Function App を右クリックして Deploy to Function App... をクリックします。これだけでデプロイできます。
ビルド・デプロイを考慮した開発とその先の検討
ここでは軽いコードのビルド・デプロイなので詳しく触れてませんでしたが、ガチな運用を考えると検討すべき点があります。
ビルドをリモート(つまりFunction App 上)で行う方法とローカルでビルドする方法があります。
remote build だとローカル環境に依存せずビルドできますが、pip のインストールサイズが大きくなったりするとエラーになることがあります。じゃぁ local build して解決しようって浅はかに思いそうですが、ローカルが Windows でビルド、動く環境は Azure Functions (Linux) で大丈夫かって問題が見えてきます。もう面倒になって Docker にするという手段もあります。Docker 楽そうだねってのはありますが docker image の管理も必要になります。リリースまでにひと手間かかる。あれ?CI/CD するなら結局 Linux で build できるからやっぱ image の管理が強いられる docker いらないよねって話になったり。こんな面倒な問題がない ONNX + C# でよくね、推論するだけならコード量はたかが知れてるしとかも出てくるでしょう。
メリットデメリットそれぞれ持っててケースバイケースなので、ガチでプロダクトを作るなら状況に合わせて最適なものを検討する必要があります。
Windows/Linux 環境差異の問題は WSL2 上で開発すれば解決するのかなぁと思っていますのでそのうち検証しようかなと。
個人的には実運用で Function App にわざわざ実行速度の遅い Python を使うとゆー選択をしてないんですよねー素直に C# で書くので。
まぁ入門編ではこんなこと気にせずに心のど真ん中において置き、次に進みます。
Azure ポータルで動作確認
Azure ポータルの Function App のリソースに戻りましょう。
ポータルで迷子になったら、左側のハブメニューでリソースグループ をクリック > 作成したリソースグループをクリックして Function App のアイコンのリソースをクリックしましょう。
関数 をクリックすると先ほどデプロイした HelloHttp の Function App が見えます。クリックしましょう。
コードとテスト の中に関数の URL 取得 をクリックすると、この Function App にアクセスする URL が取得できます。
(今更ポータルを日本語にした...)
これで、先ほどデバッグ時に試したのと同様にクエリパラメーターをつけて送信すると、動作することが確認できます。
全く触れませんでしたが、functions.json を見ると authLevel
が function
になってます。これはアクセスするのにキーが必要というアクセスレベルなので、取得した URL には Function App が生成したキーがついています。name のクエリパラメーターは、URL の最後に &name=beachside
とかな感じで付けます。
アクセスレベルについてはこちらのドキュメントに記載があります。
Application Insights でリアルタイムにログを見る
Azure ポータルで先ほど作成したリソースグループを見ると、Application Insights のリソースがありますのでクリックしましょう。
Live Metrics をクリックするとライブでログが見れます。Azure Functions が Sleep していると以下の画面のように「使用できません...」と表示されますが気にしなくて大丈夫です。
Function App を実行してみると以下のように動き出します (何度か実行して反応がなければ Live Metrics をもう一度クリックすると反応します) 。
これで、リアルタイムにログを見えます。また、メニュー: Live Metrics の下にある 検索 は数分遅れでログが入ってきて検索することができます。さらに下の方にあるログってメニューでより高度な検索や分析ができます。
おわりに
超入門的な位置づけとして HTTP Trigger での Function App をざっくり試しました。
Azure Functions の良さは、サーバーレスなので負荷が増えてもオートスケールしてくれるとかもありますが、ほかの Azure のサービスと連動してイベントドリブンで起動する便利な仕組み (Queue やファイルのアップロード・変更を検知して起動するとか) が用意されている点もあります。
Python だと ML やデータサイエンスでの用途だとデータの変更を検知して何か処理するとかをするのも容易なので、レガシーな日次バッチでの処理から、データ変更のイベントを検知して処理が動くアーキテクチャーへ進化を遂げるのに役立ちます。