mcpField
A
arm-templates

arm-templates

github.com/bagelholeクラウド・DevOps1.2k312 回インストール23 週間前に更新
リポジトリ

arm-templates について

ARM テンプレートと Bicep で Azure インフラをデプロイするガイドです。Azure ネイティブの Infrastructure as Code を使うチーム向けに、モジュール、デプロイ範囲、検証、変更プレビューを扱います。

主な機能

  1. 01Bicep と ARM テンプレートの作成
  2. 02再利用可能な Bicep モジュール
  3. 03複数のデプロイ範囲
  4. 04テンプレートの検証
  5. 05What-If による変更プレビュー

活用シーン

  1. 01コードによる Azure リソースの構築
  2. 02デプロイ前のインフラ変更の確認
  3. 03ARM JSON テンプレートから Bicep への移行
  4. 04リソースグループまたはサブスクリプション範囲へのデプロイ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bagelhole/devops-security-agent-skills --skill arm-templates

インストール後、Claude Code で/arm-templatesを入力して読み込まれたか確認します。

同梱ファイルreferences/arm-syntax.md

詳細

ARM テンプレートと Bicep

ARM テンプレートと Bicep を使用して Azure インフラストラクチャをデプロイします。Bicep は、ARM JSON にコンパイルされる推奨のドメイン固有言語で、より簡潔な構文、モジュール、充実したツールサポートを備えています。

使用する場面

  • サードパーティ製ツールを使わずに、Azure ネイティブの Infrastructure as Code が必要な場合。
  • 組織が Azure を標準としており、ポータルとの緊密な統合を求めている場合。
  • 変更をデプロイする前に What-If 分析が必要な場合。
  • 保守性を高めるため、既存の ARM JSON テンプレートを Bicep に移行する場合。
  • リソースグループ、サブスクリプション、管理グループ、またはテナントレベルのデプロイ スコープが必要な場合。

前提条件

# Install Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# Install Bicep CLI (bundled with Azure CLI 2.20+)
az bicep install
az bicep upgrade

# Verify installation
az bicep version

# Login and set subscription
az login
az account set --subscription "my-subscription-id"

Bicep の基本

仮想ネットワークを含むリソースグループのデプロイ
// main.bicep
@description('Azure region for all resources')
param location string = resourceGroup().location

@description('Environment name used for resource naming')
@allowed(['dev', 'staging', 'prod'])
param environment string = 'dev'

@description('Base name for all resources')
param baseName string

var vnetName = '${baseName}-${environment}-vnet'
var nsgName = '${baseName}-${environment}-nsg'

resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = {
  name: nsgName
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowHTTPS'
        properties: {
          priority: 100
          direction: 'Inbound'
          access: 'Allow'
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '443'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
        }
      }
      {
        name: 'DenyAllInbound'
        properties: {
          priority: 4096
          direction: 'Inbound'
          access: 'Deny'
          protocol: '*'
          sourcePortRange: '*'
          destinationPortRange: '*'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
        }
      }
    ]
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'web-subnet'
        properties: {
          addressPrefix: '10.0.1.0/24'
          networkSecurityGroup: {
            id: nsg.id
          }
        }
      }
      {
        name: 'app-subnet'
        properties: {
          addressPrefix: '10.0.2.0/24'
        }
      }
      {
        name: 'data-subnet'
        properties: {
          addressPrefix: '10.0.3.0/24'
          privateEndpointNetworkPolicies: 'Enabled'
        }
      }
    ]
  }
}

output vnetId string = vnet.id
output webSubnetId string = vnet.properties.subnets[0].id
output appSubnetId string = vnet.properties.subnets[1].id
マネージド ID を使用した VM のデプロイ
// vm.bicep
param location string = resourceGroup().location
param vmName string
param subnetId string
param adminUsername string = 'azureuser'

@secure()
param adminPublicKey string

resource nic 'Microsoft.Network/networkInterfaces@2023-05-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: subnetId
          }
        }
      }
    ]
  }
}

resource vm 'Microsoft.Compute/virtualMachines@2023-07-01' = {
  name: vmName
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    hardwareProfile: {
      vmSize: 'Standard_B2s'
    }
    osProfile: {
      computerName: vmName
      adminUsername: adminUsername
      linuxConfiguration: {
        disablePasswordAuthentication: true
        ssh: {
          publicKeys: [
            {
              path: '/home/${adminUsername}/.ssh/authorized_keys'
              keyData: adminPublicKey
            }
          ]
        }
      }
    }
    storageProfile: {
      imageReference: {
        publisher: 'Canonical'
        offer: '0001-com-ubuntu-server-jammy'
        sku: '22_04-lts-gen2'
        version: 'latest'
      }
      osDisk: {
        createOption: 'FromImage'
        managedDisk: {
          storageAccountType: 'Premium_LRS'
        }
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
    diagnosticsProfile: {
      bootDiagnostics: {
        enabled: true
      }
    }
  }
}

output vmPrincipalId string = vm.identity.principalId
output vmId string = vm.id

Bicep モジュール

モジュールの定義
// modules/storage.bicep
@description('Storage account name (3-24 chars, lowercase alphanumeric)')
param storageAccountName string

param location string = resourceGroup().location
param sku string = 'Standard_LRS'

@allowed(['Hot', 'Cool', 'Archive'])
param accessTier string = 'Hot'

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
  name: storageAccountName
  location: location
  sku: {
    name: sku
  }
  kind: 'StorageV2'
  properties: {
    accessTier: accessTier
    supportsHttpsTrafficOnly: true
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: false
    networkAcls: {
      defaultAction: 'Deny'
      bypass: 'AzureServices'
    }
  }
}

output storageAccountId string = storageAccount.id
output primaryBlobEndpoint string = storageAccount.properties.primaryEndpoints.blob
モジュールの使用
// main.bicep
param location string = resourceGroup().location
param environment string = 'prod'

module storage 'modules/storage.bicep' = {
  name: 'storage-deployment'
  params: {
    storageAccountName: 'myapp${environment}sa'
    location: location
    sku: environment == 'prod' ? 'Standard_GRS' : 'Standard_LRS'
  }
}

module vnet 'modules/network.bicep' = {
  name: 'vnet-deployment'
  params: {
    location: location
    environment: environment
  }
}

// Reference module outputs
output storageBlobEndpoint string = storage.outputs.primaryBlobEndpoint

ARM JSON テンプレートの構造

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "storageAccountName": {
      "type": "string",
      "metadata": {
        "description": "Name of the storage account"
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]"
    }
  },
  "variables": {
    "storageSku": "Standard_LRS"
  },
  "resources": [
    {
      "type": "Microsoft.Storage/storageAccounts",
      "apiVersion": "2023-01-01",
      "name": "[parameters('storageAccountName')]",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[variables('storageSku')]"
      },
      "kind": "StorageV2",
      "properties": {
        "supportsHttpsTrafficOnly": true,
        "minimumTlsVersion": "TLS1_2"
      }
    }
  ],
  "outputs": {
    "storageId": {
      "type": "string",
      "value": "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]"
    }
  }
}

デプロイ コマンド

# Validate a Bicep template before deployment
az deployment group validate \
  --resource-group mygroup \
  --template-file main.bicep \
  --parameters environment='prod' baseName='myapp'

# Preview changes with What-If
az deployment group what-if \
  --resource-group mygroup \
  --template-file main.bicep \
  --parameters environment='prod' baseName='myapp'

# Deploy Bicep to resource group
az deployment group create \
  --resource-group mygroup \
  --template-file main.bicep \
  --parameters environment='prod' baseName='myapp' \
  --name "deploy-$(date +%Y%m%d-%H%M%S)"

# Deploy ARM JSON with parameter file
az deployment group create \
  --resource-group mygroup \
  --template-file template.json \
  --parameters @parameters.prod.json

# Subscription-level deployment (e.g., resource groups, policies)
az deployment sub create \
  --location eastus \
  --template-file subscription-level.bicep \
  --parameters @params.json

# Management group deployment
az deployment mg create \
  --management-group-id my-mg \
  --location eastus \
  --template-file mg-policy.bicep

# Export resource group to ARM JSON
az group export --name mygroup --output json > exported-template.json

# Decompile ARM JSON to Bicep
az bicep decompile --file exported-template.json

# Build Bicep to ARM JSON (for inspection)
az bicep build --file main.bicep --outfile main.json

# List deployments and their status
az deployment group list \
  --resource-group mygroup \
  --output table

# Delete a failed deployment
az deployment group delete \
  --resource-group mygroup \
  --name my-failed-deployment

パラメータ ファイル

// parameters.prod.json
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "environment": { "value": "prod" },
    "baseName": { "value": "myapp" },
    "adminPublicKey": {
      "reference": {
        "keyVault": {
          "id": "/subscriptions/{sub-id}/resourceGroups/{rg}/providers/Microsoft.KeyVault/vaults/{vault}"
        },
        "secretName": "ssh-public-key"
      }
    }
  }
}

リンク済みテンプレートと入れ子になったテンプレート

// Deploy to a different resource group
module networkInSharedRg 'modules/network.bicep' = {
  name: 'shared-network'
  scope: resourceGroup('shared-networking-rg')
  params: {
    location: location
  }
}

// Conditional deployment
param deployMonitoring bool = true

module monitoring 'modules/monitoring.bicep' = if (deployMonitoring) {
  name: 'monitoring-deployment'
  params: {
    location: location
  }
}

// Loop deployment
param storageAccounts array = [
  { name: 'logs', sku: 'Standard_LRS' }
  { name: 'data', sku: 'Standard_GRS' }
]

module storageLoop 'modules/storage.bicep' = [for account in storageAccounts: {
  name: 'storage-${account.name}'
  params: {
    storageAccountName: '${baseName}${account.name}sa'
    sku: account.sku
    location: location
  }
}]

トラブルシューティング

症状原因対処方法
InvalidTemplate エラーARM JSON または Bicep の構文エラーaz bicep build を実行して、コンパイルエラーを確認します
デプロイ中の ResourceNotFoundリソースの依存関係が宣言されていないdependsOn を追加するか、Bicep の暗黙的な参照を使用します
クォータエラーを伴う DeploymentFailedサブスクリプションのクォータ超過クォータの引き上げを申請するか、別のリージョンを使用します
AuthorizationFailedRBAC 権限が不足している対象のリソースグループに共同作成者ロールを割り当てます
パラメータ ファイル内のシークレットがソース管理に含まれているシークレットがプレーンテキストで保存されているパラメータ ファイルで Key Vault 参照を使用します
デプロイに非常に時間がかかる多数のリソースが直列にデプロイされている並列デプロイができるように、dependsOn を慎重に使用します
What-If で予期しない削除が表示されるIncremental ではなく Complete モードになっている管理対象外のリソースが削除されないよう、--mode Incremental(既定値)を使用します
Bicep モジュールが見つからない相対パスが正しくないパスがモジュールを使用するファイルからの相対パスになっていることを確認します

関連スキル

  • terraform-azure -- より幅広いプロバイダーをサポートする、マルチクラウド対応の IaC 代替手段です。
  • azure-networking -- テンプレートで参照される VNet、NSG、ファイアウォールの構成です。
  • azure-vms -- 仮想マシンのサイズと構成の詳細です。
  • azure-aks -- Bicep/ARM 用の Kubernetes クラスター定義です。

コメント