BicepにおけるSubnetの定義方法

元々の定義状況

BicepでVNET及びサブネットを以下のようにして定義していた。

<VNet>
resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' = {
  name: vnetName
  location: location
  tags: tags
  properties: {
    addressSpace: {
      addressPrefixes: [
        addressSpace
      ]
    }
  }
}
<Subnet>
resource subnetInternal 'Microsoft.Network/virtualNetworks/subnets@2023-09-01' = {
  name: 'internal'
  parent: vnet
  properties: {
    addressPrefix: subnetInternalPrefix
    networkSecurityGroup: {
      id: internalNsg.id
    }
    routeTable: {
      id: routeTableInternal.id
    }
  }
}

要は、個別リソースとして定義してからparent: vnetで親リソースとして関連付けをするような記載方法である。

この場合、デプロイした際にどうなるかというと、1回目のデプロイは正常に実行できる。

<デプロイコマンド>※サーバーもあるのでそれの資格情報が入ってます

   az deployment group create `
     --resource-group rg-trial `
     --template-file main.bicep `
     --parameters workloadName=trial01 `
                   windowsAdminUsername=<YourWindowsAdminUser> `
                   windowsAdminPassword="<YourWindowsAdminPassword>" `
                   linuxAdminUsername=<YourLinuxAdminUser> `
                   linuxAdminPassword="<YourLinuxAdminPassword>"

デプロイ状況は全て成功

リソースグループにリソースも作成される

問題点の発覚

しかしながら、適当な修正をかけて2回目実行しようとしたときに以下のデプロイエラーが出る。

今回はパラメータになんも関係ないREADMEに追記して実行したらエラーになった。

Bicepは冪等性があるので変更を加えていない場所はスキップされるはずなのに何故?と思って調査していたところ、どうもSubnetの記述方法がよくないらしい。

原因

Subnetを子リソースとして個別に定義すると、Azure内部でデプロイ時に以下のような動きをする

1回目のデプロイ:

  • VNet を作成
  • サブネットを子リソースとして5つ作成
  • Azure は「このテンプレートがこの5つのサブネットを管理している」と記録

2回目のデプロイ:

  • ARM は「このテンプレートが管理すべきサブネットは5つ」を再確認
  • 既存の VNet を見ると、サブネットが5つある
  • しかし、ARM は「既存サブネットがこのテンプレートで作成されたものか」を厳密に再評価
  • サブネット定義を再解析する過程で、内部的に以下を実行:

“既存サブネット削除 → 新サブネット作成”

→NIC が接続されているため削除が失敗

ということらしい。

 

解決策

裏側の動きはよくわからないが、とにかくSubnetを個別リソースのように定義することがよくないので、VNETのプロパティとしてVNETリソース定義の中に混ぜると正常にデプロイが完了する。

<変更:VNETの中でSubnetを定義する>
resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' = {
  name: vnetName
  location: location
  tags: tags
  properties: {
    addressSpace: {
      addressPrefixes: [
        addressSpace
      ]
    }
    subnets: [
      {
        name: 'internal'
        properties: {
          addressPrefix: subnetInternalPrefix
          networkSecurityGroup: {
            id: internalNsg.id
          }
          routeTable: {
            id: routeTableInternal.id
          }
        }
      }
	・・・
 }
}

これで実行してみるとデプロイエラーが消えました。

コメント