Azure Functions の Bicep を node linux構成でできるだけシンプルに書いてみたメモ

## 概要
欲しいものは、TypescriptのFunctions。OSはLinux。

[Azure Functions の関数アプリのリソース デプロイを自動化](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-infrastructure-as-code?tabs=bicep%2Clinux%2Cdevops&pivots=consumption-plan)を見ながらbicepsファイルを作成した。
各Bicepの設定値の意味を確認していく。

<details><summary>最終的にできたbicepファイル</summary><div>

```functions.bicep
param storageAccountType string = 'Standard_LRS'
param location string = resourceGroup().location
var storageAccountName = '${uniqueString(resourceGroup().id)}azfunctions'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  location: location
  kind: 'StorageV2'
  sku: { name: storageAccountType }
}

var functionAppName = '${uniqueString(resourceGroup().id)}azfunctionsapp'
resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp,linux'
  properties: {
    reserved: true
    siteConfig: {
      linuxFxVersion: 'Node|20'
      appSettings: [
        {
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTSHARE'
          value: toLower(functionAppName)
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'node'
        }
      ]
    }
  }
}
```


</div></details>

[(2024.09.06 追記) bicepparamファイルを使ってみたメモ](https://qiita.com/hibohiboo/items/09dc4d115e5a29cbe90b)

## 環境
- az bicep v0.26.170

## Storage Account
[Bicepリファレンス](https://learn.microsoft.com/ja-jp/azure/templates/microsoft.storage/2023-01-01/storageaccounts?pivots=deployment-language-bicep)[SKU](https://learn.microsoft.com/ja-jp/rest/api/storagerp/srp_sku_types)

参考と変えた部分

プロパティ|プロパティの説明|理由
--|--|--
supportsHttpsTrafficOnly|ストレージ サービスへの https トラフィックを許可|デフォルト値がtrueとなっていたため削除
defaultToOAuthAuthentication|既定の認証が OAuth かどうか|FunctionsとOAuth認証の関わりが示されたドキュメントが見つからなかったため削除

## Web
### サーバーファーム
[リファレンス](https://learn.microsoft.com/ja-jp/azure/templates/microsoft.web/2022-09-01/serverfarms?pivots=deployment-language-bicep)
指定しなくても作成できると書いてある。一度、指定せずに作ってみる。

### WebSites
[Bicepリファレンス](https://learn.microsoft.com/ja-jp/azure/templates/microsoft.web/2022-09-01/sites?pivots=deployment-language-bicep)

不明な部分: linux だと reserved が必須となる。 何故？ [アプリケーションの構成](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-infrastructure-as-code?tabs=bicep%2Clinux%2Cdevops&pivots=consumption-plan#application-configuration)にも明記されていない。
予約なしで作るとどうなるのか → 一度作って確認してみる 

#### チェック: 有効なLinuxのバージョンを確認する
[linuxfxversion](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-app-settings#linuxfxversion) 
[ランタイムバージョンの設定](https://learn.microsoft.com/ja-jp/azure/azure-functions/set-runtime-version?tabs=portal&pivots=platform-linux)

```
$ az functionapp list-runtimes --os linux --query "[].{stack:join(' ', [runtime, version]), LinuxFxVersion:linux_fx_version, SupportedFunctionsVersions:to_string(supported_functions_versions[])}" --output table | grep node
node 20            Node|20              ["4"]
node 18            Node|18              ["4"]
node 16            Node|16              ["4"]
node 14            Node|14              ["4"]
```

#### 確認:AppServiceの環境変数の意味
[functions-app-settings](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-app-settings)より
環境変数|説明
--|--
AzureWebJobsSecretStorage|Functions ランタイムで通常の操作に使用する Azure Storage アカウント接続文字列
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING|関数アプリのコードと構成が格納されているストレージ アカウントの接続文字列。
WEBSITE_CONTENTSHARE|関数アプリのコードと構成ファイルを保存するために Functions で使用するファイル共有の名前。
FUNCTIONS_EXTENSION_VERSION|関数アプリをホストする Functions ランタイムのバージョン。チルダ (~) は、そのメジャー バージョンの最新バージョンを使用することを意味する
FUNCTIONS_WORKER_RUNTIME|ランタイムの言語


## ここまでの設定でのbicep

```biceps/functions.bicep
param storageAccountType string = 'Standard_LRS'
param location string = resourceGroup().location
var storageAccountName = '${uniqueString(resourceGroup().id)}azfunctions'

// Standard 汎用 v2 ストレージ アカウント
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  location: location
  kind: 'StorageV2'
  sku: { name: storageAccountType }
}

// 従量課金ホスティング プランのリソースを明示的に定義する必要はありません。

// 関数アプリ リソースは、少なくとも functionapp を含むタイプ Microsoft.Web/sites とタイプ kind のリソースによって定義されます。
var functionAppName = '${uniqueString(resourceGroup().id)}azfunctionsapp'
resource functionApp 'Microsoft.Web/sites@2022-09-01' = {
  name: functionAppName
  location: location
  kind: 'functionapp,linux'
  properties: {
    siteConfig: {
      linuxFxVersion: 'Node|20'
      appSettings: [
        {
          name: 'AzureWebJobsStorage'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
          value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
        }
        {
          name: 'WEBSITE_CONTENTSHARE'
          value: toLower(functionAppName)
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
        {
          name: 'FUNCTIONS_WORKER_RUNTIME'
          value: 'node'
        }
      ]
    }
  }
}
```

実行

```bash:bin/create.bash
BIN_DIR=$(cd $(dirname $0) && pwd)
BICEP_DIR=$(cd $BIN_DIR/../biceps && pwd)
RESOURCE_GROUP_NAME='hoge'
LOCATION=japaneast

cd $BICEP_DIR && az deployment group create \
  --name functionsDeployment \
  --template-file functions.bicep \
  -g $RESOURCE_GROUP_NAME
```


## 遭遇したエラー
### The parameter LinuxFxVersion has an invalid value
nodeの先頭を小文字にしていた。

```diff
-     linuxFxVersion: 'node|20'
+      linuxFxVersion: 'Node|20'
```

修正しても変わらず。
[stack over flow](https://stackoverflow.com/questions/72478340/error-the-parameter-linuxfxversion-has-an-invalid-value-when-deploying-my-azure)によると、`reserved:true`がついていない場合にもこのエラーになるもよう。

```diff
  properties: {
+    reserved: true
    siteConfig: {
      linuxFxVersion: 'Node|20'
```

## 作成してみた結果
### サーバーファーム

> 指定しなくても作成できると書いてある。一度、指定せずに作ってみる。

sku プロパティ|値|説明
--|--|--
Pricing plan|Y1|sku name, sku size
tier|Dynamic|価格レベル:従量課金プラン
family|Y|
capacity|0

[リファレンス](https://learn.microsoft.com/ja-jp/azure/templates/microsoft.web/2022-09-01/serverfarms?pivots=deployment-language-bicep) [sku](https://learn.microsoft.com/ja-jp/azure/templates/microsoft.web/2022-09-01/serverfarms?pivots=deployment-language-bicep#skudescription)

### WebSites
> 予約なしで作るとどうなるのか → 一度作って確認してみる 

ExtendedCode：01007 `The parameter LinuxFxVersion has an invalid value`エラーが発生することが分かった。
エラーメッセージ間違ってない？

## 実行
手動でデプロイしたところ、動作することまで確認した。

## 参考

[Azure Functions の関数アプリのリソース デプロイを自動化](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-infrastructure-as-code?tabs=bicep%2Clinux%2Cdevops&pivots=consumption-plan)
[クイック スタート: Bicep を使用して Azure Functions リソースを作成してデプロイする](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-create-first-function-bicep?tabs=CLI)
[　▶ AppServiceプランでどの価格レベルを選べばいいかわからず、本番環境なのにBasicを選んでしまう方](https://www.azureportal-site.com/entry/appserviceplan)

[bicep_function_app](https://github.com/sirBassetDeHound/bicep_function_app)
[アプリ設定のリファレンス](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-app-settings)
[Bicep で Linux の App Service Plan が上手く作れなかった話](https://chiguniiita.hatenablog.jp/entry/2022/03/20/224724)
[AppServicePlanProperties](https://learn.microsoft.com/en-us/azure/templates/microsoft.web/serverfarms?tabs=bicep&pivots=deployment-language-bicep#appserviceplanproperties)
[ARM テンプレートの構造と構文について](https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/templates/syntax)
[Bicep ファイルの構造と構文について](https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/file)
[Bicepを使ってAzureDevOpsのパイプラインからリソースをデプロイしたメモ](https://qiita.com/hibohiboo/items/e7c1d14a30f914fae4d8)
[Azure Functionsの全般設定のTips](https://zenn.dev/ykoiz/articles/fe759b91ab22ea)
[main.bicep](https://github.com/Azure-Samples/function-app-arm-templates/blob/main/function-app-linux-consumption/main.bicep)
[Azure Functions で使える Dynamic Service Plan について調べてみた](https://blog.shibayan.jp/entry/20160402/1459575658)

[Bicep Playground](https://azure.github.io/bicep/)