しばやん雑記

Azure Serverless とメイドさんが大好きなフリーランスのプログラマーのブログ

2020 年 8 月の Azure Functions Live で発表されたアップデート

2020/8 の Azure Functions Live でかなりインパクトの大きいアップデートについて話があったので、触れておきたいと思います。Azure Functions でイマイチだと思っていた部分がかなり改善されているので、今後は使うのが当たり前になりそうな機能ばかりです。

例によって自分の興味ある部分しか触れないので、YouTube で本編をちゃんと見ておいた方が良いです。

新機能と今後の予定でいくつか紹介されていますが、以下の 6 つに絞って試した結果をまとめておきます。まだ何も公開されていなさそうですが、OAS から Function を作るのは結構面白そうです。

特に Configuration や Checkpoint control などは全ユーザー待望だと思うので嬉しいです。

ReadyToRun

Tiered Compilation は Function Host では有効化されていませんが、Function App での ReadyToRun 済みアセンブリの読み込みに対応したようです。Function Host 自体は R2R でビルドされています。

実際にどのくらいの効果があるかは検証中ですが、原理上は悪くなることはないかなと思っています。規模の大きい Function の方が効果が出やすそうです。

この辺りの情報は以前書いたので適当に参照しておいてください。

ドキュメントにあるように csproj に 2 つ設定を追加すると、発行時に自動的に ReadyToRun 済みのアセンブリを作成してくれます。R2R には多少時間はかかりますが、最近のマシンだと無視できるレベルでしょう。

f:id:shiba-yan:20200822234056p:plain

csproj に単純に足すと、デバッグ実行時にも ReadyToRun を行ってしまうので、CI などで dotnet publish の実行時のみ ReadyToRun 済みアセンブリを作成するという戦略が良いでしょう。

以下のような単純なコマンドで ReadyToRun を行いつつビルドできます。

dotnet publish -c Release -o ./publish -r win-x64 -p:PublishReadyToRun=true

ドキュメントでは RID として win-x86 を使っていますが、Function SDK に問題がありインストールされている .NET Core の bitness に合わせないと正常にビルド出来ません。

原因は extensions.json の生成時にアセンブリを読み込む仕組みになっていますが、当然ながら bitness の違う ReadyToRun アセンブリは読み込めないためです。

殆どの開発者は x64 版 .NET Core をインストールしているはずなので、RID は win-x64 を指定する必要があるということです。解決には時間がかかりそうな気がします。

IFunctionConfigurationBuilder

Azure Functions ユーザー待望の Configuration カスタマイズ機能がついに提供されました。

これで ASP.NET Core でお馴染みの appsettings.json を使って設定を自由に読み込めるようになりました。local.settings.json は特殊なのでオブジェクトを書けなくて結構辛かったです。

App Service Plan 以外で Binding / Trigger の接続文字列などを変更しようとすると、Azure Portal に以下のようなエラーが表示されて Function Host が起動しなくなります。

f:id:shiba-yan:20200822232527p:plain

これは Scale Controller が外にいる構造上、仕方ない挙動です。ただし Premium Plan + Runtime Scale Monitoring が有効なら Scale Controller がリソースにアクセスする必要が無いので、このあたりの制限を緩和出来ないか提案をしています。

制限が緩和されれば VNET Integration を使いつつ、Key Vault に Service Endpoint or Private Endpoint を追加してアクセス元を絞ることが出来るようになるはずです。

ドキュメントなどでは IFunctionsConfigurationBuilder が待望の機能過ぎて扱いが雑になっていますが、今回 FunctionsHostBuilderContext というクラスも追加されて、Startup 内で以下の情報を簡単に参照できるようになりました。

  • ApplicationRootPath
  • Configuration
  • EnvironmentName

特に ApplicationRootPathConfiguration を触れるようになったのは、非常にありがたいです。

これにより Startup 内の Options パターンが非常に扱いやすくなっています。正直なところ、これまで IConfiguration を取る手段がなかったのがハードモード過ぎました。

拡張メソッドとして用意された GetContext を呼び出すと、ConfigureConfigureAppConfiguration の両方で参照できます。

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        var context = builder.GetContext();

        builder.Services.Configure<SampleOptions>(context.Configuration.GetSection("Sample"));
    }
}

public class SampleOptions
{
    public string Value { get; set; }
}

これですっきりしましたね。自分で ConfigurationBuilder を使って組み立てる必要が無くなったのはかなり良いです。これでやっと DI をフルに使った Azure Functions の開発が行いやすくなった感あります。

ただし Configuration の値は ConfigureAppConfiguration の時点では完全な情報ではありませんので、Key Vault を参照する場合は ASP.NET Core の場合と同様に一度 Build する必要があります。

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
    }

    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        var builtConfig = builder.ConfigurationBuilder.Build();

        var tokenProvider = new AzureServiceTokenProvider();
        var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(tokenProvider.KeyVaultTokenCallback));

        builder.ConfigurationBuilder.AddAzureKeyVault(builtConfig["KeyVaultEndpoint"], keyVaultClient, new DefaultKeyVaultSecretManager());
    }
}

これで Key Vault に保存された Secret を Managed Identity を使って読み込むことが出来ます。

App Service に用意されている Key Vault Reference では Service Endpoint / Private Endpoint を越えられませんが、アプリからの場合は問題なくアクセス出来ます。

Per app scale limits for all plans

これまでも WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT という設定がプレビューで提供されていましたが。新しくちゃんと動く設定が追加されたようです。

All plans と言っているので App Service Plan でも使えそうな気がしますが、軽く試した感じではちゃんと動いてなさそうでした。Consumption / Premium Plan 限定かもしれません。

ドキュメントにあるように SQL Database など接続数の上限が存在するサービスを利用する場合に、スケールアウトの上限を設定できるのは安心という感じです。

Durable Functions monitoring in portal

Durable Functions を使っている人にとっては待望の Orchestrator のモニタリングが Azure Portal で行えるようになりました。モニタリングのソリューションはいくつかありましたが、どれも決定打に欠けました。

今回のリリースで Azure Portal から設定不要でモニタリング出来るようになったのはかなり大きいです。

f:id:shiba-yan:20200822221433p:plain

既に完了している Orchestrator についても Running と表示されていますが、正直大した問題ではありません。使われている KQL が修正されれば終わるような話です。

一覧から日付を選ぶと、Orchestrator の実行ログをさらに細かく見ることが出来ます。この辺りはフィードバックで良くなっていく部分だろうと思います。

f:id:shiba-yan:20200822221441p:plain

Azure Portal に組み込まれたという点が非常に重要なので、これからの進化に期待しています。

Restrict storage to VNet

Function App のバックエンドで使われている Storage Account に対して、Service Endpoint や Private Endpoint でアクセス制限を行うと正しく動作しない問題があります。

ドキュメントにも Storage Account に対して Service Endpoint を追加しないように書かれています。

Service Endpoint に関しては使えるようになっている気がします。対応済みかもしれません。

とはいえ App Service の Regional VNET Integration は他のサービスに比べて挙動が特殊なことが多いので、事前に動作確認をしておく必要があります。

特に Private Endpoint が絡むとさらに複雑になる傾向にあります。

Checkpoint control for Event Hubs / Cosmos DB

Checkpoint control と言ってはいますが、早い話リトライについてです。Function 自体にはそもそもリトライという概念はなく、Queue でのメッセージ再追加や Event Grid 側のリトライに任せるなど、外部サービスを使う形で行われていました。

特に困っていたのが Cosmos DB で、Change Feed の処理が失敗した場合にはリトライなどは行われず、そのまま次の処理に進んでしまう問題がありました。それが以下の PR で解消されようとしています。

というか、何故失敗しているのに Change Feed が先に進むのだという感想しかないですが、これまではアプリケーション側にリトライを実装するという形で乗り切ってきたのが不要になります。

設計としては外部サービス側にリトライを任せた方が美しいですが、現実問題として Event Hubs と Cosmos DB の場合はどうしようもなかったということでしょう。割と待望の機能です。