ちゃんと書いてなかった気がするのと、某所で喋ったのでスライドの中身を適当にコピペします。そのうち動画・スライドが公開される気もしますが。
※2016年6月4日現在の情報です。
※だらだら長くなってしまった…
Azure Functionsって?
![image image]()
イベント駆動の”機能”実行プラットフォームです。だいたいは何かしらのデータを処理したいというのと、何かしらアクションがあって処理を実行したいという2点が実現したい何かだと思いますが、アクションを受ける部分とかわざわざ作りたくないですよね。もっと処理そのものをサクッと構築して実行したいと思います。
Azure Functionsではそのための機構が提供されてて、スクリプトベースで処理に関する記述だけに注力できます。またアクションを受ける部分、アクションしたい先についてはトリガーとバインディングという機構が提供されててその部分の開発をかなり省くことができるようになっています。
- トリガー:スケジュール、HTTP (Webhook)、キュー、ファイル作成時などを受けて処理を開始できる
- バインディング:ファイル作成やPush通知など連携先を簡単に設定できる
バインディングはかなり強力で、例えばBlobファイルへの読み書きやPush通知の細かい処理などわざわざ書く必要はありません。データの読み書きだけ行えば済むようになっています。
またトリガーとバインディングをうまく設定することでFunctionを(イベントを)連鎖させたり、他のシステムと受け渡ししたりすることができます。(あまりやりすぎるとLogic Appsなどのほうが良いケースになったりしますが)
あとオープンソースです。(後述)
![image image]()
よく言われるのはServerlessという言葉ですが、「OSレイヤー以下を抽象化しサーバーを意識させない」という点でAzure FunctionsはServerless Compute Platformとも言えます。
PaaSとして提供されている他のサービスや概念を拡張して、OSレイヤー以下のスケールとかパッチ、メンテナスなどインフラストラクチャ部分を抽象化して意識する必要がありません。
実はAzure Functionsに似たような機能はWebJobsとしてApp Service Web Apps上で実行できていました。これはこれでバインディングだったりトリガー機構は持っててAzure Functionsの原型ともいえるサービスでしたが、扱うためにはWeb Appsなりをある程度知ってないと構成したり管理するのが難しいところでした。
![image image]()
Azure Functionsでは基本的にAzure Functionsの画面(実際にはAzure Portalの一部ですけど)だけでだいたい完結するので他の余計な部分に煩わせられることなく処理に注力できるようになります。
![image image]()
はじめるには
https://functions.azure.com/signin にアクセスします!
![image image]()
Azure サブスクリプションが複数ある場合は選択して、あとはCreateするだけ!1つ1つのスクリプトはFunction Appという呼び方でまとめたものをFuncions Containerと呼ぶようです。で、既にFunctions Containerがある場合はOpenで開くこともできます。※Azure Portal上からでも作成はできます。
作成後は以下のような画面になります。(実際はAzure Portal内です)
![image image]()
Function Appの作成や設定など基本的にここから行います。Web AppsとかAzureだとかあまり意識せずに触れそうですね(まだまだな点はもちろん多いですけど)
あとはトリガーと言語を選んで作成すればテンプレートに従って作成することができます。もしGitHubなどのリポジトリから取得する場合は右下の「Start from source control」リンクからWeb Appsと同じように連携設定を行うことができます。(後からでも可)
また、他のテンプレートや言語を選択したい場合は左上の「New Function」か「Create your own custom function」リンクを選択します。もう少し詳しいテンプレート一覧が表示されるのでこちらから選びましょう。
![image image]()
現状、選べる言語としては以下の通りとなります。
- メインサポート
- node.js / JavaScript
- C# (.NET Compiler Platform Scripting API) * .cs / .csx
- 実験的なサポート
- F# / Python / PHP / Batch (.bat) / Bash (.sh) / PowerShell (.ps1)
作成すればメインの画面(ブレード)でコードを編集したり、バインディングの設定をしたりすることができるようになります。
![image image]()
左側の一覧に作成されたFunction Appの一覧が表示されます。選択することでそれぞれのコードやバインディングの情報を編集することができます。
- Developタブ
- Integrateタブ
- Monitorタブ
- 実行状況や呼び出しログなどを参照できます。(後述のモニタリング/ログあたりを参照)
- Manageタブ
- 現在の状態(有効/無効)確認と内部的なURL(設定などのJsonが返されるAPI)、削除が行えます。Preview感がすごいですね。
![image image]()
Function App全体(Functions Container)の設定等については右上のリンクから行えます。
![image image]()
- Function app settings
- Function App全体の設定が行えます。(後述)
- Monitoring
- 稼働していたインスタンス数の確認などが行えます。(後述のモニタリング/ログあたりを参照)
- Quickstart
- functions.azure.com から遷移したときに表示されるQuickstart画面を表示します。
開発
実際に処理されるスクリプトを編集する画面です。Developタブで行います。
![image image]()
![image image]()
Codeのテキストエリアで直接コードを編集します。編集が終わったらSaveしましょう。(C#の場合、Saveした後コンパイルが行われます)
コンパイル結果や実行結果はLogsの領域に出力されます。ログの実体は別途保存されているのでこの領域はClearしたりPauseしたりしても問題ありません。
Runのところではトリガーに渡す情報を入力して「Run」ボタンで実際に実行することができます。(入力する内容はトリガーなどによってプレーンテキストだったりJSON形式だったりといろいろです)
また一部トリガーではここからRunしてもエラーになったりうまく実行できないので注意しましょう。(Blobトリガーとか)
HTTPのレスポンスが返ってくる場合など、FunctionによってはOutputテキストエリアに実行後の応答が表示されます。
また一部トリガー(HTTPトリガーなど)を選択している場合は上部にAPI Keyが付いた状態の呼び出し用URLが表示されます。(後述)
基本的にこの画面と次のバインディングなどがメインで操作する箇所になるかと思います。ゴリゴリ書いていきましょう。
バインディングとトリガー
いつ/何によって実行するか(トリガー)と、入出力する他のサービス群をどう紐づけるかはIntegrateタブで行います。
![image image]()
内部的にはトリガーもInputなバインディングの一種です。(タイプがトリガーという感じ)
トリガーは1つ、InputおよびOutputのバインディングは複数指定可能です。またこれらの設定の実体はfunction.jsonファイルとして保存されているので直接編集することも可能です。(右下にあるAdvanced Editorのリンクから編集することもできます)
![image image]()
現時点でサポートしているバインディング・トリガーの種類は以下のようになります。
![image image]()
![image image]()
* HTTPのアウトプットはHTTPトリガー使用時のみ利用可能です。
テンプレートから作成したときはスクリプトに予め記述されていますが、後からバインディングを編集した場合、スクリプト(コード)にバインディングした値を受け取るようなコードを追記する必要があるので注意してください。
C#だと特に型が間違ってたりするとコンパイルエラーになったり、実行時エラーになります。(このあたり細かいドキュメントは後述。まだまだ足らない)
料金
料金プランは2種類あります。基本的に他のAzureのサービスと似てますがプランによって実行される環境のスペックだったりも決まる感じです。
- App Service Plan
- 通常のApp ServiceのPlanを使用する方法です。他のユーザー(テナント)と実行環境を共有しないという点である意味(Functionsにとって)占有プランとも言えます。
- 最大インスタンス数などスペック、機能はApp Serviceと同等になります。
- Azure Portal上で作成するときはClassic といった表記になります。
- Dnyamic Service Plan
- 詳細はこちら
- functions.azure.com から作成すると自動的にこのプランになります。現状選択できるプランの詳細は特にありません(Freeのみ)。また価格表みればわかる通り、まだ未定の状態です。
- App Service Planと異なり、こちらはAzure Functions専用のプランですね。また課金の対象は次の2種類あります。
- Compute: 実行された時間とメモリ領域サイズに応じて課金
- 設定メモリ領域サイズ(GB単位)* 実行時間(100ミリ秒単位)を基に計算
- 実行時間は100ms単位で丸められるようです
- Freeだと40万 GB*Secまで無料(128 MB 設定で約37日間フルで実行可能) ※超えたときの価格は未定
- メモリ領域サイズは 128 MB – 1536 MB の間で設定可能 (64 MB 間隔)
- Executions: 実行された回数に応じて課金
- Freeだと100万回まで無料 ※超えた時の価格は未定
- Freeプランはper アカウント per month なので同じアカウント(サブスクリプションかな?)で複数のAzure Functions コンテナーを作ったとしても共通になります。(アカウント単位で40万GB*Sec / 月まで無料ということかと)
Dynamicだと例えば128MB設定で30秒実行すると 128 MB / 1024GB * 30秒 = 3.75 GB*Sec になります。
価格についてはよく変動するので注意してください。
ここまでがざっくりな概要です。後は(誰得な)詳細とか細かなTipsを羅列していきます。
設定
基本的な設定は「Function app settings」から行います。
![image image]()
- Memory Size (Dynamic Service Plan指定時のみ設定可)
- Function App全体で使用するメモリ領域を指定します。料金に関わるので指定には注意しましょう。
- 128 MB ~ 1536MBの間で64MB刻みで指定できます。
- スクリプトの挙動が不安定だったりする場合、メモリ不足が原因の場合もあるので大き目に設定するとよかったりするかもしれません。
- Continuous Integration
- CIに関する設定です。GitHubなどのSCMと連携して自動的にFunction Appが展開されるようにすることができます。Web Appsとかと同じですね。
- Authentication/Authorization
- HTTPトリガーを使ったFunction AppにWeb Appsで用意されている認証・認可の機能を設定することができます。
- HTTPトリガーで用意されているAPI Keyを使った認証とはまた別で前段で処理されます。
- CORS
- ブラウザからHTTPトリガーなFunction Appを呼び出したりする場合、CORSの設定が必要になります。
![image image]()
既定値の3つはAzure Functions UXのブランチ等と対応してますので参考までに。
- functions.azure.com … 本番環境
- functions-staging.azure.com … master
- functions-next.azure.com … dev
- API definition
- HTTPトリガーなどWeb APIとして公開されるようなFunction Appについてより利用されやすいようにSwaggerの定義ファイル(JSONなど)を指定します。
- Advanced Settings
- Function Appに関するアプリケーション設定が行えます。簡単にいうとFunction App内で使用する接続文字列などを定義できます。(Web.configやApp.configで行うような)
- 注意点はFunctions Container全体で共通(同じ設定)という点です。
- 裏側の仕組みとしてはApp ServiceのApplication Settingsと同じです。実際、その画面が開きます(現状)
![image image]()
- ちなみにバインディングでBlobなど外部サービスと連携させた際の接続設定もこちらに保存されます。
![image image]()
- Function App内では環境変数を通じて取得することができます。(後述)
内部的な話
ざっくりアーキテクチャはこんな感じです。
![image image]()
Azure Functions Runtime (Webjobs.Script.Host)がスクリプトであるFunction Appを動かす実体となります。
通常、Azure Functionsを作ると1つのリソースグループ配下にApp Service PlanとWeb Apps、あとAzure Storageアカウントが作成されます。(※ポータル上から作成した場合はApplication Insightsも作成されます)
また実際にはWeb Apps上でいろいろ動作しています。もうちょっとそのあたりを詳しく書くと
![image image]()
こんな感じの構造になってます。※SiteExtensionsにFunctionsが入ってるのと、Azure Filesの共有フォルダをマウントしてるのがWeb Appsとちょっと違うところかもです。
ランタイムのバージョンは現状2つあります。普通に作ると最新版の~0.2になります。もし今後新しいバージョンが出てきた場合はFunction AppのSettingsタブから簡単にUpdateできます。
![image image]()
実際は FUNCTIONS_EXTENSION_VERSION 設定で~0.2 などを指定してるだけですが。細かい話をするとこんな感じです。
![image image]()
* D:\Program Files (x86)\SiteExtensions\Functions\
** 2016年5月25日現在の推測値 https://github.com/Azure/azure-webjobs-sdk-script/releases
修正内容などはGitHubのページ見ればいいですね。(Kuduとかでも同様です)
またフォルダー構造は以下のような感じ。
![image image]()
- data\secrets フォルダー
- site\wwwroot フォルダー
- 各 Function App のスクリプト等を格納
- フォルダー名 = Function App 名
- Function App 名フォルダー
- Function App に関する定義と実行スクリプト(コードファイル)を格納
- function.json = バインディングなどの定義情報
- * function.json が存在しないフォルダーは Function Appとして認識されない
![image image]()
各Function App内に含まれるファイル等は言語によっても少し異なります。
- C#
- NuGet パッケージの参照設定などは project.json に記述
- カスタムアセンブリは bin フォルダーへ
- node.js
- npm パッケージは node_modulesフォルダーへ
- D:\local\Temp\Functions\Binding
- バインディングされたオブジェクトは Temp フォルダに
- 外から参照できません
各Function Appフォルダには複数のスクリプトや関連するバイナリを置くことができますが、実行時にそれらを参照したりできないようです。(C#のアセンブリロードなどはちょっと特殊)
また複数言語の混在はエラーになるので注意しましょう。(run.csxとrun.ps1を一緒に置いとくなど)
実行するスクリプトの決定ルールなどは基本的にWebJobsと同様です。同一言語のスクリプトが複数存在する場合 run.{拡張子} が起動されます。
開発Tips
C#
- .NET Compiler Platform Scripting APIでファイルに変更があった場合コンパイルされます。(.csと.csxが対象)
- public static な Run メソッドが必須(エントリポイント)
- project.json ファイルを使用して NuGet パッケージの指定など可(細かい話は.NET Core CLIなどのドキュメントを参照してください)
- Run メソッドの引数はバインディングで指定した名前で実装します。
- 一部outputのバインディングには out パラメーター修飾子を利用します(BlobのOutput時はout string outputBlobなどにする)
- CancellationToken token を使用してグレースフル シャットダウンに応答できます。
- 外部アセンブリの読み込みは #r ディレクティブを使用します。もしproject.json で指定した場合は不要( using ステートメントで読み込み)
- カスタムアセンブリは Function App フォルダ直下の bin フォルダに保存(パス変えられません)
- 外部スクリプト(.csx)の読み込みは #load ディレクティブを使用(こちらは相対パス)
- 詳細はこちら https://azure.microsoft.com/ja-jp/documentation/articles/functions-reference-csharp/
JavaScript/node.js
その他
- バインディングされたオブジェクトはテンポラリのフォルダ上で保存
D:\local\Temp\Functions\Binding\<ジョブID>\<バインディング名>
- C# や node.js 以外の言語では上記パスが環境変数で提供されるので適宜読み出し・書き込みを行います
バインディングされたオブジェクトの取得例
C#
#r "Microsoft.WindowsAzure.Storage"
using System;
using Microsoft.WindowsAzure.Storage.Blob;
public static void Run(CloudBlockBlob inputBlob, CloudBlockBlob outputBlob, TraceWriter log)
{
log.Info(inputBlob.StorageUri.PrimaryUri.ToString());
outputBlob.StartCopyFromBlob(inputBlob);
}
PowerShell
$requestBody = Get-Content $Env:req -Raw | ConvertFrom-Json
$name = $requestBody.name
Out-File -Encoding Ascii $Env:res -inputObject "Hello $name"
PowerShellの上記例の場合、実行時に以下のようにファイルが生成されます。
D:\local\Temp\Functions\Binding\<ジョブID>\req
D:\local\Temp\Functions\Binding\<ジョブID>\res
アプリケーション設定の取得
アプリケーション設定は環境変数に入っているので以下のように取得できます。(decodeという設定を取得する場合)
C#
System.Environment.GetEnvironmentVariable("decode")
※ConfigurationManager経由でも取れます。
node.js
PowerShell
バインディングTips
細かいのはドキュメントが揃いだしてきたのでこちらを参照。
ドキュメントにもありますが、バインディング時にBlobなどパス指定する場合にパラメーターを使用することができます。
Blobの場合は {name} や {blobname}.{blobextension} といった感じ。またトリガーで {name}.txt のように指定することでパターンマッチングのようにフィルタすることもできます。この場合、 Blob名の最後が .txt のBlob時のみ発火します。
Queueの場合は
- expirationTime
- insertionTime
- nextVisibleTime
- queueTrigger
- id
- popReceipt
- dequeueCount
などが利用できます。queueTriggerにはメッセージ本文が入ってるので例えばQueueトリガーで発火した後、OutputでBlobのパスに {queueTrigger}.txt のように指定すればメッセージ本文に含まれてる文字列.txt といったファイルが作成されます。
※パラメーターはトリガーやInputのバインディングで取得したものをOutputで使うこともできます。
また特殊なパラメーターとしてGUIDを生成する %rand-guid% とランダムな数値を生成する %rand-int% も利用できます。
※それぞれC#でいうところの Guid.NewGuid().ToString() と (new Random()).Next(10000, int.MaxValue).ToString(CultureInfo.InvariantCulture) になります。
指定例:
{
"type": "blob",
"name": "outputBlob1",
"path": "outcontainer/{name}.txt",
"direction": "out“
},
{
"type": "blob",
"name": "outputBlob1",
“path": "outcontainer/{blobname}.{blobextension}",
"direction": "out“
},
{
"type": "blob",
"name": "outputBlob2",
"path": "outcontainer/%rand-guid%",
"direction": "out“
}
そのほか注意点はいくつかありますが、Blobトリガーは現状ポーリングして発火しているので1万以上のファイル(Blob)がある場合、パフォーマンス低下や発火漏れが懸念されます(公式より)
HTTPトリガー時の認可について
Web AppsのAuthN/AuthZ機能も使えますが通常API Keyを使った認可機能を使用すればよいかと思います。
また指定方法や範囲などはモードと認可レベル・Webhookタイプで変わりますので注意が必要です。
![image image]()
- モード: Standard
- 認可レベル: Function 、 Anonymous、 Admin
- Anonymousはキーなしでアクセスできます。
- Functionの場合は各Function App専用のキーもしくはホストのfunctionKeyが必要
- Adminの場合はホストのmasterKeyが必要
- URLクエリストリングにcode=<key>を付ける、もしくはHTTPリクエストヘッダにx-functions-keyを追加してキーを送信する必要があります。
- モード: Webhook
- Webhookタイプ:
- Generic JSON
- URLクエリストリングにcode=<key>を付ける
- Github
- HTTPリクエストヘッダに X-Hub-Signature という名前でキーを使って生成された署名を付ける必要がある
適切な方法で適切なレベルのキーが提供されない場合、認可エラーになり失敗します。
どの場合もキー(WebhookのGithubを選択した場合だけ名称がGithub Secretになりますが)は画面上に表示されているものを使用します。またキーの実体はdata\secrets フォルダにあります。
<Function App名>.json … 各Function App用の専用キーです。認可レベルをFunctionに指定した場合に使用できます。
{"key":"<Function App専用のキー>"}
host.json … Functionsコンテナー全体のキーを管理します。
{
"masterKey": "<Adminレベル用のキー>",
"functionKey": "<全Function App共通キー>"
}
もしキーを変更したい場合はKuduなどを使用して直接これらのファイル内のキーを編集することで変更できます。
デバッグについて
C#などの場合、Visual Studioを使用して直接Functions上の.csxファイルを開いてデバッグすることもできます。(但しApp Service Planで動作している場合のみ)※デモしたけど、シンボルが読み込まれないとかちょっと不安定だったけど…
※Cloud Explorerからファイル開いてアタッチするだけ
あるいはローカルにWebJobs.Script.Hostを動作させてローカル上でスクリプトをデバッグすることもできます。WebJobs.ScriptをCloneなりして実行することでローカル上で開発が可能です。(ちょっとコツがいる)
※最低限ローカル上でAzureWebJobsEnv 環境変数に Development と設定、AzureWebJobsStorage 、 AzureWebJobsDashboard環境変数をポータル上からコピペして設定、あとはFunctions上のsite\wwwrootフォルダ以下と同じ構成にしたフォルダのパスをAzureWebJobsScriptRoot 環境変数に設定すれば大丈夫と思います。
※function.json(バインディング)でBlobなどを使用する場合、接続文字列等をfunction.jsonで定義している名前と同じ環境変数に設定しておきます。(ないとHost起動時に読み込まれない)
※HTTPトリガーの場合はWebJobs.Script.WebHostを起動しましょう
スケールについて
Dynamic Service Planの場合、0~10の範囲でインスタンスが自動的に増減します。構成されているトリガーに基づいてトラフィックや実行状況から判断されるようです。1つのインスタンス内の同時実行可能数はメモリ領域の設定などによって異なるようです。(ちなみに今はDynamicの中でもプラン選べないのでこの制限以外選択の余地なし)
※どのように稼働してるかはMonitoringタブから確認
App Service Planの場合は基本的にApp Serviceの構成に依存します。オートスケールや稼働するインスタンス数などはApp Serviceでユーザーが構成します。
デプロイについて
FunctionsコンテナーそのもののデプロイはARM Templateを使って展開することもできます。既にQuickstart templateに公開されているのでそちらを参考に。
Function AppについてはCIの設定からSCMと連携して行うことも可能です。
またSite\wwwrootフォルダ以下にFunction App名なフォルダと必要なファイル(function.jsonとrun.csxなど)があればよいのでFTPやWeb Deployなどを使用してデプロイすることも可能です。あるいは環境によりますが、Azure File Storage上の共有フォルダを直接マウントして編集(あるいはフォルダごとコピーなど)することで展開することもできます。
モニタリング/ログ
消費ユニット/インスタンス数はMonitoringタブから参照できます。
![image image]()
お金関連(請求関連)はhttps://account.windowsazure.comやBilling API(REST API)経由で取得できます。以下の2つのメーターを参照しましょう(日本語の場合)
- コンピューティング期間 (GB秒) – Functions
- コンピューティング要求 – Functions
![image image]()
Function App単位のログやライブな実行状況などは各Function AppのMonitorタブから行えますが、現状Coming Soonです。
![image image]()
ただし、そのページにあるinvocation logとlive event streamのリンクから個別に参照することは可能です。
Invocation log(呼び出しログ)
https://<Functions名>.scm.azurewebsites.net/azurejobs/#/functions というURLになります。Azure WebJobsのログを見る時と同じアプリ(SiteExtension)ですね。
![image image]()
ちなみにログはAzure Table Storage上のAzureFunctionsLogTableコンテナーに保存されてます。(ちなみにホストに関するログ等は同じくAzure Blob Storage上のazure-webjobs-hosts コンテナーに保存される様子)※Dynamicプラン時のみかも
詳細を見ることでFunction Appのログで見た内容(Outputの内容)やバインドされた各値の内容など参照できます。
![image image]()
Live event stream
数秒ラグありますが、ライブで要求数や実行時間、失敗数などを見ることができます。
![image image]()
URLを見ればわかりますが、Web Appsのサポート用ツールだったりします。
https://support-bay.scm.azurewebsites.net/Support.functionsmetrics/#/<Functions名>/<Function App名>
Openness
Azure Functionsに関するコード等はすべてGitHub上で公開されています。もしフィードバックなどあればGitHubのIssueに登録するとよいかもです。またライセンスはMITライセンスとなっているようです。
そのほかWebJobs SDKやWeb Jobs SDK Extensionも参考に。
また複数言語対応という点もありますが、基本的にランタイムが公開されているのでオンプレだろうがAzureじゃないクラウドだろうが動かすことはできます。ただ現状手厚いサポートはありませんが。(ポータル部分とか展開方法とかいろいろ)
注意事項や制限事項
- 2016年6月4日現在、Public Preview状態
- 利用可能なリージョン
- 現状は米国西部、西ヨーロッパ、東南アジアの3か所のみ。
- カスタムドメイン名は非対応
- 内部のWeb Apps側で設定しても404になります。(要望は上がってるのと、上位にTraffic ManagerやAPI Managementを乗せるという手はある)
- スロット
質問やフィードバック
今のところPreviewということで、有償のテクニカルサポートはありません。ベストエフォート的な対応になりますが、基本的にはStack OverflowやMSDN Forum、あとTwitterなどでやり取りする感じです。
バグ報告とかはGitHubへ。
ドキュメント
その他
気が向いたら更新します。サンプルも気が向いたら。
カテゴリー:
つぶやき,
Tips Tagged:
Azure,
Cloud,
Functions,
JAZUG