Azure Functions .NET6インプロセスモデルから.NET8分離ワーカーモデルへの移行

本ページにはプロモーションが含まれています。

お仕事

こんにちは。seiです。桜の花の開花がこんなにも遅くなってるのは久々な気がする今日この頃。これが普通の状態なのか異常なのか、もうよくわかんなくなってきますね。

さて、今日は2024年11月にサポート終了が迫っている.NET6のAzure Functionsアプリケーションを、その次のLTS(長期サポート)リリースである「.NET8」へアップグレードすべく、事前に検証してみましたので、その手順を投稿していこうと思います。

ちなみに、以前は.NET8ではインプロセスモデルはサポートされず、分離ワーカーモデルのみになると思っていましたが、ここにきてインプロセスモデルも利用可能と理解しました。しかしながら、結局はインプロセスモデルは廃止の方向のようなので、もう.NET8への移行と同時にインプロセスモデルから分離ワーカーモデルへの移行も併せて行ってしまおうというのが今回の趣旨です。

はじめに

基本的には、MSさんのLearnにあるこの情報を元ネタとして実施しています。が、この手順ですと、ASP.NETCore統合としてAzure Functionsを構成しますが、今回は「組み込みの Functions HTTP 型」っていうの?つまりASP.NETCore統合不使用(HttpRequestDataとかHttpResponseData使うヤツ)での移行を行っていきます。

Azure Functions .NET8 分離ワーカーモデルへの移行手順

移行対象とするのは、下記の.NET6インプロセスモデルのAzure Functionsコードになります。

このコードでは、HTTPトリガーでクライアントからのHTTPリクエストを受け取り、Queue出力バインドで複数の値をQueue出力を行うというものです。

実行するとこんな感じ。

HTTPリクエストを受け取り、URLパラメーターで受け取った内容を出力する。

そして、QueueにURLパラメーターで受け取った内容を3回出力する。

それでは早速移行していきますが、おおまかな手順としては以下の感じになっています。

  • csprojファイルの編集
  • パッケージ参照の変更
  • Program.csファイルの追加
  • 関数アプリコードの変更

それではひとつづつ順番に行っていきましょ~。

csprojファイルの編集

まずはC#のプロジェクトファイルのcsprojファイルを変更します。

以下が変更前のcsprojファイル。

変更内容は以下のとおり。

①<TargetFramework>の値を「net6.0」→「net8.0」に変更します。

②<OutputType>Exe</OutputType>をPropertyGroup内に追加します。

③ItemGroupの「Microsoft.NET.SDK.Functions」へのパッケージ参照を以下の内容に書き換えます。

④「Microsoft.Azure.WebJobs」や「Microsoft.Azure.Functions.Extensions」名前空間のパッケージがある場合は削除します。

⑤以下のItemGroupを追加します。

最終的に変更されたcsprojファイルは以下のような感じになると思います。

パッケージ参照の変更

続いて、パッケージ参照を変更していきます。基本的には「Microsoft.Azure.WebJobs」や「Microsoft.Azure.Functions.Extensions」名前空間のパッケージで利用していた拡張機能を「Microsoft.Azure.Functions.Worker.Extentions」名前空間のパッケージとしてインストールしなおす感じです。

①NuGetパッケージマネージャーを開きます。コンソールがお好みの方はよしなに。

②利用するバインドなどのパッケージをインストールします。ここではQueue出力バインドを利用していますので、「Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues」パッケージをインストールします。

詳しくは以下のリンクにて。

Program.csファイルの追加

Program.csファイルを追加して以下のコードを記述していきます。すでにDIなど利用している場合はFunctionsStartup属性のついたStartup.csをProgram.csにリネームしていく感じでしょうか。必要であればDIも記述します。また、JSONシリアル化設定なども必要であれば追記します。

関数アプリコードの変更

あとは実際に関数アプリコードを書き換えていくだけです。変更前のAzure Functions .NET6インプロセスモデルのコードを再掲します。

変更ポイントは以下の通り。

  • [FunctionName]属性を[Function]属性に変更する
  • DIでIloggerを受け取り、コード内のlogインスタンスと置換する
  • usingの書き換え
  • staticクラス・メソッドをインスタンスクラス・メソッドに変更
  • トリガーやバインディングの変更
  • local.settings.jsonファイルの「FUNCTIONS_WORKER_RUNTIME」値を「dotnet-isolated」に変更

それでは一つ一つ見ていきます。

[FunctionName]属性を[Function]属性に変更する

となっているのを

と[Function(関数クラス名)]に書き換えるだけです。

ILoggerのDI

①まずは以下のコードを関数クラスのメンバーとして宣言します。

②関数クラスのコンストラクターを宣言し、ILoggerオブジェクトを受け取って①で宣言した変数に代入します。

③次に関数メソッドが受け取っているILoggerインスタンスを削除します。

こうなります。

④そして、コード内のlogオブジェクトを_loggerオブジェクトに変更します。

って感じに直します。

usingの書き換え

不要な「using Microsoft.Azure.WebJobs;」をすべて削除し、「using Microsoft.Azure.Functions.Worker;」を追加します。

こうなります。

staticクラス・メソッドをインスタンスクラス・メソッドに変更

に変更します。

トリガーやバインディングの変更

この手順はちょっと癖あります。基本的にはトリガーはそのまま、入力バインドはインプロセスモデル時の属性値に「Input」を付けましょうとあります。例えば、[Blob(“sample/fileName”, FileAccess.Read, Connection = “MyStorageConnection”)]だったとしたら、[BlobInput(“sample/fileName”, Connection = “MyStorageConnection”)]に変わります。Accessプロパティは不要です。

そして、出力バインドですが、入力バインドと同様に通常は「Output」を付与するとあります。ですが、今回の例では、Httpトリガーとして、クライアントにHttpレスポンスを返しつつ、Queueストレージにエンキューを行う必要があります。要するに複数の出力バインドがあるというシチュエーションを実装してみます。

元ネタはここです。

①新しいクラスを追加します。今回はCustomResponseというクラス名で追加します。そして、そこにHttpResponseを返すプロパティとQueue出力バインド用のプロパティを追加しておきます。Queue出力バインドを返すプロパティには[QueueOutput(“my-queue-items”, Connection=”AzureWebJobsStorage”)]といった感じで属性を設定しておきます。また、Queue出力バインドは1度に複数の値をエンキューしているので、Listオブジェクトといったコレクションや配列で用意する必要があります。

②次に、メソッド宣言を変更し、CustomResponseを返すようにし、Queueのバインドを削除します。

これを

このように変更します。

③最後に、メソッド内でIActionResultを返しているコードを①で追加したCustomResponseオブジェクトで返すように変更します。

local.settings.jsonファイルの「FUNCTIONS_WORKER_RUNTIME」値を「dotnet-isolated」に変更

最後にlocal.settings.jsonに分離ワーカーモデルを利用することを明示していきます。

FUNCTIONS_WORKER_RUNTIMEの値を「dotnet」から「dotnet-isolated」に変更します。

local.settings.jsonですので、言うまでもなく、ローカルデバッグでの設定です。この値が有効になるのはデバッグ時ですので、Azure実行環境でも同様の変更が必要ですが、後述します。

.NET8分離ワーカーモデル(ASP.NET Core統合)移行後のコード全体像

Azure Functionsの.NET6インプロセスモデルから、.NET8分離ワーカーモデル(ASP.NETCore統合)移行後のコード全体像は以下の通りです。

それではデバッグ実行してみます。無事Fucntionsホストが立ち上がりました。が、分離ワーカーかどうかははっきりわかりませんが、インプロセスの時と表示が若干違うのはわかります。

それではHTTPトリガーにリクエストを投げてみます。

あれ?レスポンスの文字列が返ってこない・・・orz

でも、Queueにはちゃんとエンキューされてる。

いろいろ調べたがどうしてもわからなかった。けど、単体のHTTPトリガーなんかはうまくいくのでもしかして、マルチレスポンスでHTTPとQueueを出力してるのが悪いのかなぁと憶測。

2024/06/11追記

Microsoft.Azure.Functions.Worker.Sdkのバージョン1.17.3-preview2以降かつ、Microsoft.Azure.Functions.Worker.Extensions.Http拡張機能のバージョン3.2.0以降かつ、Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCoreのバージョン1.3.0以降をインストールして、IActionResultに[HttpResult]属性をつけることで解決しました。

ちゃんとマルチレスポンスで返ってくるのを確認。いぇいv

ってことでASP.NETCore統合でいい方はここまででコードの移行は完了ですかね。

試しに、ASP.NET Core統合をやめて実装しなおしてみます。

ASP.NETCore統合ではなく、組み込み型モデルに書き換える方は引き続き次の手順をどうぞ。

Azure Functions .NET 8 IsolatedをASP.NET Core統合なしに書き換え

ということで、うまくレスポンスが返ってきませんでしたので、ASP.NET Core統合をやめ、非ASP.NET Core統合(組み込みFunctionsHTTP型)に書き換えていきます。

①NuGetパッケージマネージャーから「Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore」パッケージをアンインストールします。

②NuGetパッケージマネージャーから「Microsoft.Azure.Functions.Worker.Extensions.Http」パッケージをインストールします。

③Program.csのコードを変更し、ASP.NET Core統合を削除する。

これを、

④以下のようにコードを変更します。(変更箇所はコメントにて記述)

それでは、実行してみます。

今度は、ちゃんとHTTPレスポンスも帰ってきました。

Queueへの書き込みもばっちりです。ひとまずコードの移行は問題なさそうです。

Azure実行環境への反映

最後に、.NET8分離ワーカーモデルへと移行したAzure FunctionsコードをAzure実行環境にデプロイしていきましょう。シチュエーションとしてはAzure実行環境は.NET6インプロセスモデルで稼働しているという前提でデプロイを行ってみます。

ランタイムスタックが.NET6のAzure Functions本番系リソースを用意します。そして移行前のAzure Functionsコードがデプロイ済みです。

また、上記Azure Functionsのデプロイスロットを用意し、ステージング環境とします。もちろんこちらも.NET6インプロセスモデルのAzure Functionsです。

そして、local.settings.jsonで行ったのと同じことをAzure実行環境でも行います。[設定]-[環境変数]から、[アプリ設定]にアクセスし、ステージング環境のスロットの「FUNCTIONS_WORKER_RUNTIME」の値を「dotnet」から「dotnet-isolated」に変更し、保存を行います。

環境変数のUI、変わったんですねぇ・・・。というかいろんなところ変わってますが。

それではAzure Functionsリソースにコードをデプロイしていきます。パイプラインを組んでいる方がほとんどだと思いますが、パイプライン経由でAzure Functionsのバージョンアップまで行ってくれるか検証してないので、今回はLearnにある通り手動デプロイ時の自動アップグレードで行ってみます。

Azure Functionsアプリの公開プロファイルを作成します。

プロファイルができたら「発行」ボタンをクリックします。

以下のランタイムバージョン更新ダイアログが表示されるので、「はい」ボタンを押下しましょう。

デプロイが完了したら、Azure Functionsステージングスロットのリソースを確認してみます。ランタイムスタックが「.NET 8」に更新されているのが確認できました!

全般設定を見れば「.NET 8 Isolated」となっているので、分離ワーカーモデルとして動いていることも確認できました。

さいごに

ステージングにデプロイを行って稼働確認がOKになったら、後は本番スロットにスワップを行えば、晴れて.NET 8 分離ワーカーモデルへの移行が完了になります。

スワップしてステージング環境に移った旧本番系に再度手動デプロイを行って.NET 8へのアップグレードを行わないと次回おかしなことになっちゃいますかね?そこまでは試してないですが。「dotnet-isolated」の変更を忘れずに。

実際移行してみて、今回のHTTP&Queue出力といったような複数の出力を行うのにわざわざクラス定義しなきゃとか、ぶっちゃけめんどいですね。さらに、分離ワーカーというか、HttpRequestData、HttpResponseDataがモックしづらいので、UTコードがちょっとやばいです。というか実装してません。なんとかしてくれることを期待するのみです・・・。その辺も考慮に入れたうえでインプロセスのまま、まずは.NET8への移行だけしていくというが選択肢でもいいのかなぁと思います。今回は移行しちゃいましたが。

コード量多いとさすがに対応負担大きいので計画的に移行していきましょう。

以上、Azure Functionsを.NET8分離ワーカーモデルに移行してみました。


システムエンジニアランキング

にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

コメント

タイトルとURLをコピーしました