タイトルの通りですが、最近 Azure Functions の Consumption Plan を利用しているアプリケーションが、リロードを繰り返すと稀に 404 を返す現象に遭遇しました。この時の 404 はアプリケーションが返しているものではなく、App Service が存在しない場合に返されるページです。
ランダムで発生するので調べたところ、この現象が発生する Azure Functions は IP アドレスが 2 つ返されることが確認出来、更に片方の IP アドレスが選ばれた場合に 404 となることが分かりました。
Azure Portal や Azure Resource Manager から確認出来る Inbound IP Address は 1 つだけですが、実は Azure Functions の Consumption Plan や Elastic Premium Plan (Functions Premium) は今回のように複数の Inbound IP Address を持つことがあります。
本来 App Service は 1 つの App Service Plan に対して 1 つの Stamp (Scale unit) が割り当てられるため、1 つの Inbound IP Address しか持たない仕組みになっていますが、Consumption Plan と Elasitc Premium Plan (Functions Premium) では複数の Stamp に割り当てられることがあるため、その場合には Inbound IP Address が複数返ってくるという仕組みです。
この挙動によって所属する Stamp のキャパシティが不足している場合でも、他の Stamp を利用することで Consumption Plan や Elastic Premium Plan のスケーリングが行えるようになりますが、特定の Stamp で正しく Function App がプロビジョニング出来ていない場合に 404 となります。
複数の Stamp を利用しなければ良いので、App Settings に WEBSITE_DISABLE_CROSS_STAMP_SCALE
設定を追加すると Inbound IP Address が 1 つになるため問題は解消します。
この設定は名前の通り複数の Stamp を使ったスケーリングを無効化するものなので、追加すると 1 つの Stamp だけを使ってスケールを行おうとします。無効化するとキャパシティが不足した場合にスケーリングに制限が出る可能性があります。
該当の Function App にこの設定を追加すると、以下のように Inbound IP Address が 1 つだけ返ってきます。
返ってきた Inbound IP Address は正しく Functions App がプロビジョニングされた Stamp となるため、リロードを繰り返しても 404 が返ってくることは無くなりました。複数の Stamp を利用してスケーリングが行われることを知っていると問題の特定が楽でした。
この複数 Stamp が利用される挙動については Azure Files の利用が必須になっているため、Azure Portal から Function App を作成する際に Azure Files を追加しなかった場合には無効化されるはずです。
この辺りについては以下のドキュメントで記載されていますが、複数 Stamp を利用する場合はコンテンツの共有に Azure Files が必須なのが理由です。Consumption Plan で Azure Files を使わない場合はスケーリングが制限されると明記されています。
Since Azure Files is used to enable dynamic scale-out for Functions, scaling could be limited when running your app without Azure Files in the Elastic Premium plan and Consumption plans running on Windows.
Storage considerations for Azure Functions | Microsoft Learn
但し Windows が対象になると書いてある通り、Linux には影響しないようです。Linux の Consumption Plan はアーキテクチャが Windows の Consumption Plan とは別物になっているのが理由だと思われます。
今回の問題とは関係ないのですが、複数 Stamp を利用する設定の場合は以前に以下のエントリで動作を検証した IPv6 対応が、現在では正しく動作しなくなっているようです。
複数 Stamp を使わない設定を入れると動作するようでしたので、以下の通りいくつかの組み合わせで動作確認を行ってみましたが、現状では IPv6 を有効化する場合は複数 Stamp を使わない設定を入れないと意図した動作になりませんでした。
WEBSITE_DISABLE_CROSS_STAMP_SCALE
設定なし + IPv4AndIPv6
WEBSITE_DISABLE_CROSS_STAMP_SCALE
設定あり + IPv4AndIPv6
WEBSITE_DISABLE_CROSS_STAMP_SCALE
設定あり + IPv6
7 月に確認した時点では特別な設定なしに正しく動作していたので、内部的なアップデートが行われている可能性もありそうです。App Service のスケーリング周りについて多少なりとも理解をしていないと、今回のように意外にはまることがあるということでした。