🦔
Bicepで使える構文と使い所をまとめてみる(2)
bicepで使える構文と使い所を整理してみようと思います。ものによっては、もっとスマートな書き方があるでしょうが、そう感じるようになったらそれはそれで良いのではないでしょうか。
- 前回の記事
パラメータをオブジェクト型にして扱う
-
module
で大量のパラメータを受け渡しする場合、object
型にすると記述量が減る。 - 更に配列(
array
型)にしてfor
文を使ってで複数デプロイできる - デプロイをシリアル処理にしたい場合は
batchSize
デコレータを使用する
- 以下は、MetricAlertのデプロイテンプレートの例
- Alertのデプロイテンプレートを共通モジュールとする
- Alert定義の
param
での受け渡しはarray
型1つにまとめる -
for
文を使ってarray
オブジェクトで受け取ったパラメータを使用してデプロイ - デメリットは、コーディング時に型チェックがされないことでしょうか
param alerts array
@batchSize(1)
resource alert_metric 'microsoft.insights/metricalerts@2018-03-01' = [for alert in alerts: {
name: alert.alert_name
location: 'global'
properties: {
enabled: alert.enabled
description: alert.description
scopes: alert.scopes
severity: alert.severity
evaluationFrequency: alert.evaluation_frequency
windowSize: alert.window_size
criteria: {
allOf: [
{
name: 'metric'
metricNamespace: 'Microsoft.DBforPostgreSQL/flexibleServers'
metricName: alert.metric_name
operator: alert.operator
threshold: alert.threshold
timeAggregation: alert.time_aggregation
skipMetricValidation: true
criterionType: 'StaticThresholdCriterion'
}
]
'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'
}
autoMitigate: true
targetResourceType: 'Microsoft.DBforPostgreSQL/flexibleServers'
targetResourceRegion: alert.location
actions: [
{
actionGroupId: alert.action_id
webHookProperties: {
}
}
]
}
}]
- 以下はMetricAlertのデプロイテンプレートを呼び出す側の例
- alertsパラメータで複数のAlert定義のパラメータを渡す
- 可読性も上がるし、Alert定義の追加もしやすい
param now string = utcNow('yyyyMMdd-HHmmss')
param location string = resourceGroup().location
param psql_name string
param action_name string
param action_rg_name string
module main './modules/metric-psql.bicep' = {
name: 'alert-postgresql-${now}'
params: {
alerts: [
{
alert_name: 'alert-psql-cpu_percent'
enabled: true
description: 'PostgreSQLのCPU(%)Alert'
scopes: [ psql.id ]
severity: 2
evaluation_frequency: 'PT5M'
window_size: 'PT5M'
metric_name: 'cpu_percent'
operator: 'GreaterThanOrEqual'
threshold: 80
time_aggregation: 'Average'
location: location
action_id: action_group.id
}
//
// 省略: 2つ目以降のAlert定義
//
]
}
}
resource psql 'Microsoft.DBforPostgreSQL/flexibleServers@2022-01-20-preview' existing = {
name: psql_name
}
resource action_group 'microsoft.insights/actionGroups@2022-06-01' existing = {
name: action_name
scope: resourceGroup(action_rg_name)
}
contains関数
-
object
型にキーが含まれているかどうかは、contains()
を使用する - キーが含まれていなければ
false
が返ってくる
- 以下は、subnetのデプロイテンプレートの例
- subnetのデプロイテンプレートを共通モジュールとする
- subnet定義の
param
での受け渡しはarray
型1つにまとめる -
for
文を使ってarray
オブジェクトで受け取ったパラメータを使用してデプロイ -
contains
を使ってキーの存在チェックを行い、三項演算子を組み合わせてfalse
の場合は、既定としたい値を設定するといった使い方をする
param vnet_name string
param subnets array
@batchSize(1)
resource subnet 'Microsoft.Network/virtualNetworks/subnets@2022-11-01' = [for subnet in subnets: {
name: subnet.name
parent: vnet
properties: {
addressPrefix: subnet.cidr
privateLinkServiceNetworkPolicies: contains(subnet, 'pls') ? subnet.pls : 'Enabled'
privateEndpointNetworkPolicies: contains(subnet, 'pe') ? subnet.pe : 'Enabled'
networkSecurityGroup: contains(subnet, 'nsg') ? {
id: resourceId('Microsoft.Network/networkSecurityGroups', subnet.nsg)
} : null
serviceEndpoints: contains(subnet, 'se') ? subnet.se : null
delegations: contains(subnet, 'delegations') ? subnet.delegations : null
routeTable: contains(subnet, 'udr') ? {
id: resourceId('Microsoft.Network/routeTables', subnet.udr)
} : null
}
}]
resource vnet 'Microsoft.Network/virtualNetworks@2022-11-01' existing = {
name: vnet_name
}
- 以下はsubnetのデプロイテンプレートを呼び出す側の例
- subnet定義を_subnet変数に記述して、
module
構文のパラメータで配列として渡す - 可読性も上がるし、subnet定義の追加もしやすい
-
delegations
やrouteTable
を設定する場合もデプロイで使用する共通モジュールは変更が不要である
- subnet定義を_subnet変数に記述して、
param now string = utcNow('yyyyMMdd-HHmmss')
param vnet_name string
var _subnets = {
AzureBastionSubnet: {
name: 'AzureBastionSubnet'
cidr: '10.0.254.0/26'
nsg_name: 'nsg-AzureBastionSubnet'
}
GatewaySubnet: {
name: 'GatewaySubnet'
cidr: '10.0.254.64/26'
}
'snet-01': {
name: 'snet-01'
cidr: '10.0.0.0/27'
nsg: 'nsg-snet-01'
pls: 'Enabled'
pe: 'Enabled'
se: [
{
service: 'Microsoft.KeyVault'
}
{
service: 'Microsoft.Storage'
}
]
}
}
module subnets './modules/snet.bicep' = {
name: 'subnet-${now}'
params: {
vnet_name: vnet_name
subnets: [
_subnets.AzureBastionSubnet
_subnets.GatewaySubnet
_subnets['snet-01']
]
}
}
if文とconcat関数
- if文は真偽判定でデプロイをする/しないを決定したい場合で使用する
- 配列の結合は
concat()
で行う
- 以下はFront DoorのSecurity Policiesのデプロイテンプレートを呼び出す側の例
- Security Policiesは、WAFを適用する対象のエンドポイントを
resourceId
をidオブジェクトの配列にして設定する - エンドポイントは、Front Doorの既定のエンドポイントとカスタムドメインの2種類があり、それぞれ取得する必要がある
- そのため、取得結果のidオブジェクト配列をそれぞれ作成して
concat()
で結合している - Security Policiesデプロイ時にエンドポイントのidオブジェクト配列が空(
length()
が0)ならばデプロイをしないようにif
文を使用
- Security Policiesは、WAFを適用する対象のエンドポイントを
param fd_name string
param fd_ep_names array = []
param fd_domain_names array = []
param fd_sp_name string
param fd_waf_name string
var ep_ids = [for ep_name in fd_ep_names: {
id: resourceId('Microsoft.Cdn/profiles/afdEndpoints', fd_name, ep_name)
}]
var domain_ids = [for domain_name in fd_domain_names: {
id: resourceId('Microsoft.Cdn/profiles/customDomains', fd_name, replace(domain_name, '.', '-'))
}]
var ids = concat(ep_ids, domain_ids)
resource fd_sp 'Microsoft.Cdn/profiles/securityPolicies@2022-11-01-preview' = if (0 != length(ids)) {
name: fd_sp_name
parent: fd
properties: {
parameters: {
type: 'WebApplicationFirewall'
associations: [
{
domains: ids
patternsToMatch: [
'/*'
]
}
]
wafPolicy: {
id: waf.id
}
}
}
}
resource waf 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2022-05-01' existing = {
name: fd_waf_name
}
resource fd 'Microsoft.Cdn/profiles@2022-11-01-preview' existing = {
name: fd_name
}
- 以下はVirtual Machineをデプロイするテンプレートの例
-
if
文はexisting
を使用する場合でも同様の使い方が可能 - 以下の例では、可用性セットと近接配置グループが指定されていれば対象の
resourceId
をVMの設定として行っている
-
param location string = resourceGroup().location
param vm_name string
param aset_name string = ''
param ppg_name string = ''
var _is_aset = !empty(aset_name)
var _is_ppg = !empty(ppg_name)
resource avail_set 'Microsoft.Compute/availabilitySets@2022-11-01' existing = if (_is_aset) {
name: aset_name
}
resource ppg 'Microsoft.Compute/proximityPlacementGroups@2022-11-01' existing = if (_is_ppg) {
name: ppg_name
}
resource vm 'Microsoft.Compute/virtualMachines@2022-11-01' = {
name: vm_name
location: location
properties: {
//省略
proximityPlacementGroup: _is_ppg ? {
id: ppg.id
} : null
availabilitySet: _is_aset ? {
id: avail_set.id
} : null
}
//省略
}
以上.
(1), (2)の書き方ぐらいまで身につけると作成できる幅が広がってくると思います。
Discussion