しばやん雑記

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

Azure Functions (Premium / ASP) から Private Endpoint を使う際に必要な設定

Twitter にて SQL Server と金麦で有名なムッシュが Premium Plan で WEBSITE_VNET_ROUTE_ALL が使えないと呟いていて、いろいろ気になったので環境を作って試してみました。

WEBSITE_VNET_ROUTE_ALL は Private Link や Route Table などを使う際に必要となる設定です。この辺りについては以前書いたので、そっちを参照してください。

実際に Premium Plan で検証環境を作成してみると、最初は動いたように見えましたが、再起動などのタイミングで動かなくなってしまいました。

検証を進めると Premium Plan に限らず、App Service Plan でも同様の問題が発生することが分かりました。

ちなみに今回テストに使用したのは以下のような Function です。Private Endpoint を有効にしてある Blob Storage に置いてある画像をプロキシするだけの簡単なものです。

#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

static HttpClient httpClient = new HttpClient();

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    var stream = await httpClient.GetStreamAsync("https://appprivateendpointtest1.blob.core.windows.net/sample/shibayan.jpg");

    return new FileStreamResult(stream, "image/jpeg");
}

検証しているうちに Private Endpoint を使うサンプルを見つけたので、根本的な原因も大体わかってきました。具体的には Function Key などを保存している Blob Storage へアクセス出来ていないのが原因でした。

必要な情報を読み込めていないのに Host 自体は立ち上がるのは微妙な挙動です。一応は解決策を 2 つ見つけたので、この後はそれぞれについて簡単に説明をしておきます。

別の Storage Account を作成して Private Endpoint を追加する

サンプルでは AzureWebJobsStorageWEBSITE_CONTENTAZUREFILECONNECTIONSTRING をそれぞれ別の Storage Account として用意して、AzureWebJobsStorage 側に Private Endpoint を作成しています。

AzureWebJobsStorage は Function Key などの実行に必要な情報を格納するために使われています。

Azure Portal から作成すると同じ Storage Account が設定されますが、実際には同じである必要は全くないのと、AzureWebJobsStorage は Azure Functions Runtime が参照するため、Private Endpoint を有効にしても問題なくアクセス出来るという仕組みです。

適当に Storage Account を作成して AzureWebJobsStorage の値を上書きしておきます。

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

そして以下のように AzureWebJobsStorage に指定した Storage Account に対して Private Endpoint を作成すると、Azure Functions Runtime からアクセス出来るようになるため、WEBSITE_VNET_ROUTE_ALL を有効にした状態で各 Function が動作するようになります。

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

Function Runtime が起動したタイミングで必要なファイルは自動的に生成されます。この時、各キーは新しく作成されるため Function Key や Master Key は値が変わるので注意が必要です。

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

Private Endpoint を使うために Private Endpoint の追加が必要になるというのは、若干混乱しそうです。

Subnet で Service Endpoint を有効化する

個別に Private Endpoint を作成するのは割と手間ですし、Function の状態までも Private Endpoint にしなくてもよい良いケースもあると思います。その場合は Service Endpoint を有効にするのがお手軽です。

App Service が Regional VNET Integration で追加されている Subnet に対して、Microsoft.Storage の Service Endpoint を有効化するだけです。Storage Account を分ける必要はありません。

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

Storage Account に対して Firewall の設定を追加すると App Service にマウント出来なくなって動かなくなるので、Firewall Rule の追加はせずに Service Endpoint だけを有効化します。

Subnet に対して Service Endpoint を有効化すると、ルーティングが変化してアクセス出来るようになります。このあたりの挙動がドキュメントに書かれているのか把握はしていません。

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

テストすると問題なく Private Endpoint 経由で画像にアクセスできることが確認できます。

Service Endpoint を有効化しないままだと動かないのは謎ですが、App Service の Regional VNET Integration 自体が謎テクノロジーで作られているので仕方ない感はあります。

この場合は Azure Functions と同時に作成された Storage Account はこれまで通りパブリックのままです。そこも Private Endpoint にしたい場合は上の例のように Storage Account を分けてください。

Runtime Scale Monitoring の設定には注意

Premium Plan と Regional VNET Integration を同時に使うと、Azure Portal にある Runtime Scale Monitoring という設定が重要になってきます。

Azure Functions は Scale Controller が外部にあって、Storage Queue や Service Bus のメッセージを監視してスケーリングする仕組みになっていますが、それらのリソースが Private Endpoint などで塞がれると Scale Controller が必要なメトリックを取れなくなります。

従って Premium Plan 向けに Function Runtime 側がスケーリングに必要なメトリックを返す仕組みが追加されました。それが Runtime Scale Monitoring です。

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

ドキュメントにあるように、新しい Extension バージョンが必要になるので、古いバージョンを使っている場合はちゃんとアップデートしておきましょう。

Premium Plan と Regional VNET Integration を組み合わせて使う際は設定に気を付けましょう。