Bicep を使用して、Azure リソースの設定を行う際に、scope / parent で 拡張リソース を使用することで、設定を行うというケースがあります。
これらの属性にリソースを設定する際には、リソースの ID / 名称ではなく、Bicep 内で定義しているリソースのシンボリック名を指定する必要があります。
実際の設定例としては、診断設定のリソースとなる Microsoft.Insights/diagnosticSettings があります。
このリソースは Azure の「診断設定」を行うためのリソース定義となりますが、「どのリソースに対して診断設定を行うか」については、「scope」に対して、「resourceSymbolicName」を指定する必要があります。
Azure ストレージを例とすると、ストレージアカウントを作成するための Microsoft.Storage/storageAccounts の Bicep 内で診断設定を実施するのであれば、同一のファイル内にストレージアカウントを作成する定義があるため、ストレージ対しての診断設定のためのシンボリック名を指定することは容易です。
診断設定は様々なリソースに対して設定が可能なため「診断設定をまとめたモジュールを作成したい」というような場合には、診断設定を行うための Bicep のファイル内でシンボリック名を定義する必要があるのではないでしょうか。
本投稿では、異なるモジュールで定義されたリソースを、シンボリック名として作成するための方法について考えてみたいと思います。
サンプルとして作成した Bicep ファイルについては https://github.com/MasayukiOzawa/bicep-sample/tree/main/diagSetting で公開しています。
今回は作成したストレージアカウントに対して、診断設定を行うというシナリオを検討しています。
Contents
ストレージアカウントの作成 (storage.bicep)
ストレージアカウントについては、次の Bicep ファイルで作成をしています。
param storageAccountSku string = 'Standard_LRS' param location string = resourceGroup().location var storageNameBase = 'st${uniqueString(resourceGroup().id)}' resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = [ for index in range(0, 3): { name: '${storageNameBase}${index}' location: location sku: { name: storageAccountSku } kind: 'StorageV2' } ] output storageAccounts array = [ for i in range(0, 3): { name: storageAccount[i].name id: storageAccount[i].id } ]
今回は for を使用して、複数 (0~2 の連番の 3 個) のストレージアカウントを作成し、作成したストレージアカウントの一部の情報は、後続の処理となる診断設定を行う際に必要となるため output で出力しています。(for の使い方については 条件とループを使用して柔軟な Bicep テンプレートを作成する が参考になります)
output で出力をした情報については、Azure ポータルで展開を実施したリソースグループのデプロイから、該当のデプロイを選択し「出力」から確認をすることができ、出力情報のデバッグをしたい場合にはデプロイから確認をすることができます。
output を行う場合、単一の情報を返すことももちろん可能ですが、配列やオブジェクトを使用して連携するようにしておくと記載をシンプルにすることもできるかと思います。(インテリセンスが効きづらくなるという弊害は少しありますが)
output でシンボリック名を指定して出力
今回は作成したオブジェクトの一部の情報 (name / id) のみを output に含めましたが、output で出力をする際には、作成したストレージアカウントのシンボリック名を使用して情報を出力することも可能です。
output storageAccounts array = [for i in range(0, 3): storageAccount[i]]
シンボリック名で指定した場合、output に含まれるのは次のような情報となっており、展開したストレージアカウントの各種情報が含まれたものとなっています。
作成したリソースの複数の情報を活用する場合には、このようにシンボリック名で情報を出力することで記載をシンプルにすることができるケースもあるかと思います。
Log Analytics ワークスペース の作成 (logAnalytics.bicep)
次に Log Analytics ワークスペースを作成します。
param location string = resourceGroup().location param workspaceName string = 'log-myLogAnalyticsWorkspace' resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { name: workspaceName location: location properties: { sku: { name: 'PerGB2018' } } } output workspaceId string = logAnalyticsWorkspace.id
こちらは単純に作成するだけですね。診断設定ではワークスペースの ID が必要となりまので、この情報を output として指定しています。
main モジュールの作成 (main.bicep)
もう一つのリソースとして診断設定がありますがその前に今回作成する Bicep を呼び出すための main モジュールを作成しておきます。
module storage './storege.bicep' = { name: 'storageDeploy' } module logAnalytics './logAnalytics.bicep' = { name: 'logAnalyticsDeploy' } module diag './diagSetting.bicep' = { name: 'diagSettingDeploy' params: { storageAccounts: storage.outputs.storageAccounts workspaceId: logAnalytics.outputs.workspaceId } }
今回のメインの題材となる診断設定については「diag」で作成をしており、診断設定の情報を格納するための Log Analytics ワークスペースのワークスペース ID と、設定対象となるストレージアカウントの情報を渡しています。
診断設定の作成 (diagSetting.bicep)
ここまでで診断設定で必要となるリソース / 情報が確定しましたので、最後にストレージアカウントに対して診断設定を行います。
診断設定を作成するための Bicep ファイルが以下となります。
param storageAccounts array param workspaceId string param blobLogSetting array = [ { categoryGroup: 'allLogs', enabled: true } { categoryGroup: 'audit', enabled: true } ] param metrics array = [ { category: 'Transaction', enabled: true } ] param diagBaseName string = 'diag-{0}' // ストレージアカウントの診断設定 resource storage 'Microsoft.Storage/storageAccounts@2022-09-01' existing = [ for (storageAccount, index) in storageAccounts: { name: storageAccount.name } ] resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ for (storageAccount, index) in storageAccounts: { name: replace(diagBaseName, '{0}', storageAccount.name) scope: storage[index] properties: { metrics: metrics workspaceId: workspaceId } } ] // ストレージアカウントの BLOB についての診断設定 resource blob 'Microsoft.Storage/storageAccounts/blobServices@2023-05-01' existing = [ for (storageAccount, index) in storageAccounts: { name: 'default' parent: storage[index] } ] resource diagnosticBlobSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ for (storageAccount, index) in storageAccounts: if (contains(storageAccount.name, 'stjb6gfh2nnkvfe0')) { name: '${replace(diagBaseName, '{0}', storageAccount.name)}-blob' scope: blob[index] properties: { logs: blobLogSetting metrics: metrics workspaceId: workspaceId } } ]
他のファイル (モジュール) で作成したリソースの参照
前述のとおり、診断設定を行うためには設定対象となるリソースを「scope」で指定する必要があります。
ストレージアカウントについては「storage.bicep」で作成をしており、診断設定のファイル内では作成していません。
このような他のファイル (モジュール) で作成したリソースを、シンボリック名で使用したい場合には existing を使用して参照を行っておきます。
resource storage 'Microsoft.Storage/storageAccounts@2022-09-01' existing = [ for (storageAccount, index) in storageAccounts: { name: storageAccount.name } ]
これにより他のファイルで作成したリソースについてもシンボリック名として利用することが可能となります。
今回はストレージアカウントとして 3 個のリソースをしているため、 for を使用して、ストレージアカウント作成時に output として、指定した作成対象のストレージアカウント分、繰り返して処理を実行しています。
ストレージアカウントの作成時に output をシンボリック名で出力した場合
ストレージアカウントのシンボリック名を output した場合、出力される情報にはストレージアカウント名の単体を示す情報は含まれていません。
「"resourceId": "Microsoft.Storage/storageAccounts/stjb6gfh2nnkvfe0"」というような形式で resouceId にストレージアカウント名が含まれている状態となります。
そのため、ストレージアカウント名の指定については last / split を使用して、resourceId から切り出す必要があります。
last(split(storageAccount.resourceId, '/'))
同一の設定を複数のストレージアカウントに対して実施する
診断設定は同一種類のリソースであれば、大体の場合、同一の設定になることが多いのではないでしょうか。
今回はストレージアカウントを 3 個作成していますが、それぞれのリソースに対して、個別に定義を記載すると冗長な定義が多くなりメンテナンス性の低下につながる可能性があります。
そのため、今回は次のような記載にして for を使用しながら 1 箇所の resource の記述で 3 個のストレージアカウントに同様の設定を行うようにしています。
resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ for (storageAccount, index) in storageAccounts: { name: replace(diagBaseName, '{0}', storageAccount.name) scope: storage[index] properties: { metrics: metrics workspaceId: workspaceId } } ]
ストレージアカウントで取得する診断情報の項目については、次のような記載にしてパラメーターとして切り出しています。
param metrics array = [ { category: 'Transaction', enabled: true } ]
Bicep には、ファイル関数 があるため、このような設定に対しての定義は外部ファイル (json / yaml) として切り出しておき、loadJsonContent / loadYamlContent で呼び出して配列 / オブジェクトとして利用するということも可能ではないでしょうか。
ストレージアカウントの場合、ストレージアカウントの診断とデータストレージの診断が異なる設定となっていますので「storageAccounts」「storageAccounts/blobServices」に対して、診断設定を行うようにしています。(blobServices については、特定のストレージアカウントのみ診断設定が行われるようになっています)
特定の条件の場合のみ設定を行う場合
今回 blob の診断設定については、次のような記載をしており、if で、ストレージアカウント名が「stjb6gfh2nnkvfe0」の場合のみ、blob の診断設定を実施するようにしています。
resource diagnosticBlobSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [ for (storageAccount, index) in storageAccounts: if (contains(storageAccount.name, 'stjb6gfh2nnkvfe0')) { name: '${replace(diagBaseName, '{0}', storageAccount.name)}-blob' scope: blob[index] properties: { logs: blobLogSetting metrics: metrics workspaceId: workspaceId } } ]
条件によって設定を変更したい場合にはこのような記述も検討することができます。
以下が実際に展開した結果となりますが blob の診断設定については特定のストレージアカウントだけ設定が行われています。
まとめ
今回ケースでは診断設定のみ切り出していますので、「storage.bicep」内に診断設定の定義を記載することも当然ながら可能となっています。
しかし、リソースの数が増えてくると、リソースの作成時に診断設定も合わせて実施すると、診断設定を行っているリソースの確認をする際に複数の Bicep ファイルの内容から設定状況を確認する必要があるということが出てきてしまうのではないでしょうか。
好みによるところも大きいかと思いますが、本投稿のように、診断設定がまとまっている Bicep ファイルが作成できると、次のようなメリットを享受できるケースもあるのではないでしょうか。
- 設定状況を一つのファイルから網羅的に確認することができる
- リソースの種類によって設定が共通化できていると、設定変更の必要が発生した際に手数を少なくして設定の変更を反映することができる
リソースの種類によっては「特定の設定を追加する前に実施しておく必要がある」というような設定もあり、すべての設定が切り出せるわけではないのですが、このような方法もあるということは覚えておいてもよいのではないでしょうか。