Azure FunctionsをVS2017でローカル実行&デバッグしてパブリッシュする
MSDNブログ(↓↓↓)で Azure Functions 関連の記事を見たので自分でやってみました。
上記ブログに記述されている事、そして今回自分で試した事を要約すると以下の内容です。
- Azure FunctionsをVisual Studio 2017で開発&デバッグする(つまりローカル実行するということ)
- Azure Functionsをクラスライブラリとしてビルド&パブリッシュする
1 は、まあ 開発効率を上げるということですね。
Azure Functions自体はAzureポータルでコーディングできますが、本格的実装はローカルで行いたいですよね。
2 は、クラスライブラリとしてアセンブリ(dll)にしてデプロイすることで実行パフォーマンスを上げる意味を持ちます。
Azure Functionsは5分間非アクティブであるとアイドル状態となり、次の実行時には再度メモリ上に展開されます。C# / JavaScriptコードがデプロイされている場合、アセンブリへのコンパイル作業から再実行され起動パフォーマンスが落ちてしまいます。
では、以下に手順を・・・
ちなみに、Visual Studioとの統合ツール「Visual Studio Tools for Azure Functions」がまだ 2017 対応できていないらしく、そのため以下のような手動による操作がいくつか発生します。でも、あと数週間もすればツールがリリースされるみたいです。
Azure Functions CLI のインストール
Azure Functions CLI をインストールします。
以下のnpmコマンドでグローバル領域にインストールします。
npm i -g azure-functions-cli
Visual Studio 2017 でWebプロジェクトを作成
Visual Studio 2017を起動します。
メニュー「ファイル → 新規作成 → プロジェクト」を選択します。
プロジェクトテンプレートは「Web → ASP.NET Web アプリケーション(.NET Framework)」、プロジェクト名はここでは「AzureFunctionsWeb」としました。
「空」テンプレートを選択します。
プロジェクトのプロパティを表示します(ソリューションエクスプローラからプロジェクトをマウス右ボタンクリックメニューで「プロパティ」を選択)。
Webタブを選択し、以下の設定を行います。
* 「外部プログラムを起動する」を選択。
* パスは「C:\Users\「【ユーザー名】\AppData\Roaming\npm\node_modules\azure-functions-cli\bin\func.exe」とする。
* 「コマンドライン引数」は「host start」とする。
* 「作業ディレクトリ」は【プロジェクトフォルダ】とする。
設定を行った画面は以下の通り。
Azure Portal上で Azure Functions を作成
(Visual Studio Tools for Azure Functionsがリリースされれば、VSからプロジェクトを生成できると思いますが、それが今はないのでポータルで作成して、ローカルVSにベースとなるソースを落としてきます)
Azure Functions 作成画面を表示
https://functions.azure.com/signinをブラウザで開きます。
「New function app」の「Name」に作成するファンクション名を入力します。ここでは「RyuichiFunction0916」としました。
「Region」は「Japan East」としました。
「Create + get started」をクリックします。
「WebHook + API」「C#」を選択し、「この関数を作成する」ボタンをクリックします。
作成完了。
Azure Functions ソースのダウンロード
左下の「Function App の設定」をクリックします。
「Kuduに移動」をクリックします。
「site」を選択します。
「wwwroot」のダウンロードアイコンをクリックします。
ダウンロードしたzipのイメージは以下の通り。
WebプロジェクトにFunctionsソースを追加
先程作成したWebプロジェクト(AzureFunctionsWeb)フォルダにzipの内容を解凍します。
追加のファイルをプロジェクトに含めます。
また「run.csx」ファイルを「run.cs」にリネームします。
run.csを以下のように修正します。
run.csxでは単純に run() だけが定義されていますが、csコードにする為「名前空間・クラス」でくくります。
また必要な using を追加します。
レスポンス文字列も若干修正を加えました。
// run.cs using Microsoft.Azure.WebJobs.Host; using System.Linq; using System.Net; using System.Net.Http; using System.Threading.Tasks; namespace AzureFunctionsWeb { public class ExampleFunction { public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { log.Info("C# HTTP trigger function processed a request."); // parse query parameter string name = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0) .Value; // Get request body dynamic data = await req.Content.ReadAsAsync<object>(); // Set name to query string or body data name = name ?? data?.name; return name == null ? req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body") : req.CreateResponse(HttpStatusCode.OK, "Hello " + name + ". I'm assembly!!"); } } }
プロジェクトにNugetパッケージを追加
Nugetで以下のパッケージを追加します。
function.jsonの調整
function.jsonに「scriptFile」「entryPoint」キーを追加します。
scriptFileにはアセンブリ名を、entryPointには名前空間/クラス付きのRun()メソッドの完全名を記述します。
// function.json { "scriptFile": "..\\bin\\AzureFunctionsWeb.dll", "entryPoint": "AzureFunctionsWeb.ExampleFunction.Run", "disabled": false, "bindings": [ { "authLevel": "function", "name": "req", "type": "httpTrigger", "direction": "in" }, { "name": "$return", "type": "http", "direction": "out" } ] }
ローカル実行
Visual StudioでF5クリックにより実行を行います。
以下のようなコマンドプロンプトが表示され Function がリクエスト待ち(実行待ち)状態となります。
コマンドプロンプト表示上に、以下の記述を確認することができます。
Job host started Http Function HttpTriggerCSharp1: http://localhost:7071/api/HttpTriggerCSharp1
このURLがFunctionの受け口のURLになります。
サンプル(ExampleFunction)は「name」というキーをパラメータとして受け取ります。その為、以下のURLをブラウザでアクセスしてみましょう。
http://localhost:7071/api/HttpTriggerCSharp1?name=daigo
Functionが実行され以下のようなレスポンスが得られます。
ブレークポイントもきちんと止まります。
Azure FunctionsへのPublish
次に、ローカルで実装を行った Function を AzureにPublishします。
コマンドプロンプトを起動します。
作成したWebプロジェクトフォルダ(F:\Projects\Research\AzureFunctionsWeb\AzureFunctionsWeb)に移動します。
以下のコマンドを実行してCLIからAzureにログインします。
func azure login
Azureへのログイン画面が表示されるので、ログインを行います。
以下のコマンドで、現在PublishされているFunctionの一覧を確認します。
func azure functionapp list
現在の私の環境では2つのFunctionがPublishされていました。
RyuichiFunction0916の方が、今回作成したものです。
以下のコマンドによりFunctionをローカルからAzureへPublishします。
(RyuichiFunction0916部分は適時 Function 名に置き換えます)
func azure functionapp publish RyuichiFunction0916
正常にPublishされた結果画面が以下になります。
Azure Functionsを実行
Azureポータルで「RyuichiFunction0916」を表示。
「開発」タブを選択、「テスト」タブを選択、「要求本文」をテスト文字列に修正、「実行ボタン」クリック、を行います。
以下のように「出力」に「"Hello Daigo. I’m assembly!!“」が表示されました。
VS2017上で実装したロジックが実行されていることが確認できます。
まとめ
VS2017用「Visual Studio Tools for Azure Functions」がリリースされれば、上記のようなゴニョゴニョした作業はバックエンドで自動化されると思います。ただ、CLIなんかで、裏の動きを知っておくのは良いことだと思っています。
また、Azure functionsやマイクロサービスについては、私自身はまだ実運用の場面では使ったことがないので、色々な知見を経験者の方から学びたいと思っております。
WebHookを絡めてGithubだったりSlackだったりと連携する実装なんかも比較的容易に出来るようなので、色々試してみたいと思います。