こんにちわ。今年初投稿です。だいぶおさぼり癖が付いてきましたが、細くなが~~~~く続けていければと思いますので今年もよろしくお願いします。
みなさんAzure Functions、使ってますか?今回はMicrosoftのクラウドサービスの中の1つのサービスである「Azure Functions」を利用してクラウドストレージへファイルを書き込んでみたいと思いま~~~~っす。
Azure Functionsとは・・・
Azure Functionsは、マイクロソフトが提供するAzureクラウドサービスの中の一つです。イベント駆動型のサービスとなっており、簡単に言うと、『あるイベントが発生すると開発したAzure Functionsコードが実行される』という仕組みです。
位置づけとしてはPaaS(Platform as a Service)と言われ、ハードウェアやOSの管理・保守をすべてクラウドベンダーに任せ、開発者はコーディングに注力することができるサービスとなっています。
昨今のマイクロサービス/サーバーレスアーキテクチャーの盛り上がりによりクラウドの世界ではかなり重要な位置づけになってきているのではと思います。
ちなみに、AWSやGCPでも同様のサービスが展開されており、そちらでは「AWS Lambda」や「Google Cloud Functions」と呼ばれています。
今回の概要
上図の通りです。
①ユーザーのHttp要求により、ファイルがAzure Functionsに対して送信される。
②Azure Functionsでは渡されたリクエストボディからファイルを取得する。
③Azure Functionsの出力バインドとしてAzure Blob Storageへ出力する。
といった感じで実装していきます。
Azure Functionsの大きな強みである、トリガー、入力バインド(今回は未使用)、出力バインドを活かしてBLOBストレージへの出力を数行のコードで実現したいと思います。
ちなみに、開発環境として以下で実装していきます。
- IDE:Visual Studio 2019 Community
- 言語:C#ライブラリ
- リクエスト送信ツール:Advanced Rest Client
- Azure Storage関連:Azure Storage Emulator、Azure Storage Explorer
- Azureサブスクリプション:必要 ※Azure上のストレージへ出力する場合
Azure Functionsを利用してBLOBストレージにファイルを出力する
HttpトリガーなAzure Functionsを新規作成&ローカル実行
まずは、新規のAzure Functionsを作成していきます。このAzure FunctionsはHttpトリガーで作成します。すでにHttpトリガーなAzure Functionsがある方は読み飛ばしてください。
①Visual Studioを起動し、「新しいプロジェクトの作成」を選択します。
②「新しいプロジェクトの作成」画面が表示されるので、「Azure Functions」をプロジェクトテンプレートとして選択します。雷マークが目印です。選択後、「次へ」ボタンをクリックします。
③「新しいプロジェクトの構成」画面ではプロジェクト名や配置ディレクトリを指定して、「作成」ボタンを押下します。今回は「HttpTriggerToBlobFunction」というプロジェクト名にしてみました。
④「新しいAzure Functionsアプリケーションの作成」画面が表示されます。ランタイムは最新のもの(現時点でv3)、トリガーは「Http trigger」を選択し、「作成」ボタンを押下します。ストレージアカウント、Authorization levelはひとまず何でもよいので、「なし」、「Function」を選択しておきます。
⑤プロジェクトテンプレートからAzure Functionsコードが生成されました。
⑥実はこれだけでHttpトリガーなAzure Functionsは出来上がっています。実際にデバッグ実行することが出来ますので、F5キーまたは「デバッグ実行」で起動してみます。ファイアウォールのブロックが表示されたら「アクセスを許可」してあげます。Azure Functions Core Toolsのインストール要求があった場合もインストールしてあげます。
以下のコマンドウインドウが表示されるはずです。赤枠で囲ったURLに着目します。このURLがAzure Functionsの起動トリガーとなります。コピーしましょう。
⑦ブラウザーを起動し、コピーしたURLをアドレスバーに貼り付け、最後部に「?name=(適当な名前)」と付け足してEnterキーを押下してみます。
Azure Functionsに送られたリクエストが処理され、レスポンスとしてメッセージが返ってくるのが確認できると思います。
コマンドウィンドウにも実行ログが出力されているのが確認できます。
これでひとまず、ノンコーディングでHttpトリガーなAzure Functionsが完成しました。
Azure BLOBへの出力バインドを追加する。
先ほど作ったHttpトリガーなAzure Functionsを修正して、Azure Blobストレージへファイルを出力してみたいと思います。
①まずは利用する拡張機能を追加します。[ツール]メニューから[NuGetパッケージマネージャー]-[ソリューションのNuGetパッケージの管理]を選択します。以下の画面になるので、「参照」タブから検索欄に「webjobs storage」と入力し検索します。表示候補から「Microsoft.Azure.WebJobs.Extentions.Storage」を選択してプロジェクトにインストールを行います。
②次にメインロジックを開き、以下のコードに書き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace HttpTriggerToBlobFunction { public static class Function1 { [FunctionName("Function1")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, [Blob("myblob",FileAccess.Write)] CloudBlobContainer outputBlob, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); await outputBlob.CreateIfNotExistsAsync(); string fileName = @"MyDir/MyFile.txt"; CloudBlockBlob cloudBlockBlob = outputBlob.GetBlockBlobReference(fileName); using (CloudBlobStream stream = await cloudBlockBlob.OpenWriteAsync()) { req.Body.CopyTo(stream); } return new OkObjectResult($"ファイル出力:{fileName}"); } } } |
③コピペした方はおそらく、ビルドエラーが発生していると思います。「CloudBlobContainerの型または名前空間が見つからない」と。
「考えられる修正内容を表示する」を選択すると、usingで名前空間のインポートとして2つの選択肢があります。「using Microsoft.Azure.Storage.Blob」と「using Microsoft.WindowsAzure.Storage.Blob」の2つです。
正しくは「Microsoft.Azure.Storage.Blob」を選択する必要があります。「Microsoft.WindowsAzure.Storage.Blob」は古いパッケージとなっており、NuGetサイトでも非推奨となっています。ちなみにビルドエラーにもならないため、誤って後者を利用してしまうとこの後の手順で・・・
といったエラーが発生してしまうためその時は、もう一度「Microsoft.Azure.Storage.Blob」がusingされているかご確認ください。
ちなみに自分はこれをしてしまい解決までに1日費やしました・・・orz
Azure Sorage Emulatorを利用したローカル環境での実行
①あとは、実行だけなんですが、その前に確認です。ローカルで実行する場合は、「local.settings.json」のAzureWebJobsStorage値を「UseDevelopmentStorage=true」にしておく必要があります。これを設定することでAzure Storage Emulatorが起動し、Azure上のストレージをローカル環境でエミュレートしてくれます。
1 2 3 4 5 6 7 |
{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "dotnet" } } |
ちなみに、上記設定を失念したまま実行すると、Httpリクエストを食ったときに、
って感じのエラーが発生します。AzureWebJobsStorageに接続文字列が存在しないって言ってますので気づきますかね。
Azure Storage Emulator、開発も滞っているようですのでこれからはAzuriteに切り替えていくのがいいかもしれませんね。Azuriteは自分もまだ利用していませんので、ここではAzure Storage Emulatorで行わせていただきますが、対して違いはないと思います。
②それでは、F5キーを押下してAzure Functionsを実行してみましょう。で、実行してAzure Functionsが待機状態になっていますが、今回は単純にブラウザーからURLをたたくだけではやりたいことは実現できません。「Advanced Rest Client」などのhttpリクエストツールを利用するのが一番簡単かと思います。以下の手順を実施します。(インストールは割愛。Chrome拡張機能版がありますので簡単に利用できると思います。)
Methodに「POST」を選択し、Azure FunctionsのURLを「Request URL」に入力します。
Headersに「content-type」としてアップロードするファイルに合わせたcontent-typeを設定します。
※ちなみにここでcontent-typeを指定しなくても次の手順でファイルを指定するとアップロードするファイルに合わせたcontent-typeが自動的に設定されますので、あまり気にする必要はありません。
次にBodyタブを選択し、「CHOOSE A FILE」をクリックし、送信するファイルを選択します。最後に「SEND」をクリックすればファイルをボディに含んだHttpリクエストがAzure Functionsに送信されます。
③Advanced Rest Clientのレスポンスに以下のようにステータスコード200とAzure Functionsが返したメッセージが正しく表示されたでしょうか?
④正しくファイルが送信されたかどうかは「Azure Storage Explorer」を利用して確認するのが便利です。名前似ててややこしいですがw
Azure Storage Explorerは以下からダウンロードできます。
インストールしたAzure Storage Explorerを起動し、「ローカルで接続済み」-「Storage Account」-「エミュレーター」-「Blob Containers」と辿っていくと、Azure Functions側で実装した、コンテナー名(ここではmyblob)、仮想ディレクトリ名(MyDir)、ファイル名(MyFile.txt)が表示されるはずです。
以上でローカルでのBLOB出力がうまくいきました。
ローカル環境でFunctions実行してAzure上のBLOBにファイルを出力してみる
ローカル環境で動作確認ができましたので、今度は、ローカル環境でAzure Functionsは実行しつつ、ファイルの書き込みはAzure上のBLOBコンテナーに行ってみます。
①Azureポータルへサインインします。要Azureサブスクリプション。ない方は以下から無料プランを作成可能です。
②Azureポータルから、「リソースの作成」を選択し、「ストレージアカウント」を検索なりして、選択します。以下の画面になりますので、各項目を入力・選択し、「次:ネットワーク」をクリックします。
項目 | 設定値 |
---|---|
サブスクリプション | 対象のサブスクリプションを選択します。 |
リソースグループ | ストレージアカウントをデプロイするリソースグループを選択します。 |
ストレージアカウント名 | グローバルで一意なストレージアカウントの名前を設定します。 |
場所 | リージョンを指定します。日本国内なら、東日本、西日本どちらかかと。 |
パフォーマンス | Standardを選択。安くすませます。 |
アカウントの種類 | StorageV2(汎用v2)を選択します。 |
レプリケーション | テストで使うだけですので、ローカル冗長ストレージ(LRS)を選択します。 |
③ネットワーク設定は、デフォルトのまま「次:データ保護」をクリックします。テストですので特にアクセスの制限はしません。
④データ保護設定も特にチェックなしで「次:詳細」をクリックします。
⑤詳細設定画面です。デフォルトでOK。「安全な転送が必須」もデフォで有効になっていますのでこのまま「次:タグ」をクリックします。
⑥タグ設定は特に何も設定しません。「次:確認および作成」をクリックします。
⑦設定内容を確認したら、「作成」をクリックしましょう。
⑧リソースのデプロイが開始されます。完了するまで待ち、完了したら以下のような画面になりますので、「リソースに移動」をクリックします。
⑨作成したストレージアカウントのページに遷移しますので、左にあるブレードから[設定]の「アクセスキー」をクリックします。アクセスキーの画面が表示されますので、「キーの表示」をクリックします。
⑩キーや接続文字列が表示されます。Key1の接続文字列の右端にあるアイコンをクリックして内容をクリップボードにコピーしておきます。キーや接続文字列はこのストレージアカウントに保存されている情報にアクセスするとても重要な値ですので取り扱いには十分注意しましょう。
⑪次にVisual StudioのAzure Functionsに戻ります。BLOBバインドの属性に接続文字列の構成を「Connection = “設定名”」で追加します。今回は「MyStorage」という設定名で追加しました。
1 2 3 4 5 |
public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req, [Blob("myblob",FileAccess.Write, Connection = "MyStorage")] CloudBlobContainer outputBlob, ILogger log) { |
⑫次に、local.settings.jsonに先ほど追加した設定名(MyStorage)と、AzureポータルからコピーしたAzure BLOBコンテナーへの接続文字列を追加します。
1 2 3 4 5 6 7 8 |
{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "dotnet", "MyStorage": "DefaultEndpointsProtocol=https;AccountName=<Your account name here>;AccountKey=<Your account key here>;EndpointSuffix=core.windows.net" } } |
⑬そうしましたら、前回の実行と同様にAzure Functionsを実行し、Advanced Rest Clientから何かファイルをPOSTしてみましょう。レスポンスコード=200が返ってきたら、Azure Storage Explorerを起動し、対象サブスクリプションのBLOBコンテナーを確認してみてください。ファイルがちゃんとアップロードされているが確認できたでしょうか。
さいごに
あとは開発したAzure FunctionsをAzure環境にデプロイして、local.settings.jsonに記述していた接続文字列をAzure Functionsのアプリケーション設定にConnectionで定義した設定名で作成し、値にAzure BLOBの接続文字列をコピペしたり、またはKeyVaultなんか使って接続文字列にアクセスすればローカル環境にこだわらず実行が出来るかと思います。
詳しくは以下のサイトにて。
ちょっと長くなってしまいましたが、今回はこの辺にて。
コメント