tech.guitarrapc.cóm

Technical updates

Azure Functions C#でGitHub WebhoookやVSTS Build通知をSlackに通知してみた

AWS Lambdaといえば、Amazon Web Serviceが提供するNode.jsやPython、Javaを使ったサーバーレスなコード実行基盤です。

https://aws.amazon.com/jp/lambda/

これって、単純にコードをサーバーなしに実行できるだけじゃなくて、「AWSリソースのイベントをトリガーに様々なリソースを連動させる」「APIGatewayと連動することで、AWS以外の適当なWebHookをトリガーに様々なリソースを連動させる」といったことが可能になります。つまり、本質はリソースとリソースをつなぐ歯車の役割を果たすのです。しかもコードで自在に操作を制御できる。

だからこそグラニもAWS Lambdaは大好きで、発表されてすぐにGitHub WebHookでIssueやPull RequestをChatworkに通知する基盤をNode.jsで作ったり、Route53の処理など様々な箇所で活用しています。

さてBuild 2016で、ついにAzureによる同様の基盤が発表されました。それが、Azure Functionsです。

https://build.microsoft.com/

https://azure.microsoft.com/en-us/blog/introducing-azure-functions/

今回は、Azure Function Appsを使ったWebhook処理をいくつかC# で書いてみましょう。

Azure Functions

実際にAzure Functionsで何ができるかは、公式ドキュメントが詳しいです。

https://azure.microsoft.com/en-us/services/functions/

https://azure.microsoft.com/en-us/documentation/articles/functions-overview/

幸いにもコード処理部分は動画になっており、ただの文章よりもそうとう理解が進みます。もう少し複雑な処理も動画に追加されるともっと嬉しいです。

https://azure.microsoft.com/en-us/documentation/services/functions/

あとは先人の知恵もあります。

https://blog.xin9le.net/entry/2016/04/01/042452

https://blog.nnasaki.com/entry/2016/04/02/124236

https://blog.shibayan.jp/entry/20160402/1459575658

今後、あっという間に、AWS Lambda相当の記事はどんどん出るんじゃないですかね。Advent Calendarとかも作るといいでしょう。

https://qiita.com/tags/lambda

https://qiita.com/advent-calendar/2014/lambda

https://qiita.com/advent-calendar/2015/lambda

価格

AWS Lambdaもですが、Azure Functionsは実行した分のみの課金です。計測は2つあります。

https://azure.microsoft.com/en-us/pricing/details/functions/

1つが、メモリ*コンピュート時間

With Azure Functions you only pay for what you use with compute metered to the nearest 100ms at Per/GB price based on the time your function runs and the memory size of the function space you choose. Function space size can range from 128mb to 1536mb. With the first 400k GB/Sec free.

もう1つがリクエスト。100万リクエストまでは無料らしいですね。

Azure Function requests are charged per million requests, with the first 1 million requests free.

Dynamic Hosting Planってなんなんですかね? ドキュメントが見つけられない.... Azure Functions専用のプランらしく、今は気にしなくていいそうですが。ちなみにAzure Functionsを作成するときに、DynamicとClassicを選択できますが、Dynamicを選ぶと実行できるリージョンが今は限定されます。

Azure Functions hosted on the Dynamic Hosting plan will be available via the monthly free grant through April 22nd, with paid preview available after that date.

https://azure.microsoft.com/ja-jp/documentation/articles/azure-web-sites-web-hosting-plans-in-depth-overview/

@shibayanさんが詳細を調べてらっしゃいました。さすがです。

https://blog.shibayan.jp/entry/20160402/1459575658

テスト

リモートデバッグを含めてAWS Lambdaが提供できていない高度なデバッグビリティを担保しているのはとても素晴らしいですね。AWS頑張れ。

https://azure.microsoft.com/en-us/documentation/articles/functions-test-a-function/

困ったときは

公式にstackoverflowやMSDNフォーラムと案内があります。特にstackoverflowは中の人もちょくちょく回答してくださっているので、オススメです。

https://stackoverflow.com/questions/tagged/azure-functions

https://social.msdn.microsoft.com/Forums/en-US/home?forum=AzureFunctions

Kudu

AppServiceなのでKuduも見られます。

方法は、見たい Azure Function を選択 > Function App settings > Tools > Kuduとブレードをたどる方法。

あるいは、AppService共通のscmを付与したアドレスで。アドレスは例えば、test というAzure Functionsならhttps://test.scm.azurewebsites.net/になります。

Lambdaでのメモリとの比較とかできたり面白いです。

Visual Studio Online

またVSOにも対応しています。

これも方法はKudu同様で見たい Azure Function を選択 > Function App settings > Tools > Visual Studio Onlineとブレードをたどる方法。

あるいは、AppService共通のscmを付与したアドレスに末尾 /dev付与で。アドレスは例えば、test というAzure Functionsならhttps://test.scm.azurewebsites.net/dev/wwwroot/になります。

VSOでは、見事にC# 実行中身の .csxや .jsonも見えててとても良いです。

もちろんVSOで編集すると、Azure Functionsにも反映します。

Azure Functions の利点

いくつかあります。

幅広い言語対応

AWS Lambdaを上回る圧倒的なメリットです。

サービス 言語対応
Azure Functions C#, Node.js(JavaScript), Python, F#, PHP, batch, bash, Java, PowerShell
AWS Lambda Node.js (JavaScript), Python, Java (Java 8互換)

とはいえ、現状は以下の通り言語によって手厚さが違います。とりあえずメイン対応は、C# とNode.jsがそろってる感じです。PythonとJavaが同程度にそろうとより使う人が増えそうです。

言語 テンプレート対応
Batch
C#
JavaScript
Bash
PHP
PowerShell
Python

Azure リソースのイベント駆動処理

AWS Lambdaのメリットが、デフォルトでaws-sdk参照、IAM Role制御、VPC対応によるAWSリソースの自在なコントロールです。Azure Functionsも同様にAzureのリソースをトリガーに処理を走らせることができます。リリース直後の現在のblobについて触れている記事もあります。

https://blog.nnasaki.com/entry/2016/04/02/124236

今はBlob、EventHub、StorageQueueの対応のようですが、AWS Lambda同様に対応が増えていくでしょう。とりあえず、Cloud Watch相当のApplication InsightでトリガーはWebhookで出来そうなので、モニタリング系の連動はたやすそうですね。

もちろんUser Voiceで追加希望は効果が高いでしょう。

https://feedback.azure.com

個人的な予測では、AWS Lambda同様、Azure Functionsはプラットフォームのリソース間疎結合を担うものという位置づけになるはずなので「クラウドプラットフォームの要」となり急速に発展すると考えています。*1

CI 統合

VSだけでなく、VSTSやGitHub、Bitbucket、OneDrive、Dropboxなどからデプロイ統合が可能です。これもAWS Lambdaではとてもつらかった部分で、良く学んでAzureの従来の方法がうまく機能しています。

AWS Lambda + API Gateway 同様の処理

HttpTriggerやGeneric Webhoook 、TimerTriggerはAPI Gateway + AWS Lambdaで可能です。同様のことがAzure Functionsのみでできるのは良いことです。TimerTriggerに至ってはLambdaと同じくcron指定です。違和感なく触れるでしょう。

もちろんAuthentication/Authorizationもあります。様々なIdPと連動しているのはとてもいいですね。

気になるポイント

AWS Lambdaを触っていてAzure Functionsを触ると気になるポイントがあります。

リソースアクセス制御

もとからAzureで気になるポイントですが、IAM Roleに相当するリソースの他リソースへのアクセス制御ってどうなるのかなというのは気になります。

外部ライブラリの利用

Node.jsでasync moduleが欲しい場合など、外部リソースの参照をどうしたものか不明です。AWS LambdaでいうところのZipアップロード的なものはどうなるんですかね?requires()で良さそうではあります。

C# でも、NuGet参照したいときにどうしたものかなと。C# に関しては、CSharp Scriptingのようなので、現状では限定されている感じですが詳細がいまいち不明です。*2

https://github.com/dotnet/roslyn/wiki/Interactive-Window#r

Azure FunctionsもVSからデプロイできますが、AWS LambdaもVisual Studioから直接デプロイ、現在設定されているFunctionをもとに新規作成などが可能なので、AWS Console一切見ずに設定可能です。

Monitor

Coming Soonとのことです。一見すると、かなり良さげです。いや実際これでいいんですよ。AWS Lambdaのモニターはみにくいです。

Token による制御

ヘッダにToken IDを入れる認証は単純ですが強力です。しかし、AzureFunctionsにはtokenでの認証はGitHub Webhook type以外になさそうな....? Authorization/Authenticationでできると思ったのですが、すべてIdP連携だったためtokenでの制御ができないものでしょうか....?

https://github.com/projectkudu/AzureFunctions/search?UTF-8=%E2%9C%93&q=webHookType

できないと幾つか考慮が必要になります。

  • URLが漏れたら、Functions作り直してURL変更するしかない? *3
  • 連携系でIdPでのID連動はかなりつらい (通常対応してないです)
  • webHookTypeをGitHubにするというのも手でしょうが、X-Hub-Signatureの計算とかいちいち入れるのっていう

設定できる気がしますが、見つけられませんでした...。

作成

さくっとAzure Functionsを作成します。

Azure Portalで追加 (+) > 検索窓で Functionと入れれば Function App が表示されます。

Create を選択します。

あとは必要な入力をすればokです。

3分程度で出来上がります。

サンプル

3つC# でのAzure Functionsを作ってみましょう。Node.jsはAWS Lambdaで散々作る羽目になったのでもういいです。

  • Slackに通知
  • GitHub IssueへのコメントをWebhookで受け取ってSlackに通知
  • VSTSのビルド完了をWebhokで受け取ってSlackに通知

Slackに通知

Slackに通知部分を切り出して、他から呼びだすためのAzure Functionsです。通知が複数回ないならFunctionsを分けないほうがいいでしょうが、多くの場合は処理と通知を分けたくなるのではないでしょうか。

Jsonで受け取ってSlackに通知するので、Generic Webhookで作成します。

あとはSlackのIncoming Webhook APIにPOSTする処理をサクッと書きます。

https://gist.github.com/guitarrapc/21a7f8cf8d53769f50dada1abdd83636

Azure FunctionsもLambda同様、サンプルとなるjsonをRequest Bodyにおいておきます。

https://gist.github.com/guitarrapc/22ab70d175667bfa65b033615edaba8b

この辺のデバッグやローカルで書き書き処理は、Visual StudioよりLinqPadが安定ですねぇ。わたしは。

ローカルでサクッと動いたら、SaveしてからRunしましょう。

問題なくSlackに通知が来ましたね。

GitHub Issue へのコメント を Webhook で受け取ってSlack に通知

次はGitHub IssueへのコメントをGitHub Webhookで受け取って、Slackに通知してみましょう。

今回のはここを参考にするといいでしょう。

https://azure.microsoft.com/en-us/documentation/articles/functions-create-a-web-hook-or-api-function/

デモをみたり、テンプレートをみると、GitHub Webhook - Nodeが目に留まりC# がないのでコレを選びたくなるのですが、言語が違うので今回はGeneric WebHookをまず選択します。

とはいえ、サンプルJSONや処理の参考になるので一個作っておくといいでしょう。ということで、みてみるとなるほどです。

GitHub の Webhook 設定

さて、C# - Generic WebHookで作成したAzure Functionsですが、まずはGitHub Webhook対応しましょう。Integrateタブに行ってIntegrateGitHub に変更します。

これでDevelopタブに、GitHub Secret欄が出ています。

次にGitHub のWebhook を掛けたいリポジトリ > Settings > Webhooks % servicesに行きます。

Payload URLにAzure FunctionsのFunction UrlのURLをいれて、Function UrlのURLにAzure FunctionsのFunction UrlのURLを入れればokです。

Azure Functions のコード

さて、コメントをする前にコードを書きましょう。とりあえずGitHub Commentが書かれたときに内容を受け取るだけならこれでokです。*4

https://gist.github.com/guitarrapc/e3ed9363bf2d44dc4a1ecb37a1cb5927

これでGitHub Issueにコメントすれば、GitHub WebhookでトリガーされてAzure FunctionsのLogsに表示されます。

Slack への通知

さて、あとはSlack通知のAzure FunctionsにPOSTするようにコードを付け加えます。

https://gist.github.com/guitarrapc/f08665041b1e39b589ef3ec22561d627

Saveしてからコメントしてみると、Slackに通知されますね。

VSTS のビルド完了を Webhok で受け取ってSlack に通知

残りはVisual Studio Team Serviceのビルド完了通知をSlackに通知してみましょう。XamarinのTest Cloudなども含めて、VSTSは機能強化が著しいです。

従来は、Web AppsでASP.NET WebHooksを使うかZapierが王道でした。

https://blogs.msdn.microsoft.com/webdev/2015/09/04/introducing-Microsoft-asp-net-webhooks-preview/

https://zapier.com/zapbook/visual-studio-online/

ただ両者に一長一短があります。この隙間にほしかったのが、Lamdba相当の処理、つまりAzure Functionsです。ただし、NuGetが使えないためHook が来た VSTS Job を参照してHook が来た VSTS Job を参照して、といった処理には向いていません。しかたないので待ちましょう。

処理 メリット デメリット
ASP.NET Webhooks ごにょごにょ処理を噛ませることができるのでかなり自在に色々できます。 - Web Apps でいつ来るかわからない通知のためにずっと起動という無駄半端なさ
- エラーが起こったときに例外で死ぬ可能性がある
- Webhookを処理したいだけなのに持ち味が全く生かしきれません。
Zapier Webhook の解析、実行は完全お任せ最高です - Zapが5分単位のためリアルタイム性が損なわれる
- いろいろごにょごにょしようとすると、JavaScriptを書くことになる
- あれこれできないため若干窮屈な思いをします
Azure Functions - ごにょごにょ処理を噛ませることができるのである程度自在に色々できます。
- 必要な時にだけ処理されるのでコスト面も起動も気にしなくてok
- NuGet が使えないため楽にできることに制約があります。
- いろいろごにょごにょしようとするとそれなりにコードを書く必要があります

さっそくGeneric WebHookで作ってみましょう。

今回のは、ここを参考にするといいでしょう。

https://blogs.msdn.microsoft.com/buckh/2016/03/31/using-vs-team-services-web-hooks-with-azure-functions/

VSTS の Webhook 設定

Azure Functionsを作成したら、Function Urlをコピーします。

このFunction UrlをVSTSのWebhookに設定します。VSTS の 設定したいProject の Admin画面 > + ボタンで追加 > Web Hooks を選択します。

Triggerの設定は、Build completedがいいでしょう。

SETTINGS > URLに作成したAzure FunctionsのURLを貼り付けましょう。

RESOURCE VERSIONは、2.0-preview.2でも1.0でもいいですが、ここでは2.0-preview.2のコードでサンプルを示します。

Azure Functions のコード

VSTSでTESTをするとREQUESTのJSONが拾えます。このJSONでテストするといいでしょう。

Azure FunctionsのRequest BodyにJSON埋めて、テストを容易にします。

https://gist.github.com/guitarrapc/13c38ee8c739a1b0d07c6886dc0cbcb4/edit

また、JSONをdynamicではなくクラスとして変換すると、LinqPadでのデバッグはとても楽ちんです。*5ということでサクッと書きます。

https://gist.github.com/guitarrapc/6e5530f05872d3fbbcbc72b16802ac8f

ちなみにRESOURCE VERSION 1.0の場合はこんな感じのクラスでJSONをデシリアライズできます。

https://gist.github.com/guitarrapc/f21614008a5daeae69b523386afacf9a

テストでRun実行してみると問題なく解釈できていますね。

VSTSのWebhookからTestしても問題なくトリガーされています。

Slack への通知

最後にSlack通知のAzure FunctionsにPOSTするようにコードを付け加えます。

https://gist.github.com/guitarrapc/802a65c7734de3b4eb27327000b9a00e

Saveしてからビルドしたり、TESTするとSlackに通知されました。

まとめ

慣れの問題もありますが、Azure FunctionsをC# で書いていると、AWS LambdaのNode.jsで苦労するようなこともまったくなく素直に書けます。癖がほとんどないので、かなり使いやすいでしょう。

あとは、Nuget周りがいまいち読めない。。。。 #rでリファレンス基本効くらしいですが*6、Newtonsoft.Json以外にどこまで通るのかしら?#r Microsoft.TeamFoundationServer.Clientとかいけないんですよねぇ。

今後に期待しつつ、aws-sdkなど処理を何かしら依存していないものは、Azure Functionsに寄せていきます。さて、AWS Lambdaもいい刺激を受けて、今のデバッグやデプロイといった苦しい箇所がよくなってほしいですね。*7

あ、400記事目でした。

次回は、Azure FunctionsをGitHubとCIしてみましょう。

https://tech.guitarrapc.com/entry/2016/04/03/051552

*1:AWS Lambdaが実際そうですね

*2:#r "Newtonsoft.Json" でJson.Netは利用できますが、結構他のは怒られます

*3:TokenのRegenerateで済ませたいものです

*4:Issueの作成時のみ、更新時のみの処理を入れてくということはSwitch文などが始まるでしょう....

*5:Azure Functions上だけならdynamicでいいかと

*6:CSharp Scriptingの現行仕様より進んでる?

*7:C# 対応もね。MonoもMITになったし入れてほしい