しばやん雑記

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

Azure Functions v1 から v2 への移行手順メモ

Azure Functions のランタイムは v1 がほぼ更新が無くなり、最近は v2 の更新ばかりなので、近いうちに v1 の実質 EOL のお知らせとかが出るのではないかなと思ってます。

v2 ランタイムは安定したものになっているので、早めに移行しておいた方が良いでしょう。移行手順はドキュメントが公開されてますが、実際に作業して確認しておくことにしました。

作業前に Azure Functions 向けの Visual Studio 拡張は最新版にアップデートしておいた方が良いです。

実際に行った手順は以下の通りです。基本的にはターゲットフレームワークの変更と NuGet パッケージを更新して、淡々とコンパイルエラーを取り除く作業といった感じです。

プロジェクトを .NET Core 2.1 向けに修正

Azure Functions v1 のプロジェクトはターゲットフレームワークが net461 になっているはずなので、そこを netcoreapp2.1 に変更します。そして同様に AzureFunctionsVersion も v2 に変更します。

Microsoft.NET.Sdk.Functions は現時点の最新となる 1.0.24 を指定すれば良いです。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <AzureFunctionsVersion>v2</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.24" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

最低限必要なプロジェクトファイルはこのような形になるはずです。

最新のプロジェクトテンプレートを使って作成すると、SDK のバージョン指定は以下のようになっていることもあります。ビルド時点での最新が使われるので、こっちの方が楽かもしれません。

<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.*" />

勝手にアップデートされて問題が出る場合もあるので、この辺りは難しい部分です。個人的にはバージョンは明示的に指定する派です。

新しい Extension をインストール

Azure Functions v2 向けの Extensions は大体バージョンが 3.0.0 とかになっているので、そのバージョン以降で一番新しいものをインストールします。

時々違うバージョンもありますが、依存関係で WebJob SDK の 3.0.0 以上を要求しているものが正解です。

  • Cosmos DB (DocumentDB)
    • Microsoft.Azure.WebJobs.Extensions.CosmosDB
  • EventGrid
    • Microsoft.Azure.WebJobs.Extensions.EventGrid (2.0.0)
  • Event Hubs
    • Microsoft.Azure.WebJobs.Extensions.EventHubs
  • SendGrid
    • Microsoft.Azure.WebJobs.Extensions.SendGrid
  • Service Bus (Topic / Queue)
    • Microsoft.Azure.WebJobs.Extensions.ServiceBus
  • Storage (Blob / Table / Queue)
    • Microsoft.Azure.WebJobs.Extensions.Storage
  • Twilio
    • Microsoft.Azure.WebJobs.Extensions.Twilio

v1 から v2 への移行では特に Storage 周りの Trigger が別アセンブリになっているので、インストールが追加で必要となっています。DocumentDB は Cosmos DB に ID が変わっているのでそこも注意。

Durable Functions は最新版にアップデートしておけば良いので簡単です。

コードの修正

基本的にはコンパイルエラーになっている部分を直していけばよいです。プロパティが無くなっていたりしますが、大体は問題なく移行できるはずです。HttpTrigger 周りは変更が大きいので注意です。

TraceWriter を ILogger に変更

単純に TraceWriter を ILogger に置換すれば良いというわけでもなく、メソッドも変わっているので該当するログレベルのメソッドに置き換えていきます。

ログ周りに関しては三宅さんの記事も参考になります。

Verbose だけは該当するメソッドが無くなっているので、適当に Debug や Trace に置き換えると良いです。

HttpRequestMessage / HttpResponseMessage を修正

v1 までは ASP.NET Web API 的なインターフェースだったのが、v2 からは ASP.NET Core と同じインターフェースに変わっているので、HttpRequestMessageHttpResponseMessage はそれぞれ HttpRequestIActionResult を使うように変更していきます。

v2 では IActionResult を作るのが少し面倒です。多用する場合はヘルパーを用意しても良さそう。

// v1 の例
[FunctionName("Function1")]
public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");

    return req.CreateResponse(HttpStatusCode.OK, "Hello, world ");
}

// v2 の例
[FunctionName("Function1")]
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    return new OkObjectResult($"Hello, world");
}

v2 の方が Query や Post Data へのアクセスが行いやすいです。マルチパートデータの扱いも簡単なので、楽にアップロード周りのコードも書けるようになってます。

ConfigurationManager の削除

v2 というか .NET Core には ConfigurationManager が存在しないので、アプリ設定や接続文字列は環境変数から取るか、現時点では手動で IConfiguration を作成して取得します。

将来的には DI とかで取れるようになる気がします。最低でも標準でサポートされるはず。

config ファイルを修正

おまじない感ありますが local.settings.json に FUNCTIONS_WORKER_RUNTIME を追加しておきます。

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "AzureWebJobsStorage": "",
    "AzureWebJobsDashboard": ""
  }
}

host.json には version を追加しておくとよい感じです。

空っぽでも良いみたいですが、テンプレートでは version が付いているので合わせておきましょう。

{
  "version": "2.0"
}

スキーマが大きく変わっているので、必要な設定を 2.0 向けに修正していきます。ドキュメントがあるので、それを確認しながら行えば問題ないはずです。

extensions 周りに互換性が無くなっているはずなので、何か書いている場合には注意。

新しいバージョンをリリース

既にデプロイまでの自動化を行っている場合、v2 へのコード側の対応をしたとしてもランタイムのバージョンが v1 のままなのでデプロイしても動作しません。

ちなみにポータルからはデプロイ済みの場合は変更できないようになっています。

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

Visual Studio からデプロイする場合はバージョンを自動で確認して、必要であれば変更もしてくれるので楽ですが、この手はあまり使えないでしょう。

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

割と致命的なのが既存のキーが引き継がれずに、新しく作成されることです。HttpTrigger で認証をキーで行っている場合、v2 に切り替えると動かなくなるので詰みます。新しく Function App を作成して、デプロイして切り替えを行うしかないでしょう。

コードの修正は正直大したことないので簡単でしたが、リリースに関しては少し面倒かなという印象です。既にプロダクション環境で動かしているものは移行計画を立てた方が良いでしょう。