はじめに
サーバーレスコンピューティングの代表格、FaaS(Function as a Service)をAzureでやってみたときのメモです。
Azureには"Azure Functions"(関数アプリ)という関数をデプロイするための機能があります。
AWSだと"AWS Lambda"に対応する機能です。
とりあえずローカルで作った何かしらの関数をデプロイするやり方を忘れないようにと思って書き残しておきます。
(やり方はほかにもいくつかあります)
用意するもの
- Visual Studio Code
- Azure functions拡張機能
- Azure Account拡張機能
- python拡張機能
- Azure subscription
pythonは3.7.3で作ってます。AzureはMicrosoftのサービスなので(??)、VScodeを使って作ります。
※Azure Functionsの拡張機能はまだプレビュー版みたいです(2020/3/26現在)。以後仕様が変わるかもしれません。
手順
作るのは「年/月/日を入力したら曜日を返す関数」です。
デスクトップに"sample functions"という材料を入れておく用の空のフォルダを作って、その中で作業していきます。
①前作業:azure-functions-core-toolsをインストール
Azure Functions Core Toolsはローカルでターミナルやコマンドプロンプトから関数の開発・テストを行うためのモジュールらしいです。とりあえず最初に入れておきます。
VScodeのターミナルを開いてコマンド打つだけです。
npm install -g azure-functions-core-tools
②関数を作る
続いてターミナルで
func init
と打ちます。
「使用する言語を選んでください」的な画面が出てくるので、'python'を選択します。
すると、フォルダの中にいくつかファイルが生成されます。
これらはデプロイに必要なファイルです。追加のライブラリが必要であればrequirements.txt
に追加したりします。
続いて、ターミナルで
func new
と打ちます。
そうすると、「使うテンプレートを選んでください」的な画面が出てきます。
今回はクエリを投げたら何かの値を返してくれる関数を作りたいので、Http trigger
を選択します。
「関数の名前を教えて」と言われるので、今回は"WhatDayOfWeek"としておきます。
"sample function"フォルダの中に"WhatDayOfWeek"という名前のフォルダが作られ、中にテンプレートが入っています。
この__init__.py
がクラウド側で行う処理を記述したものです。
テンプレートでは、HTTPリクエストで文字列を投げたら、『Hello 【入力した名前】!』と返ってくる関数になっています。
loggingはログを扱うためのpythonの標準モジュールです。requirements.txt
に書いてませんが使えます。(逆に下手に追加するとデプロイできなくなりました。)
加工するのはこの__init__.py
だけでOKです。
import logging
import azure.functions as func
#うるう年かどうかだけを判定する関数
def LeapOrNot(Y):
if (Y % 4 != 0):
return False
elif (Y % 100 != 0):
return True
elif (Y % 400 != 0):
return False
else:
return True
#閏年の回数判定 基準は1970年1月1日木曜日
def HowManyLeap(Y):
mul4 = Y // 4 - 492 #492 = 1970 // 4
mul100 = Y // 100 - 19 # 19 = 1970 // 100
mul400 = Y // 400 - 4 # 4 = 1970 // 400
return mul4 - mul100 + mul400
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
days = ['Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue', 'Wed']
day_num = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
Year = req.params.get('Year')
Month = req.params.get('Month')
Date = req.params.get('Date')
if not (Year and Month and Date):
try:
req_body = req.get_json()
except ValueError:
pass
else:
Year = req_body.get('Year')
Month = req_body.get('Month')
Date = req_body.get('Date')
Y = int(Year)
M = int(Month)
D = int(Date)
#edit validation
if Y < 1970:
return func.HttpResponse('1970年以前には対応していません',status_code=400)
elif M > 12:
return func.HttpResponse('日付が間違っています',status_code=400)
elif LeapOrNot(Y):
if M == 2:
if day_num[M-1] + 1 < D:
return func.HttpResponse('日付が間違っています',status_code=400)
elif day_num[M-1] < D:
return func.HttpResponse('日付が間違っています',status_code=400)
else:
if day_num[M-1] < D:
return func.HttpResponse('日付が間違っています',status_code=400)
#経過日数を計算
passed_num = (Y - 1970) * 365 + sum(day_num[:M-1]) + D - 1
if LeapOrNot(Y) and M > 2:
leap_num = HowManyLeap(Y)
elif LeapOrNot(Y):
leap_num = HowManyLeap(Y-1)
else:
leap_num = HowManyLeap(Y)
return func.HttpResponse('{}'.format(days[(passed_num + leap_num) % 7]))
これで関数自体はできました。
"sample function"フォルダ内でfunc new
を打てば、また別の関数を作ることもできます。
(③)ローカルでテスト
ちゃんと期待した動作ができているかテストしたい場合は
func start
とやれば、フォルダ内のすべての関数に対して
WhatDayOfWeek: [GET,POST] http://localhost:7071/api/WhatDayOfWeek
といったようなURLが得られます。
これを使えば、
http://localhost:7071/api/WhatDayOfWeek?Year=2020&Month=3&Day=26
とパラメータを投げてThu
と返ってくるといったテストが行えます。
④クラウドにデプロイ
ローカルで関数を完成させたらデプロイです。
Azure系の拡張機能を入れると、VScodeのアクティビティバーからAzure系の機能を使えるようになります。サイドバーに"FUNCTIONS"が出てくるので、そこから"Local Project"->"Functions"でローカルで作られた関数が表示されるはずです。
ここで赤枠で示した部分からデプロイできます。(Azureアカウントにloginしてなければここでログインが必要です。)
このボタンだけで、"Local Project"内に入っている関数がまとめてデプロイできます。
ここからはAzure上でのデプロイ作業をVScodeから操作します。
(Azure portalでリソースを一通り作っておけば元々あるAzure Functionsのリソースにそのままデプロイするだけなのですぐです。)
一から作っていきます。
<1> +Create new Function App in Azure (Advanced)
新しい関数アプリを作るかどうか聞かれます。ログインしているサブスクリプションで作った関数アプリが表示されるので、あらかじめ作っておけば、ここでそれを選ぶだけです。
"Advanced"と書いてない方もありますが、そちらの方が設定事項が少ないです。
<2> 関数アプリの名前を入力
Azure上で作る関数アプリの名前を聞かれるので、入力します。ここでは"samplefunctions"としておきます。
この名前は'globally unique'でなければいけないらしいですが、この名前で作れるということはあまり利用者がいない説??
<3> 言語選択
関数アプリで使う言語を選択します。node.jsやjavaなどが選択できますが、ここではpythonにします。ローカルで作ったときにも聞かれたのにここでも聞かれるの?とは思う
<4> 課金プラン選択
"Select a hosting plan"と出てきます。これは課金プランのことで、Azureの公式ドキュメントに詳しく書いてあります。
ざっくり言うと、
- 関数の実行ごとに課金(従量課金,「Consumption」)
- 立てたインスタンスごとに課金(「Premium」)
- ほかのwebサービスと同一の課金制度にする(「App Service Plan」)
の3択です。
従量課金が一番FaaSっぽい?という所感。今回はConsumptionにしておきます。
<5> リソースグループを選択
関数アプリが所属するリソースグループを選びます。新しく作ると、おそらく作るリージョンとか聞かれるかと思いますが、ここでは元々あるものを使います。
<6> ストレージアカウントを選択
データを入れるストレージです。これも元々あるやつを使います。
<7> Application Insightsを選択
Application Insightsは関数の監視モニター的なものです。ログやパフォーマンス状況が見れるみたいです。(公式ドキュメント)
元々他のApp Serviceで作ってあれば、それを選択して統合することもできるみたいです。
これはSkipできるので、とりあえず関数を作りたいだけならいらないかもしれないです。
ここまでやると、デプロイが開始されます。
デプロイ中のログはVScodeの"出力"から見ることもできます。
⑤作った関数を使ってみる
"Deployment to ~~ completed"と出ればデプロイ終了です。
この時点でAzure portalから関数のページを見ることもできます。
この画面で"URL"をクリックすれば、「あなたの関数は動いてますよ!」的な画面が出てくるはずです。
関数のURLは、VScodeの方から、【サブスクリプション名】->【作った関数名】->"Functions"->【関数名】を右クリックから、"Copy Function Url"で取得できます。
ローカルで適当にpythonコードを作って実験してみます。
import requests
url = "【取得したURL】"
param = {'Year':2020,'Month':3,'Date':26}
res = requests.get(url, params = param)
print(res.text)
☟結果
Thu
さいごに
AzureでFaaSを使う際、すべてCLIでやるやり方もあるらしいです。
自分も結構理解はあやふやです。公式ドキュメントを見ながら試行錯誤してましたが苦労しました。
「とりあえず関数作ってデプロイ」がやりたいだけならこんなもんかな、と思います。