Apple Silicon(M2 MacBook Air)上でAzure Functionsのローカル開発を試す

昨年8月にM2 MacBook Air上でAzure Functionsのローカル開発を試してみてうまく動かないという状態をメモしました。

miyohide.hatenablog.com

時間も経っていることなので再度試してみました。

環境

環境は以下の通りです。まずはAzure Functions Core Tools。

Azure Functions Core Tools
Core Tools Version:       4.0.4915 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.14.0.19631

Javaのバージョンは以下の通り。

openjdk version "17.0.5" 2022-10-18 LTS
OpenJDK Runtime Environment Microsoft-6841604 (build 17.0.5+8-LTS)
OpenJDK 64-Bit Server VM Microsoft-6841604 (build 17.0.5+8-LTS, mixed mode)

サンプルアプリ

サンプルアプリはAzure Functionsのチュートリアルから。

learn.microsoft.com

環境設定

実際に動作させるためには、環境変数JAVA_HOMEを設定する必要があります。macOSにおいては以下の方法でJAVA_HOMEを設定することができます。

export JAVA_HOME=`/usr/libexec/java_home -v "17"`

HttpTrigger以外ではAzure Storageの設定が必要です。今回はAzuriteエミュレーターを使用します。

learn.microsoft.com

接続先をlocal.settings.jsonに以下の記述をします。AzureWebJobsStorageとしてUseDevelopmentStorage=trueを指定するのがポイントです。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "java"
  }
}

あとはgradle azureFunctionsRunを実行すれば起動します。

% gradle azureFunctionsRun

> Configure project :
default messager has already been registered

> Task :azureFunctionsPackage

Step 1 of 8: Searching for Azure Functions entry points
2 Azure Functions entry point(s) found.

Step 2 of 8: Generating Azure Functions configurations
Generation done.

Step 3 of 8: Validating generated configurations
Validation done.

Step 4 of 8: Saving host.json
Successfully saved to /Users/xxxxxx/work/azure_func_java/build/azure-functions/azure_func_java/host.json

Step 5 of 8: Saving local.settings.json
Successfully saved to /Users/xxxxxxe/work/azure_func_java/build/azure-functions/azure_func_java/local.settings.json

Step 6 of 8: Saving configurations to function.json
Starting processing function: TimerTriggerJava
Successfully saved to /Users/xxxxxx/work/azure_func_java/build/azure-functions/azure_func_java/TimerTriggerJava/function.json
Starting processing function: HttpTriggerJava1
Successfully saved to /Users/xxxxxx/work/azure_func_java/build/azure-functions/azure_func_java/HttpTriggerJava1/function.json

Step 7 of 8: Copying JARs to staging directory: /Users/xxxxxx/work/azure_func_java/build/azure-functions/azure_func_java
Copied successfully.

Step 8 of 8: Installing function extensions if needed
Extension bundle specified, skip install extension
Successfully built Azure Functions.

> Task :azureFunctionsRun
Azure Function App's staging directory found at: /Users/xxxxxx/work/azure_func_java/build/azure-functions/azure_func_java

Azure Functions Core Tools
Core Tools Version:       4.0.4915 Commit hash: N/A  (64-bit)
Function Runtime Version: 4.14.0.19631

[2023-01-15T07:28:44.938Z] OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
[2023-01-15T07:28:44.960Z] Listening for transport dt_socket at address: 5005

Functions:

        HttpTriggerJava1: [GET,POST] http://localhost:7071/api/HttpTriggerJava1

        TimerTriggerJava: timerTrigger

For detailed output, run func with --verbose flag.
[2023-01-15T07:28:45.239Z] Worker process started and initialized.
[2023-01-15T07:28:49.937Z] Host lock lease acquired by instance ID '0000000000000000000000001869F4F6'.

Http triggerを実装し、アクセスすると、以下のようにログが出力され無事動くことが確認できました。

[2023-01-15T07:16:24.368Z] Executing 'Functions.HttpTriggerJava1' (Reason='This function was programmatically called via the host APIs.', Id=5c835b97-c978-4bd7-a051-35a2104d739f)
[2023-01-15T07:16:24.415Z] Java HTTP trigger processed a request.
[2023-01-15T07:16:24.415Z] Function "HttpTriggerJava1" (Id: 5c835b97-c978-4bd7-a051-35a2104d739f) invoked by Java Worker
[2023-01-15T07:16:24.442Z] Executed 'Functions.HttpTriggerJava1' (Succeeded, Id=5c835b97-c978-4bd7-a051-35a2104d739f, Duration=84ms)

Timer triggerを実装すると、以下のようにログが出力され無事動くことが確認できました。

[2023-01-15T07:30:00.042Z] Executing 'Functions.TimerTriggerJava' (Reason='Timer fired at 2023-01-15T16:30:00.0150420+09:00', Id=b0054268-981c-4559-a77a-76d9e25a15d5)
[2023-01-15T07:30:00.091Z] Function "TimerTriggerJava" (Id: b0054268-981c-4559-a77a-76d9e25a15d5) invoked by Java Worker
[2023-01-15T07:30:00.091Z] Java Timer trigger function executed at: 2023-01-15T16:30:00.085913
[2023-01-15T07:30:00.099Z] Executed 'Functions.TimerTriggerJava' (Succeeded, Id=b0054268-981c-4559-a77a-76d9e25a15d5, Duration=78ms)

これで動くことは確認できました。他のTriggerやBindingを使うと何か問題が出てくるかもしれませんが、とりあえず。

ちなみに、処理を終了させようとCtrl+Cで終了してもAzure Functions Core Toolsは起動したままになっていて、再度起動しようとしたときに以下のエラーメッセージで起動しませんでした。

> Task :azureFunctionsRun FAILED
Azure Function App's staging directory found at: /Users/xxxxxx/work/azure_func_java/build/azure-functions/azure_func_java
Port 7071 is unavailable. Close the process using that port, or specify another port using --port [-p].

FAILURE: Build failed with an exception.

このときは、既存のプロセスをlsof -i:7071で見つけ出して終了させるとOKです。

$ lsof -i:7071
COMMAND   PID     USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
func    94723 xxxxx  353u  IPv4 0xXXXXXXXXXXX      0t0  TCP *:7071 (LISTEN)
$ kill -9 94723