tech.guitarrapc.cóm

Technical updates

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

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

AWS Lambda(イベント発生時にコードを実行)| AWS

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

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

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

build.microsoft.com

azure.microsoft.com

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

目次

Azure Functions

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

azure.microsoft.com

azure.microsoft.com

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

azure.microsoft.com

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

blog.xin9le.net

blog.nnasaki.com

blog.shibayan.jp

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

qiita.com

qiita.com

qiita.com

価格

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

azure.microsoft.com

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.

azure.microsoft.com

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

blog.shibayan.jp

テスト

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

azure.microsoft.com

困ったときは

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

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 について触れている記事もあります。

blog.nnasaki.com

今は 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

github.com

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 での制御ができないものでしょうか....?

github.com

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

  • 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 する処理をサクッと書きます。

gist.github.com

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

gist.github.com

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

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

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

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

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

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

azure.microsoft.com

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

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

GitHub の Webhook 設定

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

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

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

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

Azure Functions のコード

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

gist.github.com

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

Slack への通知

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

gist.github.com

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

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

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

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

blogs.msdn.microsoft.com

zapier.com

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

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

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

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

Using VS Team Services Web Hooks with Azure Functions - Buck Hodges

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 埋めて、テストが容易になるようにしておきます。

gist.github.com

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

gist.github.com

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

gist.github.com

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

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

Slack への通知

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

gist.github.com

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 してみましょう。

tech.guitarrapc.com

*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 になったし入れてほしい