前の記事
前回、キーコンテナを使ったコードに書き直して接続をチェックしようとしたところ、
パブリックからのアクセスができるNICがなかったため、パブリックIPの設定を追加します。
特定箇所のみ設定変更したい場合のIaCでの運用について、「冪等性」という言葉が非常に重要らしいので掘り下げていきます。
冪等性とは
ある操作を何度繰り返しても結果が同じになるという性質
IT用語辞典出典

言葉はわかりますが、いまいちピンとこないですね。
前回、Bicepファイルを使ってデプロイしましたが、
今回も同じファイル、同じコマンドを使います。
同じファイルですが、NICに関する部分のみコードを追加する形になります。
そうすると、VMをデプロイしたファイルなので、再度VMとかももう1台作成されるのでは・・・?
というのに対する答えが「冪等性」があるので大丈夫ということになります。
もうちょっと具体的に
既にリソースが作成されている場合は「スキップ」
差分があれば「作成・変更」
の処理を自動で判断して行ってくれるのが冪等性という性質です。
そのため、変更点があればその部分のみコードの変更は必要ですが、
特定箇所のみを変更するためのスコープを絞ったデプロイは不要で、ファイルごとデプロイすれば差分のみが反映されます。
実際に変更してみる
NICに関するBicepファイルは以下のような記述になっていました。
nic.bicep
// modules/nic.bicep
@description('デプロイする場所 (リージョン)')
param location string
@description('NIC名')
param nicName string
@description('サブネットのリソースID')
param subnetId string
@description('プライベートIPアドレスの割り当て方法 (Dynamic or Static)')
param privateIpAllocationMethod string = 'Dynamic'
// ネットワークインターフェースのリソース定義
resource nic 'Microsoft.Network/networkInterfaces@2023-09-01' = {
name: nicName
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: privateIpAllocationMethod
subnet: {
id: subnetId // VNetのサブネットIDを参照
}
}
}
]
}
}
// NICのリソースIDを外部に出力
output nicId string = nic.id
確かにプライベートIPに関する設定しか書かれていないので、以下のように変更します。
<全体構成>
.
├── main.bicep # メインデプロイファイル (全てのモジュールを連携)
├── keyvault/
│ └── keyvault.bicep # Key Vault
└── modules/
├── vnet.bicep
├── nic.bicep # 変更あり: Public IPとNSGのIDを受け取る
├── vm.bicep
├── publicip.bicep # 新規追加
└── nsg.bicep # 新規追加
publicip.bicep
// modules/publicip.bicep
@description('デプロイする場所 (リージョン)')
param location string
@description('Public IPリソース名')
param publicIpName string
resource publicIP 'Microsoft.Network/publicIPAddresses@2023-09-01' = {
name: publicIpName
location: location
properties: {
publicIPAllocationMethod: 'Static'
}
sku: {
name: 'Standard'
tier: 'Regional'
}
}
// 出力: NICモジュールで参照するためにIDと接続確認用にIPアドレスを出力
output publicIpId string = publicIP.id
output publicIpAddress string = publicIP.properties.ipAddress
パブリックIPアドレスの設定を入れてます。
AzureはパブリックIPアドレス自体のリソースがあるので、これをデプロイします。
後ほど、NICリソースに関連付けてプライベートIPとパブリックIPのNICリソースを一纏めにします。
nsg.bicep
// modules/nsg.bicep
@description('デプロイする場所 (リージョン)')
param location string
@description('NSGリソース名')
param nsgName string
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-09-01' = {
name: nsgName
location: location
properties: {
securityRules: [
{
name: 'AllowRDPInbound'
properties: {
priority: 100
direction: 'Inbound'
access: 'Allow'
protocol: 'Tcp'
sourceAddressPrefix: '*' // ⚠️ 運用時は特定のIPに制限すべき
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '3389' // Windows VM (RDP) のポート
}
}
]
}
}
// 出力: NICモジュールで参照するためにIDを出力
output nsgId string = nsg.id
一旦、テストなのでインターネットから3389でアクセスできるようにしました。
nic.bicep
// modules/nic.bicep
@description('デプロイする場所 (リージョン)')
param location string
@description('NIC名')
param nicName string
@description('サブネットのリソースID')
param subnetId string
// --- 新規追加パラメータ ---
@description('NSGのリソースID')
param nsgId string
@description('Public IPのリソースID')
param publicIpId string
// NIC(publicIP)のリソース定義
resource nic 'Microsoft.Network/networkInterfaces@2023-09-01' = {
name: nicName
location: location
properties: {
// 1. NSGの関連付け
networkSecurityGroup: {
id: nsgId
}
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
privateIPAllocationMethod: 'Dynamic'
subnet: {
id: subnetId
}
// 2. Public IPの関連付け
publicIPAddress: {
id: publicIpId
}
}
}
]
}
}
output nicId string = nic.id
AzureのNICリソースは1つのリソースにプライベートIPとパブリックIPを持つことができるので、同じリソース内でどちらも定義しています。
NSGもNICに割り当てています。
main.bicep
// main.bicep
@description('デプロイする場所 (リージョン)')
param location string = resourceGroup().location
// --- 必須パラメータ ---
@description('VM名')
param vmName string
@description('管理者ユーザー名')
param adminUsername string
// --- Key Vault 関連パラメータ (外部からIDを受け取る) ---
@description('既に作成されているKey Vaultの完全なリソースID')
param existingKeyVaultId string
@description('Key Vaultに保存されているVM管理者パスワードのシークレット名')
param adminPasswordSecretName string = 'vm-admin-password'
// --- ネットワーク/VM設定パラメータ ---
@description('仮想ネットワーク名')
param vnetName string = 'vnet-deploy-bicep'
@description('サブネット名')
param subnetName string = 'subnet-deploy-bicep'
@description('NIC名')
param nicName string = 'nic-deploy-bicep'
@description('VMのサイズ (例: Standard_B1s)')
param vmSize string = 'Standard_B1s'
// --- Key Vault 参照の準備 ---
// Key Vault IDから Key Vault 名を抽出
var keyVaultName = last(split(existingKeyVaultId, '/'))
// Key Vault のプロバイダー情報を取得するための変数 (Bicepが参照を解決するために必要)
// Bicepでは外部リソースへの参照に `resourceId()` が使われますが、Key Vault参照には特殊な構文が必要です。
var keyVaultReference = resourceId(
subscription().subscriptionId,
resourceGroup().name,
'Microsoft.KeyVault/vaults',
keyVaultName
)
// --- 1. Public IP モジュールのデプロイ ---
module publicIpModule 'modules/publicip.bicep' = {
name: 'publicip-deployment'
params: {
location: location
publicIpName: '${vmName}-pip'
}
}
// --- 2. NSG モジュールのデプロイ ---
module nsgModule 'modules/nsg.bicep' = {
name: 'nsg-deployment'
params: {
location: location
nsgName: '${vmName}-nsg'
}
}
// 3. 仮想ネットワークモジュールのデプロイ
module vnetModule 'modules/vnet.bicep' = {
name: 'vnet-deployment'
params: {
location: location
vnetName: vnetName
subnetName: subnetName
}
}
// 4. ネットワークインターフェースモジュールのデプロイ
module nicModule 'modules/nic.bicep' = {
name: 'nic-deployment'
params: {
location: location
nicName: '${vmName}-nic'
subnetId: vnetModule.outputs.subnetId
// Public IPとNSGモジュールの出力を渡す
nsgId: nsgModule.outputs.nsgId
publicIpId: publicIpModule.outputs.publicIpId
}
}
// 5. 仮想マシンモジュールのデプロイ
module vmModule 'modules/vm.bicep' = {
name: 'vm-deployment'
params: {
location: location
vmName: vmName
adminUsername: adminUsername
vmSize: vmSize
nicId: nicModule.outputs.nicId
// Key Vault 参照をシークレットURIとしてVMモジュールに渡す
// この構文により、デプロイ時にAzure Resource ManagerがKey Vaultからシークレットを取得します。
adminPassword: '[reference(\'${keyVaultReference}\', \'2023-07-01\').secretUriWithVersion(\'${adminPasswordSecretName}\')]'
}
}
// 最終的なVM IDを出力
output virtualMachineId string = vmModule.outputs.vmId
// --- 接続用のPublic IPを出力に追加 ---
output publicIpAddress string = publicIpModule.outputs.publicIpAddress
モジュールを追加したのでmain.bicepで呼び出してデプロイするために、publicipのnicとNSGモジュールを呼び出すコードを追記しました。
※デプロイした後に気づきましたが、nicの名前が変わっています。
さて、変更点としては
- パブリックIP、NSGリソースの追加
- NICリソースの修正
- main.bicepでのモジュール呼び出し処理の修正
のみで、VNETやVMをデプロイするコードは特に変更を加えていません。
これを以下のコマンドで実行します。
# パラメータをハッシュテーブルまたはインラインで指定する例
Connect-AzAccount
# Key Vault IDの取得
$existingKeyVaultId = (Get-AzKeyVault -VaultName $keyVaultName).ResourceId
# $HOME\.azure\bin を現在のセッションのPATHに一時的に追加
$env:Path += ";$HOME\.azure\bin"
$vmParameters = @{
vmName = "vm-deploy-bicep"
adminUsername = "adminUser"
existingKeyVaultId = $existingKeyVaultId
adminPasswordSecretName = "vm-admin-password"
location = $location
}
# main.bicep のデプロイ実行
New-AzResourceGroupDeployment -ResourceGroupName rg-vmdeploy-bicep `
-TemplateFile "main.bicep" `
-TemplateParameterObject $vmParameters
main.bicepをデプロイしているので、素直に考えるとVNETのモジュールやVMのモジュールも呼び出されて新規作成する動きをしようとするはずです。
が、結果としてはVMやVNETのリソースは作成されず、コードに変更を加えた箇所のみが実行されています。
<実行前>

<実行後>

※全然本筋と関係ないですが、NICの名前を間違えてデプロイしてしまいvm-deploy-bicepからvm-deploy-bicep-nicになっています。前の名前のリソースは残置され新しいNICリソースができていてややこしかったので前のNICは消しました。
繰り返しになりますが、このコードに変更を加えた箇所のみが変更される性質を「冪等性(べきとうせい)」といいます。
以上。
次はCI/CDパイプラインを検証してみたいです。


コメント