Azure Functions で実行時のIDを取得する

Azure Functionsを使ってるときに今実行されている状態のIDを使いたい場合があるかと思います。後で追跡する場合に呼び出されたIDとか関連付けされていると便利ですよね。

というわけで、呼び出しログ(Invocation Log)とかで使われるIDをコード内で使う方法です。

C#の場合

using System;

public static void Run(string input, ExecutionContext executionContext, TraceWriter log)
{
    log.Info($"InvocationId: {executionContext.InvocationId}");
}

C#の場合はExecutionContext型の引数を受け取るようにすればOKです。ExecutionContext型にはInvocationIdプロパティがあるのでそちらを参照します。ちなみに内部的にも同じ型でcontextという名前でバインディングされるので、contextという引数名にするとバインディングエラーになります。修正されるかもしれませんが。

JavaScriptの場合

module.exports = function (context, input) {
    context.log('Node.js manually triggered function called with input:', input);
    context.log(context.bindingData.InvocationId)
    context.done();
};

JavaScriptの場合はcontextのbindingDataにInvocationIdが生えてるのでそちらを使います。

実行結果はこんな感じで、呼び出しIDが取得できます。

2016-08-03T19:14:03.491 Function started (Id=f58733a5-d6ce-4035-8a42-c6b95b7d79b7)
2016-08-03T19:14:03.491 InvocationId: f58733a5-d6ce-4035-8a42-c6b95b7d79b7
2016-08-03T19:14:03.491 Function completed (Success, Id=f58733a5-d6ce-4035-8a42-c6b95b7d79b7)

Azure Functions で実行中にコンパイルするとどうなるの

裏でFunction Appが実行中のときにコンパイルして(コンパイルエラーになったりして)るときに実行中のものはどうなるのか、予想では別物なんで問題ないと思いますが一応。

検証用コード

using System.Net;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info($"Start ----");
    // parse query parameter
    string name = req.GetQueryNameValuePairs()
        .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
        .Value;

    await Task.Delay(TimeSpan.FromSeconds(20));

    // Get request body
    dynamic data = await req.Content.ReadAsAsync<object>();

    // Set name to query string or body data
    name = name ?? data?.name;

   log.Info($"End ----------");
   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);
}

HttpTriggerなC#のテンプレートにStartとEndのログと間にTask.Delayで処理止めてるだけのシンプルなやつです。
※ログにFunction Startedとか出るので無駄な気もするけど一応

手順的にはこんな感じ

1.  上記コードを実行する(適当に呼び出す)
2. Task.Delayしてる間にコードを適当に弄ってSaveしてコンパイルエラーにする
3. 結果を見る
4. そのまま再度呼び出す

実行結果はこんな感じになりました

2016-07-19T03:34:42.334 Function started (Id=14c91f2c-2490-437c-b461-258a13872d82)
2016-07-19T03:34:42.334 Start ----
2016-07-19T03:34:45.698 Script for function 'HttpTriggerCSharp1' changed. Reloading.
2016-07-19T03:34:45.698 Compiling function script.
2016-07-19T03:34:45.776 run.csx(14,13): error CS1002: ; expected
2016-07-19T03:34:45.776 run.csx(11,48): error CS0246: The type or namespace name 'aaaa' could not be found (are you missing a using directive or an assembly reference?)
2016-07-19T03:34:45.776 run.csx(14,13): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:34:45.776 run.csx(17,20): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:34:45.776 run.csx(14,5): warning CS0168: The variable 'dynamic' is declared but never used
2016-07-19T03:34:45.776 Compilation failed.
2016-07-19T03:35:02.334 End ----------
2016-07-19T03:35:02.334 Function completed (Success, Id=14c91f2c-2490-437c-b461-258a13872d82)
2016-07-19T03:35:27.915 Function compilation error
2016-07-19T03:35:27.915 run.csx(14,13): error CS1002: ; expected
2016-07-19T03:35:27.915 run.csx(11,48): error CS0246: The type or namespace name 'aaaa' could not be found (are you missing a using directive or an assembly reference?)
2016-07-19T03:35:27.915 run.csx(14,13): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:35:27.915 run.csx(17,20): error CS0103: The name 'data' does not exist in the current context
2016-07-19T03:35:27.915 run.csx(14,5): warning CS0168: The variable 'dynamic' is declared but never used
2016-07-19T03:35:27.915 Function completed (Failure)
2016-07-19T03:35:27.961 Exception while executing function: Functions.HttpTriggerCSharp1. Microsoft.Azure.WebJobs.Script: Script compilation failed.

StartとEndの間でコンパイル走ってエラーになってますが、Function Id=14c91f2c-2490-437c-b461-258a13872d82は継続して処理が完了してます。

その後再度呼び出してみるとコンパイルが完了してないので再度コンパイル→失敗→500エラーが返る、という感じです。

予想通りでしたね。なんかおかしい、という場合はぜひ追加の検証をお願いします。

Azure Functions / Overview and Under the hood

2016年12月5日更新

ちゃんと書いてなかった気がするのと、某所で喋ったのでスライドの中身を適当にコピペします。そのうち動画・スライドが公開される気もしますが。→ されました

※2016年12月5日現在の情報です。
※だらだら長くなってしまった…

続きを読む →

Windows 10 のデバイスポータル

Windows 10 のInsider PreviewにBuild 14342が本日リリースされました。

細かな話はさておき、このビルドからちゃんとデバイスポータルが動作するようになりました。

デバイスポータルというのは、Windows 10 IoT Coreが最初にお披露目したと思うのですがブラウザ経由でデバイスの状態を確認したり、アプリケーションをデプロイしたりといったユーティリティが提供されたWeb管理ツールです。

image

見たことある人もいますよね。実はこのデバイスポータルはWindows 10であればどのデバイスファミリーでも利用可能だったりします。
例えばWindows 10 IoT CoreのほかにPhoneやXBox、HoloLensなどもそうですね。既定の設定(ポート)や設定方法についてはドキュメントを見ましょう。

Windows 10のデスクトップで有効にするにはBuild 14342にあげてから設定→更新とセキュリティ→開発者向けを表示し、「デバイスポータルを有効にする」をオンにします。

image

認証は適宜設定しましょう。なお接続方法のところにリンクがありますがポート指定されてないのでクリックしても接続できません。

Windows Developer Modeのパッケージがインストールされていることも確認しましょう。
image

なお実体はWeb Managementというサービスです。レジストリなどを弄った後はこのサービスを再起動しておくといいかもです。
image

さてDesktopの場合、接続するポートがランダムになってしまうので面倒くさいです。
一応レジストリで固定化できるのでしておきましょう。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WebManagement\Service

にDWORD(32bit)でHttpPort、HttpsPortを作ってそれぞれポート番号を指定します。
また動的なのをやめるために UseDynamicPorts を0に設定します。(設定後サービス再起動しましょう)

例:
image

※このあたりを参照 → Device Portal for Desktop

接続してみると認証が有効な場合以下のような画面になります。

image

適当に設定してあげるともろもろアクセスできるようになりますので良しなに。
image

まぁそういう感じでざっくり管理がどのデバイスファミリーでも利用できるのは良いかもですね。

Azure Media Encoder Standard のスキーマとか

Azure Media Servicesで動画のエンコード行う際、最近だとMedia Encoder Standardを使うかと思いますが今日はそのスキーマの話です。

エンコードのジョブを作成する際、どういったフォーマットや品質でエンコードを行うか指示するわけですが、通常はプリセットを利用するわけです。

ポータル上でプリセット使う場合に選択するアレですね。なおドキュメントは過剰翻訳されてるというか、英語で見ても翻訳されてたりちょっとイマイチです。(指定するプリセット名が翻訳されてしまってる…)
※実際に指定する際は各プリセットの個別ページに記載されてるやつを使いましょう。

さてもっときめ細かく指定したい場合はカスタムプリセットを作ってエンコードすることもできます。
その際、XML形式とJSON形式を選べるわけですが、XML形式はSchemeが一応公開されてるにも関わらずJSON形式はさっぱりです。

なおたまに見るとUpdateされてたりします。具体的には回転情報を維持するかどうかなど。

image

今までは黒帯ついたりしてたのでこれでちゃんとできますね。さてJSON形式ですがMSDNライブラリのほうにはないので、Azure公式ドキュメントのほうを探しましょう。と言いたいところですが、肝心なところがGitHubにしかない予感。

こちらにいろいろ載ってるので参考まで。

H.264のプロファイルをBaselineにする方法とかいろいろ。慣れるとXMLのスキーマみてどこに何指定したらいけるかなんとなく判断できますが、基本的にTry&Errorになりそうな気がします。

※変な値指定するとJobでエラー返るので判断はある程度付きます。(ただしある程度)

なおMedia Encoder Standard(だけじゃないかもしれませんが)の裏側はFFmpegなので、FFmpegでできそうなことはだいたいできると思います。FFmpegバンザイ。(プリセットの内容みて引数生成してるだけな気がする)

まぁそんな感じでMedia Servicesをお楽しみください。

Azure Virtual Machines の再デプロイ

Azure の仮想マシン(Virutal Machine)でリモート接続できなくてにっちもさっちもいかなくなった場合とか、なんだか調子が悪いわぁということでホストを移りたいとかたまにありますよね。

そういう時はホストが移動するのを期待してインスタンスサイズを変えたりしてたわけですが、いつの間にかそんなことしなくても簡単に再デプロイできるようになっていました。

image

わぁ便利。3月頭ぐらいに実装されてたっぽいです。

続きを読む →

App Service Environmentでバックエンドと通信できない

App Service Environment(日本語名:App Service 環境)を使うとVNET(v1)※現状 に接続することができます。
普通のApp Serviceと違ってClosedな環境にしたり、VNETにつなげられるということはVPNであれこれしたりできるわけです。

なので内部用で外には公開したくないSQL Serverな仮想マシンとかVNET参加させたRedis(Premium)とかと合わせて完全VNETオンリーな環境が作れるわけですが、VNETの注意点として以下のように記載されています。

App Service 環境からバックエンド リソースへの安全な接続
App Service 環境から仮想ネットワーク内のエンドポイントへの送信トラフィックには、注意すべき点が 1 つあります。App Service 環境から、App Service 環境と同じサブネットにある仮想マシンのエンドポイントに到達することはできません。App Service 環境が、App Service 環境専用として予約されているサブネットにデプロイされていれば、通常、これは問題にはなりません。

クラシックなVNET(v1)の制限なのかNSGの制限なのか、はっきりとわかりませんでしたがApp Service Environmentと同じサブネット上の他の機器とうまく通信できないようです。

なので教訓としてApp Service Environmentは専用Subnetに配置しましょう。(作るのが大変なのでこちらを専用化したほうが楽でしょう。CIDRの都合もあるかもしれないし)

さてさて、そうは言ってもそこを何とかならないですか?というのが世の常ですね。
一応泥臭い回避策はないことはないのですが、、、

簡単に言うとApp Service EnvironmentのWorkerPoolであるWeb Appsの設定で明示的にVNETに参加させるという感じです。
この機能そのものは通常のApp Serviceでもある機能で、VNETにPoint to Site接続でVPN接続する機能です。
image

同じVNETにいるくせにVPNを張らないといけないとは!w(おまけにPoint to Siteの設定がVNET側にも必要です)
ということで結局大変でしかも余計な口ができてしまうので、あきらめて作り直したほうがいいかと思います。

まとめ

ネットワークの設計は慎重に。ドキュメントは穴があくほど見まくりましょう。

Azure Management REST API用のBearerトークン

よく忘れるので。

$adal = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
[System.Reflection.Assembly]::LoadFrom($adal)
[System.Reflection.Assembly]::LoadFrom($adalforms)
$adTenant = "<あなたのテナント>.onmicrosoft.com"
# well-known ID
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://management.core.windows.net/"
$authority = "https://login.windows.net/$adTenant"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto")
$authHeader = $authResult.CreateAuthorizationHeader()
# Write-Host "Bearer Token: $authHeader"
$authHeader | Out-File bearerToken.txt

これでBearerトークン出来上がり。認証はいつもの認証ダイアログ的なのが出るので安心です。
(要Azure PowerShell)

参考:Setting up PostMan to call the Azure Management APIs

Windows 10 で省電力時にモニタのサイズがおかしくなる (未解決)

Windows 10でDisplay Portのモニタを使ってる時に、省電力の設定でモニタの電源オフされたあと復帰するとウィンドウのサイズなどがすごく小さくなるケースがあります。

image

ここの設定ですね。

どうも解像度を見失って既定値使うからっぽいです。なのでレジストリ弄って既定値をディスプレイの解像度にしておいてあげるとよさそうです。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\Configuration

の配下に SIMULATED_ で始まるキーがあるのでその下の00キーの PrimSurfSize.cx および PrimSurfSize.cy をそれぞれ適切な解像度の値にしてあげます。

image

※ うちのモニタだと2560×1440なので。

とりあえずうまくいったっぽい ( ´ー`)フゥー... なおると思ったんだけどやっぱり駄目っぽい…

Azure Resource Managerのハンズオン

セミナーの詳細よくわかってなかったのですが、ARMの基本的な体験ができるハンズオンが公開されました。

ハンズオンでは最終的にSQL Databaseを使った複数台で負荷分散する仮想マシン上のWebアプリケーションをテンプレートを使ってデプロイという感じです。
ざっくり図にするとこういう感じです。
image

演習で使うテンプレートなどはこちらにおいてます。

まぁ練習用なのですごくシンプルです。最低限のことしかしてません。
演習ではデプロイの方法を学ぶというか触れてもらう意味合いのほうが強いので、テンプレートをゼロから起こしたりといった内容ではありません。あしからず。。

ARMテンプレートのTipsについて

  • Azure リソース マネージャー テンプレートを設計するためのベスト プラクティス
  • テンプレートに利用できる式や関数
  • テンプレート全般
  • テンプレートリンク
    • templateLinkのほかにもパラメーターや変数もリンクできます。活用しましょう。
    • 公式(?)のQuick Templateなどは多用してますね。まぁストレージとか大きなリソース単位で分けておけば再利用しやすいです。
  • copyとcopyindex()
    • 一部リソースプロパティ(ロードバランサーのinboundNatRulesとか)は使えません
    • inboundNatRulesで使えないということは各インスタンスに直接接続するためのRDPの口を用意するのが難しいということです。この場合だと明示的にVM0用、VM1用とべた書きすればもちろんOKですけどありえないですよね。(インスタンス数固定ならまぁ。。。)※まぁそもそもそういうことしないほうがいいよねというのはある
    • ハンズオンではLBしてもいいからとりあえずRDPの口はあけてます。他のインスタンスは多段してね☆
  • apiVersion
    • Scheme
    • 結構はまるポイントです。注意しましょう。
  • タグ
    • タグは活用しましょう。別で書こうと思いますがポリシーとかにも使えるし。
    • あとConcatとか活用しだすとVisual Studioでいじってるときとか結構ひどい見た目になるので、キーがdisplayNameでタグ付けして表示名をつけてあげるといいかと思います。
  • PowerShell DSCの話はざっくりしかしてません(Windowsの場合)
    • 認証情報の渡し方はprotectedStringsとPrivateSettingsRefあたり活用すればいいかと
    • DSC側のConfigrationもだいぶ無茶してる感あります。。本番で使うにはもうちょっときれいにしたほうがいいでしょう。Scriptとか、、、ひどいコードですみません。そのまま使えないことはないですがきれいじゃないなぁ
    • システム全体のオーケストレーションは別途考えてみてください。
    • 今見直したらアプリケーション固めたZipのURLとか決めうちしちゃってるので、ARM Templateから渡すようにしたりとかしておけばよかったですね。
  • リソース固有情報(resourceGroup().idとか)はうまく活用してください。
  • Azureポータル上でもリソースエクスプローラーはあるのですが(参照からどうぞ)、外部のサイトのほうができること多いです。どういうプロパティ・値を指定したらいいのか不明な時は手動でデプロイしてからリソースエクスプローラーでごにょごにょ参照するといいかと思います。
  • AzureResourceVisualizerとか意外と便利かもですね。node.jsでローカルで動かせますよ

あとは何だろう、CloudFormationのTipsなども参考にするといいかもしれませんね。ただまぁJSONをべたべた書くのはなかなか苦行なのでVisual Studio使うのがいいかと思います。。。