こう感じているなら、ARMテンプレートとBicepを使った自動化に踏み込む価値がある。Azure仮想マシン作成を毎回ポータルで手動操作すると設定の記録が残らず、開発・ステージング・本番と環境が増えるたびに手順書の管理コストが膨らんでいく。
この記事では、ARMテンプレートとBicepを使ってAzure仮想マシン作成を自動化する実践手順を解説する。Ubuntu 24.04 LTS~RHEL 9系を想定環境として説明する。
この記事のポイント
・ ARMテンプレートはJSONでVMリソースを定義し、az deployment group createで繰り返しデプロイできる
・ BicepはARMテンプレートの上位言語で可読性が高く、bicep buildでJSONに変換できる
・ parametersファイルを分けると開発・本番の設定を1コマンドで切り替えられる
・ デプロイ失敗時はaz deployment group show --queryでエラー詳細を素早く確認できる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜARMテンプレートとBicepを使うのか
Azure仮想マシン作成をポータルのGUIで行うことの問題点は、「再現性がない」という一点に尽きる。クリックした内容は記録されず、後から「あのVMとまったく同じ設定でもう1台作りたい」という要求に応えられない。ARMテンプレート(Azure Resource Managerテンプレート)はJSONで記述するインフラ定義ファイルだ。このファイルをazコマンドに渡すと、VNetの作成・パブリックIPの取得・NICのアタッチ・VMの起動まで一括で処理できる。同じファイルを使えば何度でも同じ構成が再現できる。
BicepはARMテンプレートの上位言語として2021年にMicrosoftが正式リリースした。JSON特有の冗長な記法をなくし、型安全性を持つ宣言型言語として設計されている。Bicepで書いたファイルはaz bicep buildでARMテンプレート(JSON)に変換できるため、最終的にデプロイするのはARMテンプレートと変わらない。
どちらを使うべきかという問いには、「新規で書くならBicep、既存JSONを引き継ぐならARMテンプレートを読めればよい」という答えが一般的だ。Azureのドキュメントも現在はBicepのサンプルを主として掲載している。
ARMテンプレートによるAzure仮想マシン作成の基本手順
1. テンプレートの基本構造を理解する
ARMテンプレートは以下の最上位キーから構成される。・ $schema:テンプレートのスキーマURL(固定値)
・ contentVersion:テンプレートのバージョン管理用文字列
・ parameters:実行時に外部から渡す変数の定義
・ variables:テンプレート内で使いまわす計算済みの値
・ resources:作成するAzureリソースの配列(必須)
・ outputs:デプロイ後に取得したい値(VMのIPアドレスなど)
Linux VMを1台起動するには、以下のリソースを resources 配列に定義する必要がある。
・ Microsoft.Network/virtualNetworks(VNet)
・ Microsoft.Network/publicIPAddresses(パブリックIP)
・ Microsoft.Network/networkInterfaces(NIC)
・ Microsoft.Compute/virtualMachines(VM本体)
2. Linux VM用のARMテンプレートを作成する
以下は Ubuntu 24.04 LTS の VM を1台作成する最小構成のARMテンプレートだ。vm-deploy.json として保存する。{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vmName": { "type": "string", "defaultValue": "myLinuxVM" }, "adminUsername": { "type": "string" }, "adminSshPublicKey": { "type": "string" }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]" } }, "variables": { "vnetName": "[concat(parameters('vmName'), '-vnet')]", "subnetName": "default", "nicName": "[concat(parameters('vmName'), '-nic')]", "publicIpName": "[concat(parameters('vmName'), '-pip')]" }, "resources": [ { "type": "Microsoft.Network/virtualNetworks", "apiVersion": "2023-04-01", "name": "[variables('vnetName')]", "location": "[parameters('location')]", "properties": { "addressSpace": { "addressPrefixes": ["10.0.0.0/16"] }, "subnets": [ { "name": "[variables('subnetName')]", "properties": { "addressPrefix": "10.0.0.0/24" } } ] } }, { "type": "Microsoft.Network/publicIPAddresses", "apiVersion": "2023-04-01", "name": "[variables('publicIpName')]", "location": "[parameters('location')]", "sku": { "name": "Standard" }, "properties": { "publicIPAllocationMethod": "Static" } }, { "type": "Microsoft.Network/networkInterfaces", "apiVersion": "2023-04-01", "name": "[variables('nicName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]", "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpName'))]" ], "properties": { "ipConfigurations": [ { "name": "ipconfig1", "properties": { "privateIPAllocationMethod": "Dynamic", "publicIPAddress": { "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIpName'))]" }, "subnet": { "id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', variables('vnetName'), variables('subnetName'))]" } } } ] } }, { "type": "Microsoft.Compute/virtualMachines", "apiVersion": "2023-07-01", "name": "[parameters('vmName')]", "location": "[parameters('location')]", "dependsOn": [ "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" ], "properties": { "hardwareProfile": { "vmSize": "Standard_B2s" }, "osProfile": { "computerName": "[parameters('vmName')]", "adminUsername": "[parameters('adminUsername')]", "linuxConfiguration": { "disablePasswordAuthentication": true, "ssh": { "publicKeys": [ { "path": "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]", "keyData": "[parameters('adminSshPublicKey')]" } ] } } }, "storageProfile": { "imageReference": { "publisher": "Canonical", "offer": "ubuntu-24_04-lts", "sku": "server", "version": "latest" }, "osDisk": { "createOption": "FromImage", "managedDisk": { "storageAccountType": "Premium_LRS" } } }, "networkProfile": { "networkInterfaces": [ { "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" } ] } } } ], "outputs": { "publicIpAddress": { "type": "string", "value": "[reference(variables('publicIpName')).ipAddress]" } } }
3. az deployment group createでデプロイする
テンプレートのデプロイには az deployment group create を使う。事前にリソースグループが必要なので、まず作成しておく。# リソースグループを作成する(未作成の場合) az group create --name myResourceGroup --location japaneast # ARMテンプレートをデプロイする az deployment group create \ --resource-group myResourceGroup \ --template-file vm-deploy.json \ --parameters adminUsername=azureuser \ adminSshPublicKey="$(cat ~/.ssh/id_rsa.pub)"
# 出力例(環境により異なります) { "outputs": { "publicIpAddress": { "type": "String", "value": "20.xxx.xxx.xxx" } }, "provisioningState": "Succeeded" }
ssh azureuser@20.xxx.xxx.xxx
BicepでARMテンプレートを書き直す
先ほどのJSONテンプレートと同じVMをBicepで書き直すと、コードが大幅に短くなる。BicepはJSONの冗長な記法(dependsOn の明示的な配列・resourceId 関数の繰り返し)を排除し、型推論でparameterの記述量も減らせる。1. Bicepのインストールと確認
Azure CLIにBicepが統合されているため、az bicep install で使えるようになる。# Bicepのインストール az bicep install # バージョン確認 az bicep version # 出力例(環境により異なります) Bicep CLI version 0.30.x (xxxxxxxx)
2. Linux VMのBicepファイルを書く
以下は先ほどのARMテンプレートと同等の構成をBicepで記述したものだ。vm-deploy.bicep として保存する。param vmName string = 'myLinuxVM' param adminUsername string @secure() param adminSshPublicKey string param location string = resourceGroup().location var vnetName = '${vmName}-vnet' var subnetName = 'default' var nicName = '${vmName}-nic' var publicIpName = '${vmName}-pip' resource vnet 'Microsoft.Network/virtualNetworks@2023-04-01' = { name: vnetName location: location properties: { addressSpace: { addressPrefixes: ['10.0.0.0/16'] } subnets: [ { name: subnetName properties: { addressPrefix: '10.0.0.0/24' } } ] } } resource publicIp 'Microsoft.Network/publicIPAddresses@2023-04-01' = { name: publicIpName location: location sku: { name: 'Standard' } properties: { publicIPAllocationMethod: 'Static' } } resource nic 'Microsoft.Network/networkInterfaces@2023-04-01' = { name: nicName location: location properties: { ipConfigurations: [ { name: 'ipconfig1' properties: { privateIPAllocationMethod: 'Dynamic' publicIPAddress: { id: publicIp.id } subnet: { id: vnet.properties.subnets[0].id } } } ] } } resource vm 'Microsoft.Compute/virtualMachines@2023-07-01' = { name: vmName location: location properties: { hardwareProfile: { vmSize: 'Standard_B2s' } osProfile: { computerName: vmName adminUsername: adminUsername linuxConfiguration: { disablePasswordAuthentication: true ssh: { publicKeys: [ { path: '/home/${adminUsername}/.ssh/authorized_keys' keyData: adminSshPublicKey } ] } } } storageProfile: { imageReference: { publisher: 'Canonical' offer: 'ubuntu-24_04-lts' sku: 'server' version: 'latest' } osDisk: { createOption: 'FromImage' managedDisk: { storageAccountType: 'Premium_LRS' } } } networkProfile: { networkInterfaces: [ { id: nic.id } ] } } } output publicIpAddress string = publicIp.properties.ipAddress
3. Bicepファイルからデプロイする
Bicepファイルは az deployment group create にそのまま渡せる(内部でARMテンプレートに変換される)。# Bicepファイルを直接デプロイ(az bicep buildは不要) az deployment group create \ --resource-group myResourceGroup \ --template-file vm-deploy.bicep \ --parameters adminUsername=azureuser \ adminSshPublicKey="$(cat ~/.ssh/id_rsa.pub)" # ARMテンプレートJSONに変換したい場合(確認用) az bicep build --file vm-deploy.bicep # → vm-deploy.json が生成される
パラメータファイルで開発・本番の環境を切り替える
ひとつのBicepファイルで開発・ステージング・本番の3環境を管理するには、パラメータファイルを環境ごとに用意するのが基本パターンだ。1. パラメータファイルの構造
パラメータファイルはJSONで記述する(Bicep 0.19以降はbicepparamファイルも使えるが、JSON形式が最も普及している)。# params-dev.json(開発環境用) { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "vmName": { "value": "vm-dev" }, "adminUsername": { "value": "devadmin" }, "adminSshPublicKey": { "value": "ssh-rsa AAAA..." } } }
# params-prod.json(本番環境用) { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "vmName": { "value": "vm-prod" }, "adminUsername": { "value": "prodadmin" }, "adminSshPublicKey": { "value": "ssh-rsa AAAA..." } } }
2. パラメータファイルを指定してデプロイする
--parameters オプションにファイルパスを指定するだけで環境を切り替えられる。# 開発環境にデプロイ az deployment group create \ --resource-group rg-dev \ --template-file vm-deploy.bicep \ --parameters @params-dev.json # 本番環境にデプロイ az deployment group create \ --resource-group rg-prod \ --template-file vm-deploy.bicep \ --parameters @params-prod.json
本番環境のSSH公開鍵など機密性の高い値は Key Vault と連携して参照する設計も検討するとよい。パラメータファイルにシークレットをそのまま書くと、ファイルをgitにコミットした際にシークレットが漏洩するリスクがある。
デプロイ失敗時のトラブルシュート
エラー1: InvalidTemplateDeployment
テンプレートの構文エラーやリソース名の重複が原因で発生することが多い。まずエラーの詳細を確認する。# デプロイ操作の一覧を取得する az deployment group list \ --resource-group myResourceGroup \ --query "[].{name:name, state:properties.provisioningState}" \ --output table # エラー詳細を確認する(デプロイ名は上の出力から取得) az deployment group show \ --resource-group myResourceGroup \ --name <デプロイ名> \ --query "properties.error" # 出力例(環境により異なります) { "code": "InvalidTemplateDeployment", "message": "The template deployment ... failed ...", "details": [ { "code": "QuotaExceeded", "message": "Operation results in exceeding quota limits..." } ] }
エラー2: ResourceNotFound(NICがVNetを参照できない)
ARMテンプレートでリソース間の依存関係が正しく設定されていないと、VNetの作成が完了する前にNICの作成が始まり失敗する。# ARMテンプレートの場合: dependsOnを明示的に設定する "dependsOn": [ "[resourceId('Microsoft.Network/virtualNetworks', variables('vnetName'))]" ] # Bicepの場合: リソースの参照を使えば依存関係は自動解決される # subnet の id を vnet.properties.subnets[0].id のように参照する
エラー3: Bicepのバリデーションエラー
デプロイ前にBicepのテンプレートを検証したい場合は、az deployment group validate を使う。# デプロイ前のバリデーション az deployment group validate \ --resource-group myResourceGroup \ --template-file vm-deploy.bicep \ --parameters @params-dev.json # What-If確認(実際に何が変更されるか事前確認) az deployment group what-if \ --resource-group myResourceGroup \ --template-file vm-deploy.bicep \ --parameters @params-dev.json
本記事のまとめ
Azure仮想マシン作成をARMテンプレートとBicepで自動化するポイントをまとめる。| やりたいこと | コマンド・ファイル |
|---|---|
| ARMテンプレートでVMをデプロイする | az deployment group create --template-file vm-deploy.json |
| Bicepファイルでデプロイする | az deployment group create --template-file vm-deploy.bicep |
| BicepをARMテンプレートJSONに変換する | az bicep build --file vm-deploy.bicep |
| パラメータファイルを指定してデプロイする | az deployment group create --parameters @params-prod.json |
| デプロイ前に変更内容を確認する | az deployment group what-if --template-file vm-deploy.bicep |
| デプロイエラーの詳細を確認する | az deployment group show --query "properties.error" |
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:azureルートテーブルの優先度とカスタムルートの挙動を検証する|VPN環境で実測
- この記事の属するカテゴリ:Azureへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます