しばやん雑記

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

Azure Portal の Resource Manager に便利機能が用意されている話

少し前から Azure Portal のトップページにある Resource groups を選択すると、単純にリソースグループの一覧が表示されるだけではなく、Resource Manager という専用のブレード内にあるリソースグループ一覧が表示されるようになりました。ナビゲーションからも Resource Manager として検索すると直接飛べるようになっています。

この Resource Manager というブレードは名前からわかるように Azure の足回りに関係する項目がまとまっています。単純にリソースグループや管理グループの一覧が表示出来るわけではなく、Tools に非常に便利な機能が揃っています。

実際のところ、これまでも Azure Portal の何処かには存在していたのが集約されただけっぽさはありますが、Resource Manager という項目でまとまっていることが非常に重要です。特に個人的には Resource Graph Explorer と Resource Explorer がマニアックですが特別便利だと感じています。ARM API Playground は az rest でも実現出来ますが、ブラウザで出来た方が認証面含めて楽なので痒い所に手が届く機能です。

ここからは簡単にそれぞれの機能について説明しておきます。ぶっちゃけ Resource Explorer と ARM API Playground について書きたかっただけです。

Resource Graph Explorer

既に知っている人も多いはずですが、Resource Graph Explorer が検索で辿らなくても Resource Manager から簡単にアクセスできるようになりました。Resource Graph は Azure Portal でも使われているリソース検索のための機能です。シンプルに言ってしまえば Azure リソースに対して KQL でクエリを実行できる機能です。

KQL が使えるのでリソースの設定値などプロパティの値に対して検索を実行できるのが特徴です。昔は KQL を覚えるのが大変でしたが、今は LLM に任せることが出来るので使うシナリオは増えているかと思います。

アップグレードや移行が必要なリソースを検索するのに便利です。実際に Azure Advisor の Workbooks では Resource Graph をフル活用してサービスのリタイアと関係するリソースの一覧を出しています。

Resource Explorer

個人的に一番使っていたサービスですが、独立したアプリケーションとして提供されていた Resource Explorer が Azure Portal に組み込まれました。UI はシンプルになってしまいましたが、リソースの JSON を直接編集できるので Azure Portal で設定できないプロパティを直接弄るのに使います。

Azure Portal では殆どのプロパティがちゃんと UI で変更可能になっていますが、App Service のような機能が多いサービスは UI が間に合っていないケースが存在し、特に困るのは認証の設定が Azure Portal では一部しか用意されていないことです。

この authsettingsV2 は設定値が多くて Azure CLI で変更するのが大変なので、一部だけ変更できる Resource Explorer はかなり便利に使えます。本番環境の構築では ARM Template や Terraform を使うので問題はないのですが、動作検証や PoC などでサクッと試したい時に重宝します。

ARM API Playground

Resource Explorer でほぼ同じことが実現出来ますが、Azure Resource Manager の REST API を直接叩きたい時には ARM API Playground が使えます。古い Resource Manager には Raw モードという同じような機能が用意されていましたが、ARM API Playground で同じことが出来ます。

Azure CLI の az rest で全く同じことが出来ますが、やはりブラウザ上で実行出来るのは非常に便利です。Azure CLI のインストールが必要なく、テナントの切り替えも容易なのはかなりのメリットです。

膨大にある REST API を直接実行したいというシナリオは正直あまりないと思いますが、こういった低レベルな API 呼び出しが行える環境があるというのは安心感があります。

Resource Explorer では VM の停止や Azure Functions のトリガー同期といった処理は実行できないため、そのような場合には ARM API Playground が利用できます。マニアックですが意外に便利な時があります。

Azure Container Apps Dynamic Sessions の MCP サポートを使って Code Interpreter を簡単に実現する

Ignite 2025 で発表された機能で個人的にかなり気になったのが Dynamic Sessions の MCP サポートです。これまでも LLM に Python コードを生成させて Dynamic Sessions で実行するという処理を書いたことはあるのですが、MCP として API が提供されているため簡単に Code Interpreter を組み込めるようになりました。

使い方は以下のブログが詳しいですが、Foundry Agent かつ Shell での利用なので若干ニッチな使い方をしています。今回はよりオーソドックスな Python で試してみます。

Dynamic Sessions を知らない方もいるとは思うので、詳細は以下のドキュメントを参照してください。ざっくり言うと Container Apps の実行基盤を利用して、サンドボックス環境下で Python などのコードを実行するサービスです。安全な環境でコードの実行が行えるので、LLM が生成したコードも安心して実行できます。

これまでは LLM に Python のコードを生成させて、その結果を Dynamic Sessions の API を経由して実行するという流れでしたが、MCP ツールとして提供されているので処理の途中に組み込むことや、コード生成を行って実行が必要なのかを LLM 側に判断させることが可能となりました。

現在 Dynamic Sessions の MCP を有効化するには ARM Template を使う必要があるため、以下のような Bicep を作成して ARM Template にコンパイルしてデプロイしました。

param name string = 'sessionpoolsample'

resource sessionPool 'Microsoft.App/sessionPools@2025-10-02-preview' = {
  name: name
  location: 'Japan East'
  properties: {
    poolManagementType: 'Dynamic'
    containerType: 'PythonLTS'
    scaleConfiguration: {
      maxConcurrentSessions: 5
    }
    sessionNetworkConfiguration: {
      status: 'EgressEnabled'
    }
    dynamicPoolConfiguration: {
      lifecycleConfiguration: {
        lifecycleType: 'Timed'
        cooldownPeriodInSeconds: 300
      }
    }
    mcpServerSettings: {
      isMcpServerEnabled: true
    }
  }
}
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "metadata": {
    "_generator": {
      "name": "bicep",
      "version": "0.39.26.7824",
      "templateHash": "10140790373505388271"
    }
  },
  "parameters": {
    "name": {
      "type": "string",
      "defaultValue": "sessionpoolsample"
    }
  },
  "resources": [
    {
      "type": "Microsoft.App/sessionPools",
      "apiVersion": "2025-10-02-preview",
      "name": "[parameters('name')]",
      "location": "Japan East",
      "properties": {
        "poolManagementType": "Dynamic",
        "containerType": "PythonLTS",
        "scaleConfiguration": {
          "maxConcurrentSessions": 5
        },
        "sessionNetworkConfiguration": {
          "status": "EgressEnabled"
        },
        "dynamicPoolConfiguration": {
          "lifecycleConfiguration": {
            "lifecycleType": "Timed",
            "cooldownPeriodInSeconds": 300
          }
        },
        "mcpServerSettings": {
          "isMcpServerEnabled": true
        }
      }
    }
  ]
}

設定としては isMcpServerEnabledtrue にするだけなので非常に簡単です。ちなみに Japan East でも問題なく有効化して利用出来ています。

デプロイが完了すれば MCP のエンドポイントと API キーを取得すれば、各種 MCP に対応したクライアントから利用できます。エンドポイントは Azure Portal の JSON View から確認するのが一番楽です。

アクセスに必要な API キーは Azure CLI を使って直接 REST API を叩くしかないようなので、ブログにあるように以下のコマンドを実行して取得する必要があります。この辺りは Azure Portal から確認出来るようになって欲しいですね。既に RBAC でのアクセスも出来るようですが、設定が分からないので試してはいません。

az rest --method POST --uri "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.App/sessionPools/$SESSION_POOL_NAME/fetchMCPServerCredentials?api-version=2025-10-02-preview" --query "apiKey" -o tsv

このコマンドで取得した API キーは x-ms-apikey というヘッダーで渡す必要があるので、GitHub Copilot Chat の場合は mcp.json ファイルで以下のように headers で API キーを指定すれば問題ありません。

{
	"servers": {
		"my-mcp-server-ddaf56e8": {
			"url": "https://japaneast.dynamicsessions.io/subscriptions/***/resourceGroups/***/sessionPools/***/mcp",
			"type": "http",
			"headers": {
				"x-ms-apikey": "***"
			}
		}
	}
}

設定後にサーバーを起動すれば以下のように 2 つの Dynamic Sessions MCP が提供するツールが確認出来ます。Dynamic Sessions は環境の作成と実行という二つの処理が必要なので、それぞれで MCP ツールが用意されているわけです。

それぞれの MCP ツールにはかなり長い説明が付けられているので、独自の MCP ツールを作る際の参考にもなりそうです。問題なくツールも認識されたので Copilot Chat から実行を試してみます。

ツールが正しく認識していれば、以下のようにコードの生成と実行までを自動的に行ってくれます。

Python コードの実行結果を確認すると、以下のように stdout に計算結果が出力されていることが確認出来ます。この結果を基に応答が生成されていることも同時に確認出来ます。

Dynamic Sessions は出力結果からわかるように stdoutstderr を返すようになっているので、生成されたコードが stdout に出力するようになっていないと、出力が空で返ってくるので注意が必要です。

明示的にコードの実行結果を stdout に出力するように指示する必要が出てくるケースもあります。この辺りはシステムプロンプトで定義しておくのが無難です。

Microsoft Ignite 2025 で発表された App Service / Azure Functions / Container Apps のアップデート

毎年恒例になりつつありますが、今年も Ignite 2025 で Azure でも特に PaaS / Serverless 領域でのアップデートが多く発表されたので、特に自分が気になる点を中心にまとめておきます。

最近では App Service などを含めて Azure Application Platform と呼ばれていますが、Ignite 2025 でのアップデートは以下でまとめられています。

個人的には API Management 関連のアップデートが多いと感じています。Premium v2 が GA していたり、A2A や MCP といった AI 関連機能がさらに追加されているのが特徴的です。

今回メインとなる App Service 関連のアップデートですが、以下のようになかなかの量があります。Azure Functions と Container Apps は AI 関連の機能が相変わらず多めです。

ここから先は各サービスごとに気になるアップデートを細かく見ていきます。

App Service

これまで通り App Service は順当なアップデートが行われていますが、今回は Managed Instance が一番大きなアップデートとなります。それ以外には .NET Aspire のサポートや App Service on Linux での Log stream 改善や、言語バージョンのアップデートなどが中心です。

まだ機能はリリースされていませんが、2026 年には Linux での Outbound IPv6 サポートや Private Endpoint のカスタムドメインサポートなどが予定されているようなので期待です。ASEv3 も今後アップデートが行われていくようです。

Managed Instance が Public Preview

今回のメインとなる App Service の Managed Instance が Public Preview として公開されました。そもそも App Service は Managed だろと突っ込みたくはなるのですが、立ち位置としては昔懐かしの Cloud Services のようにスクリプトによって VM のカスタマイズが行えるオプションという感じです。

カスタマイズ用のスクリプトをデプロイしたり、レジストリキーを変更するといった処理が Cloud Services の時よりも安全に行えるようになっています。Bastion 経由での RDP にも対応しているところが更に Cloud Services っぽいです。

ASEv3 でも良いのではという気はしますが、GAC やアプリケーションのインストールが行える点が Managed Instance の特徴です。Windows Containers でも同様のことは行えましたが、直接 VM に対して構成を行う点が大きく異なっています。

個人的にはあまり積極的に使うサービスではなく、あくまでもオンプレの VM からの移行時に役立つサービスだと認識しています。

Async Scaling が Public Preview

これまでの App Service のスケーリングは実際にインスタンスを確保し終わるまでブロッキングを行っていたようで、一時的なキャパシティ不足の時にはスケーリングに失敗するといった挙動になっていたようです。

今回の Async Scaling では名前の通り非同期でスケーリング処理を行うため、インスタンスの確保が完了するまで待つのではなく、バックグラウンドで指定された台数まで増やすといった処理になるようです。

このような動作によって、最近のキャパシティ不足でのスケーリング失敗を回避できるようになるようです。元々非同期でスケーリングしてると思っていたので、個人的にはこちらの挙動の方がしっくりきます。

Custom Error Pages が GA

App Service の前段にいるリバースプロキシが YARP に置き換えられた時にプレビューとなったカスタムエラーページですが、ようやく GA となりました。App Service がシステムで返すエラーページをカスタマイズ出来るため、懐かしさすらあるデザインのページをユーザーに見せないように出来ます。

Terraform などの IaC ツールとの相性がイマイチ悪そうという思っているので、個人的にはあまり使わないかも知れませんが、ブランディングという観点では設定しておいて損はないでしょう。

Azure Functions

ここ最近は AI をターゲットにしたアップデートが多かった Azure Functions ですが、今回も AI をターゲットにしてはいますが MCP と Durable Functions 関連がメインとなっていて、なかなか魅力的なアップデートとなっています。

Durable Functions の基盤となっている Durable Task Framework の適用範囲が Agent Framework にも広がり、更に実行を支えるための Durable Task Scheduler も GA したことで Serverless Agent の本番運用の準備が整ったという印象です。

今後も Azure Functions の重要性が高まることを感じさせるアップデートという印象です。

MCP Trigger / Binding が GA

今年で一番の機能だと思っている Azure Functions の MCP Trigger / Binding ですが、GA したことで安心して本番向けにも使えるようになりましたし、C# 以外の言語でも Streamable HTTP を使えるようになったので扱いやすくなっています。

MCP サーバーを Flex Consumption 上で Self hosting する機能は Preview ですが、個人的には Container Apps などでホストした方が良いのではという気持ちがあります。

GA 後もこの MCP 拡張は開発が積極的に行われていて、最新のコミットでは enum のサポートや MCP Tool の実行結果として画像などを返せるようになっています。

Authentication で OAuth 2.0 PRM サポートが Public Preview

既に以下の記事で書きましたが、App Service Authentication で OAuth 2.0 の Protected Resource Metadata に対応したので、MCP クライアントが自動的に認証を行って安全に MCP Tool を使えるようになりました。

現時点の Entra ID は Dynamic Client Registration に対応していないので、手動で Entra ID にアプリケーション登録が必要ですが、Visual Studio Code では Entra ID でログインして安全に利用できることを確認済みです。

Flex Consumption で Rolling Update が Public Preview

既に Flex Consumption は GA していますが、これまでダウンタイム無しのデプロイでよく使われていた Deployment Slot に対応していなかったため、運用で悩んでいたケースもあると思います。今回のアップデートで Rolling Update に対応したので Deployment Slot を使わずとも安全にデプロイ出来るようになりました。

これまでの挙動となる Recreate と Rolling Update の違いは公式ドキュメントが分かりやすいので、必ずこちらを確認してから設定するか検討してください。

設定から Rolling Update を選択すると、次からのアプリケーションデプロイ時にインスタンスが順次アップデートされるため、古いコードと新しいコードが同時に動作するタイミングが発生します。処理に互換性が無い場合は問題となる可能性が高いので慎重に選択してください。

Durable Task Extension for Microsoft Agent Framework が Public Preview

個人的に Serverless で AI Agent を実行する際の決定版だと思っている、Durable Task Extension for Microsoft Agent Framework が公開されました。名前の通り Durability を Agent Framework に追加する拡張ですが、長時間実行される AI Agent を確実に実行することや、途中で人間が介入する処理を実装出来ます。

これまでも Durable Functions の Activity を使って同じような処理を書いてきましたが、Agent Framework に強く統合されている点が大きく異なります。Agent Framework については深く書きませんが、Function Calling と MCP Tools を実装の中心に置くことによってよってかなり洗練されています。

Durable Task Scheduler の Dedicated が GA / Consumption が Public Preview

Durable Functions は非常に便利な機能なのですが、標準のストレージ実装では Observability が若干弱かったり、パフォーマンス面で上限があまり高くないというのが弱点でしたが、高性能かつモニタリングも充実している Durable Task Scheduler の Dedicated がついに GA しました。

コストは Azure Storage や Netherite を使っていた時よりは正直上がりますが、Task Hub で複数運用も出来るのでトータルコストは十分下げる余地がありますし、非常に使い勝手の良いダッシュボードが付いているので、本番運用時でも安心して利用できます。

今回 Dedicated が GA したタイミングで待望の Consumption が Public Preview として公開されました。まだ Azure Portal からはデプロイ出来ないようですが、1 アクション当たりの完全従量課金となっているため、小規模なワークロードや開発環境などで非常に便利に扱えるはずです。

課金の単位となっているアクションがあまりイメージが付かないと思いますが、以下のドキュメントで非常にわかりやすく説明されているので、Consumption を使う場合には必ずチェックしておいてください。

ざっくり計算で 1 カ月に 16 万アクション以上使う場合には Dedicated の方がお得になるようでした。本番で利用する際には事前にある程度見積もってから Tier を選択してください。

Container Apps

例によって AI 関連の機能が前面に打ち出されてますが、個人的にはプラットフォームとしてのアップデートがしっかりと行われているのが印象的です。Serverless GPU のリージョン拡張や Confidential Computing が Public Preview など AI 関連という感じですね。

恐らく Azure Functions でもサポートされていると思いますが、Container Apps で Durable Task Scheduler のサポートが GA となっているのも大きいです。スケーリング周りでの対応だと思いますが、これでゼロスケールまでの対応が行えるかと。

Dynamic Session の MCP サポートが Public Preview

Container Apps の基盤を利用して LLM が生成したコードを安全に実行可能な Dynamic Session ですが、組み込みの MCP エンドポイントが Public Preview となったので既存の AI アプリケーションに組み込みやすくなりました。デプロイ時に設定する必要がありそうですが、Dynamic Session は MCP 経由で使うのがベストでしたので手間が省けます。

独自のアプリケーションで Python のコードを実行して、その結果を更に LLM に返すことが出来るので LLM が苦手とする計算や集計といった処理を確実に行えるようになります。これはかなり便利な機能なので、積極的に組み込んでいきたいです。

Premium Ingress が GA

標準の Ingress はプラットフォーム側のリソースを使っている関係でパフォーマンスには限界がありましたが、Premium Ingress では独自の Workload Profile 上でホストできるようになるため性能を大きく上げることが可能です。

かなりのハイパースケールな環境が対象になるかと思いますが、標準の Ingress に足を引っ張られる可能性が無くなるので、大規模なアプリケーションでも安心して使いやすくなりますね。

Rule-based Routing が GA

リクエストのパスや FQDN によってどの Container App にルーティングを行うか定義出来る Rule-based Routing も GA です。Front Door や Application Gateway を使ってパスベースのルーティングを行っているケースでは、Rule-based Routing に切り替えた方がシンプルかつ柔軟に定義できる可能性があります。

FQDN によってルーティング先の Container App を切り替えられるので、マルチテナントのアプリケーションを実現する際に便利に使えるかと思います。

Flexible Workload Profile が Public Preview

Container App Environment には Consumption と Workload Profile の 2 つが用意されていますが、3 つ目の Flexible Workload Profile が Public Preview となりました。Workload Profile のようにインスタンスサイズを事前に定義して確保するのではなく、Consumption と同じ使い勝手で専用プールで動作し VNET を定義出来るようになります。

Consumption よりメモリの上限は増えていますが、Workload Profile のように大きなリソースを確保することは出来ません。Azure Functions と同じように Consumption を使っている場合は Flexible Workload Profile を使う方が追加のコストは乗ってきますがメリットが多いはずです。

Deployment labels が Public Preview

これまで Container Apps の Revision mode は Multiple が CI/CD のシナリオでは非常に使いにくいと思っていましたが、今回 Deployment labels が Public Preview となったので App Service などの Deployment Slot に近い形で扱えるようになりました。Deployment mode を Deployment labels に変更すると Azure Portal の表示も大きく変わるので最初は戸惑いそうです。

まだ試せていませんが、事前に Deployment label を作成しておいて、ルーティングを変更できる仕組みになっているので、使い勝手としても Deployment Slot に非常に近いのではないかと思っています。

既に公式の GitHub Action では特定の Deployment label に対してデプロイする機能をサポートしているようなので、簡単に試せる環境にはなっています。

Deployment Slot のように Swap ではなく Redirect label という機能になっていて、ルーティングを変更する仕組みのようなので、デプロイ時のフローについてはもう少し検討する必要がありそうです。

Azure Functions の OAuth 2.0 Protected Resource Metadata 対応で MCP サーバーを Entra ID 認証化する

開催中の Ignite 2025 に合わせて Azure Functions の Easy Auth で OAuth 2.0 の Protected Resource Metadata に対応したので、MCP サーバーの認証として Entra ID が使いやすくなりました。

詳細は以下のブログで紹介されていますが、肝心な具体的な設定方法が見当たらないため、実際に Visual Studio Code から Entra ID 認証で保護された MCP サーバーにアクセスする部分まで試しました。

今回は Visual Studio Code が持っている Entra ID アプリケーションで認証を行い、Azure Functions でホスティングしている MCP サーバーを使うようにします。Entra ID は Dynamic Client Registration に対応していないので、その部分だけは注意する必要がありました。

Azure Functions で Entra ID 認証の構成を行う

まずは Azure Functions に対して組み込みの Authentication を使って Entra ID 認証を構成します。基本的な手順はこれまで通りなので、以下のドキュメントの通りに行っていけばよいですが、API だという点だけは頭に入れておくと良いです。

Azure Portal から Authentication を構成する手順は Microsoft を選んで進めれば問題ありません。Client Secret 周りもデフォルトで特に問題ないので進めていきます。

今回、追加で必要な設定は Additional checks にある Allowed client applications だけになります。ここに Visual Studio Code の Client Id である aebc6443-996d-45c2-90f0-388ff96faa56 を追加してあげます。

Visual Studio Code の Client Id は以下のドキュメントで見つけることが出来ました。

これで Azure Functions の Authentication が Visual Studio Code 経由で発行された Bearer Token を正しく受け付けられるようになります。

OAuth 2.0 PRM の設定を追加する

次に MCP クライアントが認証に必要な情報を把握できるようにするために、OAuth 2.0 Protected Resource Metadata の追加設定を行っていきます。この機能が今回追加されたものとなり、設定は App Settings に WEBSITE_AUTH_PRM_DEFAULT_WITH_SCOPES という名前でスコープ名を登録します。

登録するスコープ名は Authentication の設定時に自動で作成された Entra ID アプリケーションの Expose an API から確認出来ます。ひとまずドキュメントにもあるように、この値をそのまま使えば問題ありません。

コピーしてきたスコープ名を Azure Functions の App Settings に登録するだけなので、設定自体は非常に簡単です。この設定を行うと /.well-known/oauth-protected-resource でメタデータが公開されます。

実際に設定を行った Azure Functions に対してメタデータのパスにアクセスすると、以下のような内容が返ってきます。これでメタデータを使って VS Code は認証を行ってくれるようになります。

今回は Entra ID で確認していますが、他のプロバイダーも利用できるのかは確認していません。プレビュー中は Entra ID 限定で有効になっている可能性はあります。

Azure Functions でキー認証を無効化する

最後に Azure Functions にデプロイした MCP サーバーでキー認証を無効化しておきます。少し前のバージョンから host.jsonwebhookAuthorizationLevel を指定することで、デフォルトのキー認証を無効化出来るようになっています。

設定の値として Anonymous を指定するとキー認証が無効になるため、デプロイを行うと MCP サーバーの利用には Entra ID 認証が必須な状態となっています。

Visual Studio Code から MCP サーバーへアクセスする

これで全ての設定が完了したので Visual Studio Code に作成した MCP サーバーを追加して、認証を含めた動作を確認していきます。MCP サーバーの追加はコマンドパレットから行っていきますが、エンドポイントを入力すると以下のように認証を VS Code から要求されます。

このダイアログで Allow を選択すると、Microsoft アカウントや組織アカウントでのログイン処理が走って、以下のようなポップアップが表示されます。これは VS Code の Entra ID アプリケーション経由で MCP サーバーへのログインを行っています。

次へを選択すると MCP サーバーとして登録している Entra ID アプリケーションへのアクセスを許可するポップアップになるため、ここで承諾を選択すると Entra ID 認証が完了してトークンが無事に発行されます。

もちろんこれは最初の 1 回だけ表示されるポップアップになるので、次回のアクセスからは自動的に Entra ID 認証が完了するはずです。

無事に Entra ID 認証を使って MCP サーバーへのアクセスが行えれば、MCP ツールが認識されるはずです。以下のように 1 tools と表示されているので、問題なくアクセスが行えていることが分かりますね。

実際に Copilot Chat を使って MCP サーバーを使って処理を試してみましたが、以下のように正しく MCP ツールを呼び出して処理が行えています。

組み込みの Authentication を使っているので、MCP ツール側ではアクセスしているユーザーの情報は HTTP ヘッダーで取得出来ます。少し Entra ID 周りの知識が必要にはなりますが、扱いにくいマスターキーを使うことなく Bearer Token で認証が行えるのはかなり良いですね。

当然ながらクレームも MCP ツール側で取得出来るため、RBAC も簡単に実現できるかと思います。

App Service / Container Apps / Static Web Apps の Entra ID 認証を Managed Identity でシークレットレス化する

意外に昔から使えるようになっていたようですが、App Service Authentication で Microsoft Entra ID 認証を使う際に必要だった Client Secret を、Managed Identity を使うことで不要に出来る機能が追加されていました。

現状はプレビュー扱いのようですが、ドキュメントもひっそりと更新されていました。

Entra ID 認証を使うと Client Secret は推奨の有効期限が 180 日となっていますし、以前は期限なしにも出来ましたが現在は最長でも 2 年までとなっているため、定期的な更新が必須となっていますが、Managed Identity を使うと Client Secret 自体が必要無くなるため更新も必要無くなります。

Bicep を使って自動化する方法が以下のブログで紹介されていますが、肝となる部分は Entra ID のアプリ登録で Managed Identity を Federated Credentials として登録していることです。

ちなみに Azure Portal からの App Service Authentication の設定時に既存の Entra ID アプリケーションを選ぶと Managed Identity を使う方法で構成されるようです。新しい Entra ID アプリケーションを作成する場合にはこれまで通りの Client Secret を使う方法になります。

実際に Azure Portal で新しく Entra ID アプリケーションを作成し、Client Secret を使う方法から Managed Identity を使う方法に切り替えてみます。App Service Authentication の設定自体はこれまで通り行います。

後で Managed Identity に切り替えるので Client Secret の期限は適当で問題ありません。とりあえず推奨の 180 日にしておけば良いです。

Azure Portal から App Service Authentication の設定が完了すると、App Settings には MICROSOFT_PROVIDER_AUTHENTICATION_SECRET という名前の設定が追加され、この設定に Client Secret が入っているのでこれを削除するのが今回の目標となります。

この後は User-Assigned Managed Identity を作成して、必要な設定を行っていきます。まずは適当な名前で User-Assigned Managed Identity を作成して、App Service Authentication の設定時に作成された Entra ID アプリケーションの Federated Credential として作成した UAMI を割り当てます。

GitHub Actions 向けに Federated Credential を使うのが流行った時には Managed Identity のドロップダウンは用意されていなかった気がしますが、今は以下のように選択肢があるので選択して UAMI の設定を行います。

User-Assigned Managed Identity を Federated Credential として追加すると、以下のような表示になります。

Entra ID アプリケーションに UAMI を紐づければ、後は App Service にも UAMI を割り当てて App Settings に追加すれば手順は完了です。まずは UAMI を割り当てますが、これはシンプルに Identity の設定から追加すれば良いので難しいことはありません。

App Service に UAMI を割り当ててしまえば、最後に OVERRIDE_USE_MI_FIC_ASSERTION_CLIENTID という名前で割り当てた UAMI の Client Id を App Settings に追加して認証の設定を更新します。Client Secret の設定であった MICROSOFT_PROVIDER_AUTHENTICATION_SECRET は必要無くなるため同時に削除しておきます。

認証の設定更新は以下のように Client Secret Setting Name として追加した App Setting を選ぶだけです。

このタイミングで App Service にアクセスすると Client Secret を使っていた時と同じように Entra ID 認証が通ることが確認出来ます。Client Secret を使わずに Federated Credential を使うため有効期限を完全に無くすことが出来ました。

最後に Entra ID アプリケーションの設定から Client Secret を完全に削除すれば終わりです。

今回は App Service を対象に行いましたが、Container Apps と Static Web Apps も同じ Authentication の実装を使っているのと、Managed Identity が利用できるので同じように Client Secret を使わずに Entra ID 認証が行えるので、更新期限を意識する必要がなくなります。

特に Static Web Apps についてはドキュメントが存在しなかったのですが、Managed Identity は使えるので実際に設定して確認したところ問題なく動作しました。

Azure Front Door と Static Web Apps の組み合わせでの最適なキャッシュ設定を探った

Static Web Apps を使って SPA アプリケーションをデプロイして運用していると、現状の Static Web Apps のリージョンが一番近くて East Asia になり日本からはレイテンシがそこそこ大きいので、Front Door を導入して全体的なパフォーマンスを改善したくなります。

特に最近のフレームワークはバンドルされるので、ファイル名がハッシュベースでユニークなものになるためキャッシュさせやすいです。今回は Nuxt 4 を使って Front Door での適切なキャッシュ設定を確認しました。

Nuxt 4 はビルドを行うと以下のように _nuxt ディレクトリ以下にバンドルされたファイルが入るので、このディレクトリ以下をキャッシュすると効果が出ます。それ以外の index.html などのファイルはキャッシュすると問題になるので無効化する必要があります。

バンドルされたファイル名にはハッシュベースでユニークなものが入るので、それぞれを Immutable なものとして扱えるためキャッシュしやすいのがメリットです。

これから実際に Static Web Apps と Front Door に設定を追加して、キャッシュを有効化していきます。

Static Web Apps で適切な Cache-Control を返す

ファイルやディレクトリ単位での柔軟なキャッシュを行うために Cache-Control を返す設定を SWA の設定ファイル staticwebapp.config.json に追加します。

設定方法としてはルート単位での追加と、グローバルでの追加があるので、上手く組み合わせて実現します。今回は以下のように _nuxt ディレクトリ以下はキャッシュを長時間行うように設定しますが、それ以外はキャッシュしないように設定を追加します。

{
  "$schema": "https://www.schemastore.org/staticwebapp.config.json",
  "routes": [
    {
      "route": "/_nuxt/*",
      "headers": {
        "Cache-Control": "max-age=31536000, immutable"
      }
    }
  ],
  "globalHeaders": {
    "Cache-Control": "no-store"
  }
}

この設定を含めてデプロイを行うと _nuxt ディレクトリ以下のファイルはキャッシュが有効となり、それ以外のファイルはキャッシュが無効なヘッダーが返るようになります。

API で適切な Cache-Control を返す

Static Web Apps の特徴となるバックエンド API をホストする機能ですが、その対象となる /api パス以下には staticwebapp.config.json でのヘッダー設定は反映されません。そのため API 側で適切に Cache-Control ヘッダーを返す必要があります。

Azure Functions の場合は host.json にカスタムヘッダーを設定があるので、それを使うと簡単に独自のヘッダーを返すことが出来ます。

{
  "version": "2.0",
  "extensions": {
    "http": {
      "routePrefix": "api",
      "customHeaders": {
        "Cache-Control": "no-store"
      }
    }
  }
}

基本的には API はキャッシュを行わないので、上のような設定を使ってグローバルに適用してしまって問題ないはずです。API 単位で細かいキャッシュ設定が必要な場合には、フレームワーク側に機能があるはずなので柔軟に対応できるはずです。

Front Door のキャッシュを有効化する

ここまでの設定で Static Web Apps レベルでは一通り適切なキャッシュ設定が行えたはずなので、後は Front Door 側でキャッシュ設定を有効化するだけとなります。

キャッシュの設定はルート単位で行うので、SWA 側で行っていた設定を Front Door で行うことも出来ましたが、管理性が悪いので Front Door 側でキャッシュのために複雑な構成を行うのは避けた方が無難です。

実際の設定としては以下ぐらいで問題ありません。クエリ文字列をキャッシュキーに含めるかどうかは要検討ですが、Nuxt 4 の場合はファイルにハッシュが含まれているので無視して問題ありません。

Front Door でキャッシュを有効化すると圧縮が利用可能になるので、キャッシュと同時に圧縮も有効化しておくと転送サイズが小さくなるのでより効率的になります。

この設定で Static Web Apps でホストしている Nuxt 4 アプリケーションのアセットは Front Door で適切にキャッシュされるようになりますが、Static Web Apps が Cache-Control を返さないケースがあれば 1-3 日の間でランダムにキャッシュされてしまうので、意図しない挙動となる可能性が高いです。

If the Cache-Control header isn't present on the response from the origin, by default Front Door randomly determines a cache duration between one and three days.

Caching with Azure Front Door | Microsoft Learn

基本的にはここまでの設定で全ての Static Web Apps からの応答には Cache-Control が付くはずですが、稀に SWA の障害などで壊れた応答が返ることがあるようです。その場合には応答に Cache-Control が含まれないため Front Door で長時間キャッシュされてしまいます。

かなりレアケースにはなるのですが、この問題を避けるために Front Door のルールセットで Cache-Control が付いていない場合にはキャッシュ設定をオーバーライドして回避します。

ルールセットのキャッシュのビヘイビアで Override if origin missing を選ぶと、キャッシュ設定が無い場合のオーバーライドが可能です。具体的には以下のようなルールセットを用意することで、キャッシュ設定が無い場合には 1 秒だけキャッシュするようにします。

本来であればキャッシュ自体を無効化したいのですが、0 秒に設定した場合には無効化とはならず設定自体が無視されるので、今回は 1 秒を設定して回避しています。SWA の障害発生時というレアケース向けの設定なので、このような設定でも問題にはならないと考えています。

キャッシュが意図した通りに行われているか確認

一通り設定が完了したので実際に Front Door のエンドポイント経由でアクセスして、キャッシュが行われているかを確認します。Front Door は X-Cache ヘッダーでキャッシュの状態を返してくれるので、この値を見るとキャッシュが行われているか確認出来ます。

ルートにアクセスすると index.html が返るのでキャッシュが無効になっています。

次に _nuxt ディレクトリ以下のファイルではキャッシュにヒットしていることが確認出来ます。

以前に比べて Front Door のキャッシュパージは高速化されていますが、意図しないキャッシュが行われてしまうと大きな問題となるため、まずは TTL は短めから徐々に伸ばしていくのがベストでしょう。全てのリクエストに対して Cache-Control を適切に返すというのも重要になります。

Streamable HTTP に対応した Azure Functions の MCP Extension がリリースされたので試した

正直なところタイトルの通りですが、今年一番の注目 Azure Functions の機能である MCP Extension (MCP Tool Trigger) の Preview 7 がリリースされ、待望の Streamable HTTP がサポートされたので試していきます。

リリースノートは公開されていませんが、コミットを追えば何が追加されたのか確認出来ます。

Streamable HTTP のサポート関連ではありますが、Preview 7 から MCP の実装が独自から公式 MCP C# SDK の実装に切り替えられたので、互換性という観点でも改善されているはずです。

AOAI Dev Day 2025 でも話しましたが、これまでの Azure Functions の MCP Extension は Streamable HTTP ではなく HTTP + SSE のみのサポートだったので、常時接続が必要だったので実装面でもスケーラビリティ面で扱いにくいものでした。セッション資料は以下で公開されているので適宜参照してください。

噂によると MCP Extension の GA は 8 月だったはずですが、多少ずれている可能性がありそうです。遅くとも 9 月中には GA するとありがたいです。

既に以下の公式ドキュメントは Preview 7 の機能が反映されているので、まずはこちらにも目を通しておくと安心です。リリースとほぼ同時にドキュメントの更新も行われているのは安心感があります。

ちなみにこのエントリを書いている時点では Extension Bundles に MCP Extension の Preview 7 が含まれていないため、C# 以外の言語では func extensions installextensions.csproj を作って、明示的に拡張機能をインストール必要があります。

数日中には Extension Bundles のアップデートが行われて Preview 7 が含まれると思いますが、意外に拡張機能を明示的にインストールする方法は知られていないので、これを機に知っておいても損はありません。

ここから先は実際に Preview 7 の機能を試した結果を書いていきます。後述しますがバインドされたプロパティの型変換で一部挙動が変わっているのを確認したので注意が必要です。

ステートレスな Streamable HTTP

今回の Preview 7 での最重要アップデートになる Streamable HTTP ですが、現時点ではステートレスのみがサポートされていますが、ステートフルが必要となるケースはかなり少ないと思うので、大きな問題にはならないと考えています。

拡張機能のアップデートを行うと自動的に Streamable HTTP が有効になるので、デバッグ実行を行うと以下のように Streamable HTTP と SSE のエンドポイントの両方が表示されます。

Streamable HTTP がサポートされたので Flex Consumption へデプロイすることが容易になりました。

これまでの HTTP + SSE の場合は常時接続が必要になるので、ゼロスケールが行われる Flex Consumption との相性があまり良くなかったです。

プロパティの POCO バインディング

個人的には Streamable HTTP よりも便利だと思っているのが POCO へのバインディングがサポートされたことです。これまで MCP Tool Trigger でプロパティを受け取る場合には、以下のようにメソッドの引数に属性とセットで並べていく必要があり、受け取るプロパティが増えると可読性が急に悪化していました。

[Function(nameof(Echo))]
public object Echo([McpToolTrigger(nameof(Echo), "指定された人にあいさつします")] ToolInvocationContext context,
                   [McpToolProperty(nameof(name), "string", "人の名前", true)] string name)
{
    return $"Hello, {name}";
}

その問題を解決できる機能が POCO バインディングです。ドキュメントが公開されているので詳細はこちらを参照貰えれば良いですが、C# でよくある実装パターンに MCP Tool Binding を持ち込めるのが便利です。

実際に最初の MCP Tool 実装を POCO バインディングを使うように書き換えると、以下のように受け取るプロパティを別のクラスとして定義する形になります。これまでは McpToolProperty 属性を使っていましたが、C# の機能である required キーワードや Description 属性を使って定義出来るようになりました。

[Function(nameof(EchoPoco))]
public object EchoPoco([McpToolTrigger(nameof(EchoPoco), "指定された人にあいさつします")] EchoRequest request, ToolInvocationContext context)
{
    return $"Hello, {request.Name}";
}

public class EchoRequest
{
    [Description("人の名前")]
    public required string Name { get; set; }
}

明示的に名前やプロパティの型を定義する必要がなく、自動的にプロパティの型からマッピングを行ってくれるので非常に定義しやすくなりました。

ローカルでデバッグ実行しながらテストとして Copilot Chat を使って実行してみると、以下のように定義したクラスに値がマッピングされていることが確認出来ます。この辺りは C# を使って開発したことがある方なら馴染み深い挙動でしょう。

もちろん実行結果も以下の通り、意図した通りの挙動となっています。注意点としてはプロパティ名が JSON ですが PascalCase になることです。古い方法では大体 camelCase になっているはずなので、MCP クライアント側にキャッシュが残っていると、プロパティのマッピングが正しく行われないことがありました。

これは C# の JsonSerializer 実装によるものなのでカスタマイズ可能かもしれませんが、POCO バインディングへの移行タイミングでは気を付けましょう。

非常に便利な機能なのですが、既に実装して利用していた MCP サーバーの実装を Preview 7 にアップデートしたところ型変換のエラーが発生して、正しく動作しないケースがいくつかありました。具体的には以下のような MCP Tool を実装していました。

[Function(nameof(GetUser))]
public object GetUser([McpToolTrigger(nameof(GetUser), "ユーザー ID からユーザーの詳細を返します")] ToolInvocationContext context,
                      [McpToolProperty(nameof(userId), "string", "ユーザー ID")] string userId)
{
    return $"Id: {userId}";
}

これはよくある ID を受け取って詳細を返すという MCP Tool ですが、ID のフォーマットによって余計な型変換を行ってしまうことがありました。

例えば以下のように数字ベースの ID であれば文字列として扱われるので問題ありませんでした。

次に userId として GUID ベースの文字列を渡そうとしてみます。全ての型を string として定義しているので、Preview 6 までは問題なく動作していました。

しかし Preview 7 では 受け取る Function の引数の型が string になっていても内部的に GUID として扱われて、Function 呼び出し時にキャスト不可になり失敗してしまいました。

どうも内部で使われているバインディングの処理が、引数やプロパティの型を考慮していないようです。今回の場合は引数の型を Guid に変更すれば動くようになりますが、意図しない型変換が発生しているので不具合として報告するつもりです。

Microsoft Build 2025 で発表された Azure Cosmos DB for NoSQL のアップデート

毎年の話ではありますが、Microsoft Build のタイミングでは Cosmos DB は多くのアップデートが公開されます。今年の Build 2025 でも例によって大量のアップデートが公開されているので、特に NoSQL に関する機能についてまとめておきます。

見てわかるように Cosmos DB for NoSQL だけでも以下のように大量のアップデートが公開されています。継続的に投資が行われていることが分かります。

Build 2025 で発表された Cosmos DB のアップデート全体については、以下の 2 つのブログを見てもらうと大体把握出来るはずです。Cosmos DB for NoSQL に特化したブログとそれ以外という形になっています。

最近の流れに従う形で AI ワークロード向けの機能が多いですが、Cosmos DB for NoSQL ではスケーラビリティやパフォーマンス、更に信頼性の改善に繋がる機能が追加されています。サービスとしての使いやすさにも直結する部分なので嬉しいですね。

Full Text Search / Hybrid Search が GA

Ignite 2024 で発表された Cosmos DB の Full Text Search と BM25 を組み合わせた Hybrid Search が GA しました。Full Text Search は Vector Search とは異なり、後から Full Text Index を追加できるのが便利です。

Vector Search と Full Text Search を組み合わせると Hybrid Search が実現できるので、AI ワークロードのナレッジストアとして Cosmos DB が非常に扱いやすくなっています。ただし GA しましたが日本語アナライザーのサポートは追加されていないため、日本語のドキュメントで利用するのはしばらくお預けです。

英語以外の Full Text Search と Fuzzy Search が Public Preview

日本語の対応は入ってきませんでしたが、Full Text Search でドイツ語・スペイン語・フランス語への対応が Public Preview で追加されました。そして同時に Fuzzy Search のサポートも Public Preview になっているので、最大距離を明示的に指定することで柔軟な検索が実現できるようになっています。

英語以外の Full Text Search と Fuzzy Search については Public Preview なので、いつものように Cosmos DB の Features から明示的に機能を有効化する必要があります。

ちなみに Features の内部的な値はこれまで通りの EnableNoSQLFullTextSearch なので、ARM Template や Terraform で利用する場合にはこの値を使えば問題ありません。これまで Full Text Search を試していた場合は、すでに有効化された状態になっているはずです。

Sharded DiskANN (Filtered vector search) が Public Preview

これまで DiskANN を含む Vector Search ではコンテナーの Partition Key に関係なく、データセット全体に対して Vector Search が行えていましたが、インデックスが大きくなればなるほどパフォーマンスは悪くなるので、Vector Search でも特定の値でインデックスを分割する機能が Shareded DiskANN になります。

Vector Index を作成する際に Shared Key を指定すると、その値に従って DiskANN のインデックスが作成されるので、それぞれのインデックスサイズが小さくなるためパフォーマンスが改善します。ただし検索時には Shared Key を指定する必要があるので、マルチテナントのシナリオに最適というわけです。

Global Secondary Index が Public Preview

これまでは Materialized Views という名前で提供されていた機能ですが、今回の Build のタイミングで大幅に機能がリニューアルされて Global Secondary Index という名前で Public Preview になりました。名前としては Index となっていますが、実体としては Change Feed で別の Container を作成する機能です。

Materialized Views の時は Dedicated Gateway が必要で追加コストがかなり大きく乗ってくる機能でしたが、Global Secondary Index は RU 以外の追加コストが発生しないようなので、かなり使いやすくなっています。その代わりにシンプルな射影のみ行えるという機能になっています。

例によって Features で有効化が必要になるので、その点だけは注意が必要です。既に Materialzied Views を有効化していたアカウントでは Global Secondary Index も使えるようになっています。

しかし自分が確認した限りでは、既存のアカウントと Container に対して GSI を作成した場合には上手く動作しませんでした。アカウントを新規に作成した場合は動作したので、既存アカウントへのデプロイが間に合っていない可能性はありそうです。

Per Partition Automatic Failover が Public Preview

Cosmos DB は内部的に物理パーティションと呼ばれるコンピューティングリソースが大量に存在することで、無制限のスケーリングが実現されています。そしてマルチリージョンの構成でも同じように物理パーティションがリージョン単位で同じだけ用意されています。

もし障害が発生してフェールオーバーが必要になった場合、これまでは全ての物理パーティションに対してフェールオーバーが行われていましたが、PPAF が有効になっている場合には障害が発生した物理パーティションのみフェールオーバーされるようになります。

これまでマルチリージョン構成で耐障害性を高めるにはマルチ書き込みを有効化してデプロイする必要がありましたが、PPAF が有効な場合はシングル書き込みの場合でも最小限の物理パーティションのみがフェールオーバーされるので、シンプルな構成を保ちつつも高い耐障害性を実現することが可能になります。

PPAF は Cosmos DB の信頼性を更に高めるアップデートになるので、GA が待ち遠しいですね。

Serverless to Provisioned Throughput が GA

Cosmos DB は Provisioned Throughput と Serverless の 2 つの容量モードが用意されていて、パフォーマンスとコストのどちらを優先するか決めやすくなっています。Serverless は完全従量課金となるのでスモールスタートに最適ですが、途中から Provisioned Throughput に変更することが出来ないので、サービスが大きくなった場合にはデータ移行が必要で手間がかかっていました。

今回シームレスに Serverless から Provisioned Throughput に変更できるようになったので、そのようなユースケースにも対応しやすくなりました。

Azure Portal から Cosmos DB アカウントを開くとツールバー部分にボタンが追加されているので、ここから簡単に Provisioned Throughput に変更可能です。

移行後の初期 RU は物理パーティションの数から自動的に設定されるので、移行後には必ず割り当てられた RU を再確認してください。思ったよりも高くなっている可能性があるので注意が必要です。

Cosmos DB Fleets が Public Preview

Build で新しく発表された機能としてはかなり注目度が高そうなのは、この Cosmos DB Fleets ではないかと思います。これまで Cosmos DB でマルチテナントのアプリケーションを実装する場合はパーティションキーを使って分離するという戦略を取ってきましたが、物理的にデータストアを分離したいという場合には Cosmos DB アカウントを分ける必要があり、それぞれで最小の RU を設定する必要があるためコストを最適化することが難しくなっていました。

しかし Fleets を使うと Fleets 単位で RU を事前に割り当てておくことが出来、その Fleets に追加された Cosmos DB アカウント間で割り当てられた RU を共有することが出来るので、全体として RU を最適化することが可能になります。

現在 Fleets はサブスクリプションから Preview Feature の登録をする必要があります。現状は利用できるサブスクリプションが絞られている可能性があるので、いち早く試したい場合には Cosmos DB チームへ連絡を取るのが一番早そうです。

少なくとも自分のサブスクリプションではまだ登録が完了していないので試すことが出来ていない状態です。マルチテナントな SaaS を提供しているシナリオでは待望の機能ではないかと思います。

Throughput Bucket が Public Preview

アプリケーションから Cosmos DB を使っている場合には、突然のアクセス増などで RU が一時的に不足して 429 エラーが発生することがあります。Cosmos DB SDK を使っている限り、適切にリトライが行われて動作に影響が出ることはほぼありませんが、重要な書き込み処理で 429 エラーが発生してしまうのは可能な限り避けたいです。

今回 Public Preview となった Throughput Bucket を使うと、割り当てられた RU を 5 つの Bucket として分割することが出来、処理毎にどの Bucket を使うか指定可能になります。

Throughput Bucket を使うことで、優先度の高い処理用の Bucket には多い RU を割り当てておき、優先度の低い処理には少ない RU を割り当てて最悪リトライで対応するといった処理が実現できるようになります。

現在 Public Preview になっている Priority-based Execution に近い機能にはなりますが、5 つまで Bucket を作成してそれぞれに RU を割り当てられるという点が大きく異なります。

JavaScript SDK v4 が GA

正直なところ v4.0.0 がリリースされたタイミングで正式版になったと考えていたのですが、Cosmos DB チームとしては JavaScript SDK の v4 はこのタイミングまでは Preview 扱いだったようです。

GA のタイミングで Bulk の改善や Vector Search と Full Text Search のサポートなどが行われているようです。大きな改善としてはクエリ実行のパイプラインが大きく改善されたようなので、アップデートする価値はかなり大きそうです。

Microsoft Build 2025 で発表された App Service / Azure Functions / Container Apps のアップデート

今年も Microsoft Build 2025 に現地参加していますが、例によってキーノートでは全く触れられていない PaaS / Serverless 系のアップデートは多いので、自分の興味のある機能を中心に簡単にまとめます。

最近は AI 関連の機能に押されがちなのですが、App Service や Azure Functions は AI アプリケーションのワークロードを支える重要な部分なので、順当にアップデートが行われています。特に App Service は少し前に VMSS への移行が完了しているので、いろいろ手を入れやすくなってそうな気配です。

最近の App Service や Azure Functions は小手先の機能追加ではなく、足回りとなる PaaS 基盤の大規模なアップデートが行われているのでかなり気合が入っていることがわかります。

App Service

Azure の PaaS 基盤として割と枯れてきた App Service ですが、今回の Build 2025 の前後で魅力的なアップデートが発表されています。新しい Tier だけではなく、ネットワーク周りも Hybrid Connection Manager の新バージョンや IPv6 への対応が着々と進んでいます。

それ以外にもキーノートでも話が合った SRE Agent への対応も注目ですね。新しい言語バージョンへの対応も淡々と行われていますし、今年の夏には .NET 10 の Early Access が提供される予定のようです。

Premium V4 が Public Preview

Ignite 2020 で Premium V3 が発表されてから早 5 年、そして Build 2023 でメモリ最適化インスタンスと P0V3 が追加されていますが、今年の Build 2025 では新しい Premium V4 が Public Preview となりました。最新世代の VM インスタンスが使われていて、全てが AMD ベースとなっています。

現在は Public Preview 中かつ、段階的にロールアウトが行われているようなので利用可能なリージョンは限られますが、Azure CLI で以下のコマンドを叩くと一覧で確認可能です。

az appservice list-locations --sku P0V4 -o table

基本的には Premium V4 はこれまでの Premium V3 の VM アップグレード版となるので、機能面での差は特になく Windows と Linux の両方で利用可能になります。例によって現時点では新しく作成した場合のみ利用可能で、既存の App Service Plan を Premium V4 に切り替えることはほぼ出来ません。

但し Premium V4 はこれまでの App Service Plan とは異なり、Outbound IP アドレスが固定化されなくなり Azure Functions の Consumption Plan と同じように動的に変わるようになりました。ドキュメントにも以下のように記載されていて、Outbound IP アドレスの固定が必要な場合は NAT Gateway が必要です。

The Premium V4 tier lacks stable outbound IP addresses. This behavior is intentional. Although Premium V4 apps can make outbound calls, the platform doesn't provide stable outbound IPs for this tier. This differs from previous App Service tiers. The portal shows "Dynamic" for outbound IP addresses for Premium V4 apps. ARM and CLI calls return empty strings for outboundIpAddresses and possibleOutboundIpAddresses. If Premium V4 apps need stable outbound IPs, use Azure NAT Gateway for predictable outbound IPs.

Azure Portal 上も Dynamic という表示になりますので、外部サービスのファイアーウォール設定が必要な場合は NAT Gateway の追加コストが発生しますが、最近は Outbound IP アドレスがあまりにも多くなってきていたので、NAT Gateway を使った方が安心ではあります。

ちなみに Azure 内で完結する場合は Outbound IP アドレスを使うのではなく、Service Endpoint や Private Endpoint を使ってアクセス元を制限するようにしてください。

2 Availability Zones サポートが GA

少し前に App Service でも 3 つの Availability Zones にデプロイすることで 99.99% の SLA が得られるようになりましたが、今回の Build 2025 のアップデートで 2 つの Availability Zones だけでも 99.99% の SLA になりました。これまでと違いコストが 2 倍で済むので非常に使いやすくなっています。

そして大きな変更点としては既存の App Service Plan の Zone Redundancy を後からオンオフ出来るようになりました。最初はスモールスタートで 1 インスタンスかつ 1 ゾーンで運用を開始して、サービスが大きくなるにつれて可用性を高めたいというケースは多いはずなので、今回のアップデートは待望の機能です。

以下のドキュメントで変更方法が公開されていますが、自分が試した範囲ではまだ利用出来ませんでした。Azure Portal でもまだ変更できないので、機能自体がデプロイ中の予感です。

ちなみに Zone Redundancy のオンオフが出来るかどうかは App Service Plan によるので、非対応の Scale unit に当たってしまっている場合は再デプロイが必要になります。対応した App Service Plan かどうかは Azure CLI などを使って maximumNumberOfZones プロパティの値を確認する必要があります。

.NET Aspire サポートが Public Preview

Azure Functions に続いて App Service でも .NET Aspire サポートが Public Preview になっています。.NET Aspire サポートによって App Service にデプロイするアプリケーションでも依存関係の解決などが簡単に行えるようになります。

仕組みが Azure Functions と App Service は同じなので使い勝手はほぼ同じのようです。App Service 側のアップデートというよりも .NET Aspire 側のアップデートになります。

Azure Functions

Azure Functions についても App Service と同じ基盤で動くオプションがあるので、Premium V4 などの恩恵をそのまま受けることが出来るようになっていますが、Build 2025 で発表されたものとして重要なのは Flex Consumption Plan 関連のアップデートになります。

Flex Consumption は GA となっていますが、まだサポートされていない機能や Public Preview の機能が多いので今後のアップデートにも期待です。それ以外には各言語のアップデートなどが順当に行われています。

Flex Consumption を利用可能なリージョンが拡大

これまで Flex Consumption は GA していても限られたリージョンでのみで利用可能でしたが、Build の少し前に大幅にリージョンが拡大されて東日本でも利用可能になりました。

いろいろなチャネルからフィードバックを上げていましたが、ようやく東日本でも使えるようになったのは嬉しいですね。西日本ではまだ利用可能になっていませんが、少し前に西日本は AZ がサポートされたこともありますし、キャパシティ面での問題が解消されつつあるので近いうちに来ると考えています。

Flex Consumption で 512MB インスタンスが Public Preview

これまでの Flex Consumption は 2048MB と 4096MB のインスタンスサイズが用意されていましたが、Flex Consumption のスケーリングはリージョン単位でインスタンス合計サイズの上限が決まっているため、小さいアプリケーションの場合スケーリングの効率が下がっていましたが、512MB を使うとこれまで以上のスケーリングが実現出来ます。

特に Azure Functions の場合は小さいアプリケーションをデプロイするケースが多いと思うので、512MB インスタンスを使う機会が増えるのではないかと思います。

Flex Consumption で Availability Zones サポートが Public Preview

Azure Functions で従量課金のオプションで Zone Redundancy を有効化することは出来ませんでしたが、Flex Consumption が今回一部のリージョンで Zone Redundancy を有効に出来るようになりました。しかも後から変更することも出来るので柔軟に設定可能です。

まだ東日本では AZ を有効化することは出来ませんが、Flex Consumption の AZ は Cosmos DB などのサービスとは異なり、有効化してもコストが変わることが無いので非常に使いやすいものになっています。

SQL Trigger の Consumption Plan サポートが GA

Azure Functions の SQL Trigger 自体は既に GA していましたが、Consumption Plan はサポートされていませんでした。スケールコントローラが対応していないと Consumption Plan への対応とは言えない事情がありますが、v3.1.284 以上でサポートされました。

SQL Database へのアクセスはプライベートネットワークに閉じている場合は Consumption Plan では上手く動作しない気配があります。Flex Consumption サポートとは言っていないのが気になりますが、将来的には正式対応されると考えています。

Python での HTTP Streaming サポートが GA

Ignite 2024 で Python を使った場合の HTTP Streaming サポートが Public Preview になっていましたが、Build 2025 では GA となり安心して使えるようになりました。

LLM 利用時にはレスポンスのストリーミングが必須なので、今回のリリースはかなり重要だと思います。

OpenTelemetry サポートが Public Preview

これまで Application Insights へのテレメトリ送信はこれまで独自のプロトコルでしたが、OpenTelemetry への対応が Public Preview で追加されています。今回は珍しく全ての言語で最初からサポートされているので広く試すことが出来ます。

OpenTelemetry を使うことで Application Insights 以外にも、OTel に準拠したサービスに送信することが出来るようになっています。OTel を使うことでカスタマイズ性は高まっていますが、現在は非対応の機能も多く存在しているので注意が必要です。

Container Apps

ここ最近の Container Apps は足回りのアップデートはあまり多くなく、Azure の PaaS / Serverless の中では AI 関連の機能が多く実装されている印象があります。特に GPU を必要とするシナリオでは Container Apps が Serverless で GPU が使えるのは大きなメリットです。

AI 関連以外ではネットワーク周りのアップデートが目立ちます。足回りのコンピューティングについては大きなアップデートはないので、割と安定してきている気がします。

Dedicated GPU サポートが GA

Container Apps の Serverless GPU は既に GA していましたが、今回の Build では Dedicated GPU が GA となりました。常に GPU を使い続ける必要があるようなワークロードに最適なオプションとなります。

利用される GPU VM は NC A100 v4 ベースとなるので、NC シリーズでの最新世代となります。SKU は以下のドキュメントにもあるように複数用意されているので、VM をデプロイして管理するよりも簡単に GPU インスタンスを扱えるのはメリットです。

Dedicated GPU は Workload Profile な Container App Environment である必要があるので注意が必要です。オンデマンドで使う用途ではこれまで通り Serverless GPU を使っていただくのがベストですが、パフォーマンスを重視する場合は Dedicated GPU を使うことになります。

Dynamic Session の Serverless GPU サポートが Early Access

正直なところ Container Apps 感が無い機能である Dynamic Session ですが、Serverless GPU 付きで動かす機能が Early Access となっています。

これを使うことで LLM が生成した Python コードが GPU を使う場合でも、完全に分離された環境内で安心して利用できるようになっています。

Native Azure Functions サポートが GA

Azure Functions のホスティングオプションとして Container Apps が選べますが、これまでは Azure Functions を作成しても裏側の Container Apps リソースが作成されるので、1 つの Azure Functions を作成すると 2 つのリソースが存在する形になっていました。

今回の Native Azure Functions サポートで裏側の Container Apps リソースが作成されず、Azure Functions リソースだけになるため設定や管理が行いやすくなっています。

もちろん Container Apps の機能は全てサポートされているので、安心して Native Azure Functions へ移行することが出来ます。リソースの作成時に kind プロパティで functionapp を指定するだけなので、移行自体も簡単に行えます。

既に Azure Functions を Container Apps でホスティングしている方は、今回の Native Azure Functions サポートへ移行するのがお勧めです。

Private Endpoint サポートが GA

Contianer Apps は標準の機能で Public IP を持たない Private 専用の環境を作成することが可能ですが、Front Door のようなグローバルリソースでは Private Endpoint を使わない限り Private 接続が行えませんでした。今回 Private Endpoint 対応が GA したので安心して利用できるようになりました。

Public Preview 中は対応していませんでしたが、GA のタイミングで TCP も利用できるようになっています。Private Endpoint はテナント間でも利用できるので、複雑なシナリオでも VNET Peering を使わずに実現できるケースも多いかと思います。

Premium Ingress が Public Preview

デフォルトで用意されている Container Apps の Ingress はコストが発生しない代わりに、割り当てられているコンピューティングリソースに上限があり、最大のスケーリングも 10 までとなっています。ほとんどのケースでは十分だと思いますが、それ以上のスケーリングが必要なケースのために Premium Ingress が Public Preview となりました。

Premium Ingress はデフォルトの Ingress とは異なり、特定の Workload Profile に紐づくためインスタンスサイズやスケーリングも柔軟に設定可能です。Premium Ingress ではタイムアウト設定など細かく制御が可能なので、そのあたりの調整を行いたい場合にも利用できます。

但し Premium Ingress は Workload Profile にデプロイする必要があるので、デフォルトの Ingress とは異なり追加のコストが発生します。この点だけは注意が必要ですね。

Rule-based Routing が Public Preview

これも Ingress に関係しますが、これまでホスト名単位でそれぞれの Container Apps にルーティングされるのが基本でしたが、Front Door などのように HTTP のカスタムドメインやパスベースで細かくルーティングを定義出来るようになりました。

カスタムドメインを使う場合には少し手間が発生しそうですが、簡単なルールであれば Front Door や Application Gateway を追加する必要が無く、Container Apps だけで完結出来るため柔軟に対応できますしコストも最適化出来そうです。

GitHub Actions と SWA CLI を使った Azure Static Web Apps へのデプロイを高速化する

最近は Static Web Apps へのデプロイを行うために Static Web Apps CLI を使うことが多いです。理由としては公式の GitHub Action は Docker Image を毎回ビルドするため時間がかかるのと、ビルドが必要ない場合に Oryx が必要ないので軽量な処理で行いたいというのがあります。

特に SWA CLI を使うと Service Principal / OpenID Connect を使ったシークレットレスでのデプロイが簡単に行えるというのが大きいです。詳細については以下のエントリを参照してください。

このように SWA CLI を使ったデプロイが非常に便利なので、今では GitHub Actions からのデプロイでも SWA CLI を使うようにしていたのですが、GitHub Actions で動かすとランダムでエラーが発生するようになってしまいました。既に Issue は複数上がっていたのですが解消出来ていませんでした。

根本的な原因は SWA CLI が実行時にデプロイ用クライアントが存在しない場合にダウンロードすることにあるため、デプロイ用クライアントのダウンロードをスキップすると回避可能です。

デプロイクライアントは ~/.swa 以下に保存されているため、GitHub Actions のワークフロー内でこのディレクトリをキャッシュするように設定を追加します。

name: Deploy to SWA

on:
  push:
    branches: [ master ]
  workflow_dispatch:

env:
  SWA_CLI_DEPLOYMENT_TOKEN: ***

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Cache SWA CLI
      uses: actions/cache@v4
      with:
        key: swa-${{ runner.arch }}-${{ runner.os }}
        path: |
          ~/.swa

    - name: Deploy to Static Web App
      run: swa deploy ./dist/ --env production

このワークフローを使ってデプロイを行ってみると、キャッシュがある場合には該当ディレクトリを復元し、更に SWA CLI を使ったデプロイ時にはクライアントのダウンロードが行われずに再利用されていることがわかります。ダウンロードしないためデプロイ時に謎のエラーは出なくなります。

デプロイ時に謎のエラーは出なくなるのですが、別にデプロイにかかる時間は大きく短縮できないため、SWA CLI 自体もキャッシュしてしまえば時間のかかる npm からのインストールをスキップ出来ます。

ただし単純に npm がインストールされたディレクトリをキャッシュするだけだと、バージョンアップに追従できなくなってしまうので工夫が必要です。具体的には最新のバージョンを取得してキャッシュキーの一部として扱うことが解決しています。

name: Deploy to SWA

on:
  push:
    branches: [ master ]
  workflow_dispatch:

env:
  SWA_CLI_DEPLOYMENT_TOKEN: ***

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Retrieve SWA CLI version
      id: swa-cli-version
      run: echo "version=$(npm view @azure/static-web-apps-cli version)" >> $GITHUB_OUTPUT

    - name: Cache SWA CLI
      id: cache-swa-cli
      uses: actions/cache@v4
      with:
        key: swa-${{ runner.arch }}-${{ runner.os }}-v${{ steps.swa-cli-version.outputs.version }}
        path: |
          ~/.swa
          /usr/local/bin/swa
          /usr/local/lib/node_modules/@azure/static-web-apps-cli

    - name: Install SWA CLI
      if: steps.cache-swa-cli.outputs.cache-hit != 'true'
      run: npm install -g @azure/static-web-apps-cli

    - name: Deploy to Static Web App
      run: swa deploy ./dist/ --env production

キャッシュが存在している場合は npm インストールをスキップしたいので、条件式を使ってキャッシュが存在する場合にはスキップを行うようにしています。キャッシュがあっても npm インストールを実行すると処理時間の短縮には繋がらないので注意です。

このワークフローを実行すると 2 回目以降はキャッシュが存在しているため、SWA CLI の npm インストールがスキップされていることが確認できます。

実行時間についてもキャッシュが使われている場合には大幅にデプロイ時間が短縮されていて、キャッシュが効いていない場合に比べて半分程になっています。

Static Web Apps のデプロイにこれまで絶対に 1 分以上掛かっていたのを 30 秒ほどまで短縮できたので、プレビュー環境など頻繁にデプロイしたい場合に待ち時間も減らし素早く確認できるようになりました。

ちなみにダウンロードの問題は SWA CLI の v2.0.5 で修正されたので、最新版を使っている限り問題は発生しなくなっています。古いバージョンを使っている場合にはアップデートしておくのが無難です。

バージョンのアップデートを行うとエラーは発生しないのですが、都度 npm からのインストールやデプロイクライアントのダウンロードといった処理は発生するため、キャッシュを入れておくと待ち時間のストレス無くデプロイが行えるようになります。