Skip to content

MS_ARMTemplate

nishi_74322014 edited this page Sep 1, 2026 · 1 revision

Azure Resource Manager テンプレート

概要

  • ARM テンプレートとも。

  • Azure では、主に ARM テンプレートを利用して、
    インフラ〜OS レイヤまでのインフラ構築の「自動化(IaC)」を行う

補足(最新化 / Bicep): 現在、ARM テンプレート(JSON)を
直接書くことは推奨されていない。
Bicep という DSL が用意されており、
これをコンパイルすると ARM テンプレートになる。

Bicep(.bicep)──ビルド──▶ ARM テンプレート(.json)──▶ ARM API
  人が書く                    機械が読む

Bicep の利点は、

  • 記述量が半分以下になる([parameters('x')] のような文字列式が不要)、
  • 依存関係が自動推論される(後述の dependsOn の苦労が大幅に減る)、
  • 型チェックと補完が効く、

という点。本ページが述べている苦労の多くは Bicep で解消される。
ただし、ARM テンプレートの構造(parameters / variables / resources /
outputs、resourceId の考え方)はそのまま Bicep にも通じる
ため、
以下の内容は現在も理解する価値がある。

詳細

機能

入力

Resource Manager はテンプレートを解析し、
その構文を適切なリソース・プロバイダの REST API 操作に変換する。

出力

既存のリソース・グループのテンプレートの取得

  • リソース・グループの現在の状態をエクスポート
  • 特定のデプロイに使用されたテンプレートを表示

構造

ARM テンプレートとパラメタ・ファイルから構成される

ARM テンプレート

作成するリソース群を指定する(template.json)。

ARM パラメタ・ファイル

  • 可変要素をパラメタ化する(parameters.json)。
  • テンプレート実行時に外部から値を与える。

編集と実行

編集

Visual Studio Code に ARM Tools プラグインを入れ編集。

実行

Azure ポータルから保存・実行すると便利。

※ ローカルで実行するには、PowerShell ライブラリのインストールなど環境構築が必要になる。

補足(最新化): 現在は Azure CLI で完結する。

# 事前確認(差分を見る)
az deployment group what-if -g <RG名> --template-file main.bicep

# 適用
az deployment group create -g <RG名> --template-file main.bicep --parameters @params.json

特に what-if(What-If 操作) は、
「このテンプレートを適用すると何が変わるか」を事前に表示する機能で、
本ページ後半の「配置が成功するまで trial and error」の苦労を
大幅に軽減する。

作り方

Automation

  • スクラッチで記載するのは難しいので、
    Automation オプション、Automation スクリプトを使用する。

  • リソースの作成前 or 作成後でやり方が変わってくる。

    • リソース作成時にテンプレートを引き抜く。
      ポータルからのリソース作成時に、Automation オプションを確認

    • リソース作成後にテンプレートを引き抜く。
      リソース・グループまたはリソースから、Automation スクリプトを出力

  • 以下のトレード・オフがあるので、
    2つの方法を併用して作成する。

Automation オプション<br>リソース作成時にテンプレートを引き抜く。 Automation スクリプト<br>リソース作成後にテンプレートを引き抜く。
GOOD 綺麗な JSON が入手できる 合体(依存関係アリ、構成変更後)の JSON を入手できる。
BAD ・一部の新しいリソースでサポートされていない。<br>・全てがパラメタライズされた状態の JSON。<br>・単体(依存関係ナシ、構成変更前)の JSON しか入手できない。 ・リソースによっては、JSON 化出来ないモノがある。<br>・半端にパラメタライズされた状態の JSON。<br>・余分な値や、重複した出力がされることがある。

補足(この 2 つの使い分けが本ページの核): ポータルで作った構成から
テンプレートを「引き抜く」という手法は、
ゼロから JSON を書くのが非現実的であるという現実に即した実践知である。

【Automation オプション】= 作成前のプレビュー
   ポータルの [確認と作成] の直前で見られる
   → 綺麗だが、そのリソース単体のみ

【Automation スクリプト】= 作成後のエクスポート
   リソース グループの [テンプレートのエクスポート]
   → 全体が取れるが、余計な値まで付いてくる

「綺麗な単体」と「汚い全体」を突き合わせて手で組む、
というのが本ページの手法である。

サンプル・シナリオ

ハブネットワークの ARM テンプレート作成

※ 以下、サンプル・シナリオの手順

手順

リソース作成時のテンプレート引き抜き機能を使用する。

  • ポータル上で仮想ネットワーク、Azure Firewall(+パブリック IP)を構成する。

  • 作成前に、Automation オプションを選択し、
    ARM テンプレートとパラメタ・ファイルを引き抜く。

  • テンプレートに、基本的な修正を施す。

  • テンプレートの修正後、実際にリソースを作成する。

サブネットの作成

既存リソースから、リソース作成後のテンプレート引き抜き機能を使用する。
(作成時は引き抜き不可であるため)

  • 先ず、ポータル上でサブネットを3つ構成する(仮想ネットワークのサブ・リソース)。

    • 管理 VM 用
    • DNS 等配置用
    • Gateway 用
  • 作成後に、Automation スクリプトを選択すると、
    当該リソースが含まれるリソース・グループ全体を
    ARM テンプレートとパラメタ・ファイルに引き抜く。

  • Automation スクリプトの特徴。

    • リソース・グループ全体が引き抜かれる。
    • 既定値や、現在の状態など、余分なパラメタ値が引き抜かれる。
    • サブ・リソースが独立したリソースとして展開される。
      • このため、全体的に冗長になる。
      • また、依存関係が展開先に変更される。
  • Automation スクリプトをテンプレートにマージする。

    • コチラのテンプレートをベースに、Automation スクリプトを参考にして、
      展開されたリソース(サブネット)は、(仮想ネットワークの)サブ・リソース的にマージする。

      • ココでは、サービス・エンドポイントの定義が追加されているのでコレもマージする。
      • 既定値や、現在の状態など、GUI から設定していない余分な値は、移行しないようにする。
    • 最後に、テンプレートに、基本的な修正を施す。

  • テンプレートの修正後、実際にリソースを作成する。

補足(サブ・リソースの 2 通りの書き方): サブネットのような
「親に属するリソース」は、ARM では 2 通りに書ける。

// ① 親の中に入れ子で書く(本ページが推奨する形)
{ "type": "Microsoft.Network/virtualNetworks",
  "properties": { "subnets": [ { "name": "mgmt", ... } ] } }

// ② 独立したリソースとして書く(エクスポートされる形)
{ "type": "Microsoft.Network/virtualNetworks/subnets",
  "name": "vnet/mgmt", ... }

①と②を混在させると、デプロイのたびにサブネットが消えるという
事故が起きる(① 側の定義が ② を上書きするため)。
原文が「サブ・リソース的にマージする」と一貫して述べているのは、
この事故を避けるための判断である。

ルート・テーブル(UDR)の作成

同様に、既存リソースから、リソース作成後のテンプレート引き抜き機能を使用する。
(リソース依存関係の指定がポイント)

  • ポータル上でルート・テーブル(UDR)を構成する。

  • Automation オプションを確認する(依存関係ナシ、構成変更前)。

  • 上記のルート・テーブルをポータル上で実際に作成し、

  • Automation スクリプトを生成する(依存関係アリ、構成変更後)。

  • Automation スクリプトを確認する。

    • ルート・テーブルとルートが生成され、関連付けは、サブネット側に入る。
    • ルート・テーブルのサブ・リソースのルートが展開され、重複して出力される。

    ※ 前段階の Automation スクリプトと Diff を取るなどすると良さそうではある。

  • Automation スクリプトをテンプレートにマージする。

    • ベースのテンプレートに新規リソースとサブ・リソースの定義だけをマージする。

      • ルート・テーブルとルートの作成の定義
      • サブネットに追加されたルート・テーブル割当の定義
    • 依存関係を分析して、依存関係を設定し直す。
      依存関係設定は、親同士の依存関係に置き換えると良い。

      • 「サブネット → ルート・テーブル」の依存関係を、
      • 「仮想ネットワーク → ルート・テーブル」の依存関係に修正。
    • 最後に、テンプレートに、基本的な修正を施す。

  • テンプレートの修正後、実際にリソースを作成する。

VPN Gateway の作成

再び、リソース作成時のテンプレート引き抜き機能を使用する。
(テンプレートに含めるリソースの範囲がポイント)

  • ポータル上で Gateway 用サブネットに、
    VPN Gateway(+パブリック IP)を構成する。
    (対向ネットワークが無いと設定できない所は構成しない等)

  • 作成前に、Automation オプションを選択し、
    ARM テンプレートとパラメタ・ファイルを引き抜く。

  • Automation オプションをテンプレートにマージする。

    • リソース作成後のテンプレート引き抜き機能を使用した後に、
      リソース作成時のテンプレート引き抜き機能を使用する場合、
      (既にあるリソースが前提になっているので)
      以下の様に依存関係の修正が必要になることがある。

      • 定義にリソースを識別する固定値の ID が使用されている場合、
        resourceId 関数を使用した動的解決が必要になることがある。
      • また、依存関係設定は、親同士の依存関係に置き換えると良い。
    • 最後に、テンプレートに、基本的な修正を施す。

  • テンプレートの修正後、実際にリソースを作成する。

Azure Firewall の設定

既存リソースからのテンプレート引き抜き機能に対応していない場合の扱い方
現時点では、上記の引き抜き機能が実装された。
(されていない場合は、リファレンス頼りになる)

  • ポータル上で Azure Firewall に以下を構成する。

  • 上記をポータル上で実際に適用し、

  • Automation スクリプトを生成・確認する。

  • Automation スクリプトをテンプレートにマージする。

    • Azure Firewall の、properties の、
      xxxxxRuleCollections をテンプレートにマージする。
    • 最後に、テンプレートに、基本的な修正を施す。
  • テンプレートの修正後、実際にリソースを作成する。

診断ログ・ストレージの作成

再び、リソース作成時のテンプレート引き抜き機能を使用する。
(グローバル一意リソースが存在するケース)

  • ポータル上でストレージ・アカウントを構成する。

  • 作成前に、Automation オプションを選択し、
    ARM テンプレートとパラメタ・ファイルを引き抜く。

  • Automation オプションをテンプレートにマージする。

    • ストレージ・アカウントのセクションをテンプレートにマージする。

      • virtualNetworkRules のサブネットの固定値の ID を resourceId で動的解決する。
      • コチラの段階で、サブネットにサービスエンド・ポイントが指定されている。
      • そして、(サブネットではなく)仮想ネットワークへの依存関係を追加する。
    • 最後に、テンプレートに、基本的な修正を施す。

  • テンプレートの修正後、実際にリソースを作成する。
    (この際、グローバル一意リソース用の変数入力が求められる)

補足(グローバル一意リソース): ストレージ アカウント名は
全世界で一意である必要がある(<名前>.blob.core.windows.net という
FQDN になるため)。
したがって、テンプレートに固定名を書くと他人と衝突して失敗する。
後述の parameters / variables で
「共通のプレフィックス + 環境ごとの識別子」を組み立てるのが定石。

現在は uniqueString(resourceGroup().id) 関数を使い、
リソース グループごとに決定的な一意文字列を生成する方法が一般的。

仮想マシンの作成1

管理 VM 用サブネットに管理用の仮想マシンを作成するが、
仮想マシンでは、

  • リソース作成時のテンプレート引き抜き機能と
  • リソース作成後のテンプレート引き抜き機能とを

併用する(そして、評価式の修正のコツがポイント)。

  • ポータル上で仮想マシンを構成する。

  • 作成前に、Automation オプションを選択し、
    ARM テンプレートとパラメタ・ファイルを引き抜く。

    • 仮想マシンは、多数のリソースから構成されることが解る。

    • また、各リソース間に依存関係もある。

      • NIC → (NSG、パブリック IP)
      • NSG → (-)
      • パブリック IP → (-)
      • 仮想マシン → (NIC)
  • Automation オプションをテンプレートにマージする。

    • パスワードは、グローバル一意リソース同様、
      parameters セクションに変数を追加する(が、型は secureString にする)

    • parameters セクションに変数の加工が必要な場合、variables セクションが使用されている。

      variables を使用しないように展開すると、この中に動的解決すべきパラメタを確認できるので、
      この値を resourceId で動的解決する(NIC が利用するサブネットや NSG の ID が該当する)。

    • 最後に、テンプレートに、基本的な修正を施す。

  • 上記の仮想マシンをポータル上で実際に作成し、

  • Automation スクリプトを生成・確認する。
    すると、追加で以下の依存関係が確認できる。

  • Automation スクリプトをテンプレートにマージする。

    • 上記の依存関係を追加するが、同様に、
      親同士の依存関係に置き換えると良い(サブネット → 仮想ネットワーク)。

    • 最後に、テンプレートに、基本的な修正を施す。

  • テンプレートの修正後、実際にリソースを作成する。
    (この際、グローバル一意リソース用の変数入力が求められる)

補足(secureString の重要性): パスワードを string 型で受けると、
デプロイ履歴にパラメータの値が平文で残る(ポータルから見える)。
secureString にすると値がログに残らない。

より安全なのは、Key Vault から参照する方式である。

"adminPassword": {
  "reference": {
    "keyVault": { "id": "/subscriptions/.../vaults/myVault" },
    "secretName": "vmAdminPassword"
  }
}

こうすると、パラメータ ファイルに秘密そのものを書かずに済む。

仮想マシンの作成2

DNS 等配置用サブネットに DNS サーバ用の仮想マシンを作成するので、
冗長化のタメに可用性セットに2台の仮想マシンを配置するが、
この場合、1台作成してコピペで増やすという方法が採れる。

  • 先ず、ポータル上で可用性セットを作成する。

  • 作成前に、Automation オプションを選択し、
    ARM テンプレートとパラメタ・ファイルを引き抜く。

  • Automation オプションをテンプレートにマージする。

  • 上記の可用性セットをポータル上で実際に作成し、

  • 更に、ポータル上で当該可用性セット上に仮想マシンを構成する。

  • 作成前に、Automation オプションを選択し、
    ARM テンプレートとパラメタ・ファイルを引き抜く。

  • Automation オプションをテンプレートにマージする。

  • 上記の仮想マシンをポータル上で実際に作成し、

  • Automation スクリプトを生成・確認する。
    すると、追加で以下の依存関係が確認できる。

  • Automation スクリプトをテンプレートにマージする。

  • 最後に、仮想マシンをコピペで増やし、リネームし、衝突が無いことを確認する。
    (アンチ・マルウェアなどを構成すると、VM 名が含まれないリソースが含まれるケースもあるらしい)。

  • テンプレートの修正後、実際にリソースを作成する。
    (この際、グローバル一意リソース用の変数入力が求められる)

  • 更に、静的 IP を構成して、追加のフィードバックを行う。

    • Automation スクリプトを生成・確認する。
    • スクリプトをテンプレートに Diff &マージ。
    • 静的 IP は NIC のコンフィギュレーションらしい。

補足(「コピペで増やす」の代替): 原文の手法は素朴だが確実である。
現在は **copy 要素(Bicep では for ループ)**で
同じ定義を N 個展開できる。

resource vm 'Microsoft.Compute/virtualMachines@2023-03-01' = [for i in range(0, 2): {
  name: 'dns-vm-${i}'
  ...
}]

コピペだと片方だけ直して不整合になる事故が起きやすいため、
台数が増えるならループにする方がよい。
ただし原文が指摘する「VM 名が含まれないリソース」の衝突は
ループでも起きるため、確認は必要。

ポイントのまとめ

Automation を使用してテンプレートを作成する際のポイントのまとめ。

基本的な修正

何れの場合も、以下の、基本的な修正を施す。

  • テンプレート内のパラメタ値の具体値化を行う。

    • template.json の resources セクションの "[parameters('XXXX')]" を、
      parameters.json の parameters セクションの具体値に変える。
    • 具体値に変えた、template.json の parameters セクションのパラメタを削除する。
  • 既定で GUI からの入力を使用するパラメタの動的値化を行う。

    • リソース・グループ名(name)、リソースを作成する場所(location)

    • "[parameters('XXXX')]" だった所を "[resourceGroup().XXXX]" に変更する。
      (これでテンプレートを実行する際に与えられるパラメタを使用するらしい)

  • 冗長な concat 関数は文字列にしてしまう。

補足(この「具体値化」の意図): 一見すると IaC の原則に反する
(パラメータ化を戻している)ように見えるが、これは合理的である。

ポータルからエクスポートすると、変える必要のない値まで
すべてパラメータ化される
。
その結果、parameters が数十個並び、
本当に変えたい値がどれか分からなくなる。

【エクスポート直後】parameters が 40 個 → 何を渡せばいいのか不明
【整理後】         parameters が 3 個  → 環境ごとに変わるのはこれだけ

**「環境ごとに変わるものだけをパラメータにする」**という原則に
戻す作業、と理解するとよい。

ユーザ入力を反映する場合

グローバル一意リソースが存在する場合などのケースで利用する。

  • parameters セクションを使用すると、
    実行時にユーザ入力を反映できる。

    • parameters セクションに変数を追加する。
"parameters": {
  "virtualDataCenterId": {
    "type": "string",
    "defaultValue": ""
  }
},
  • グローバル一意リソース名などに(文字列連結で)反映する。
"name": "[concat('xxxxxx', parameters('virtualDataCenterId'))]",
  • variables セクションを使用すると、
    parameters セクションの変数を加工できる。

    • variables セクションに変数を追加し parameters を加工する。
"variables": {
  "diagnosticsStorageAccountName": "[concat('azrefarchubrgdiag', parameters('virtualDataCenterId'))]"
},
  • グローバル一意リソース名などに variables を使用する。
"name": "[variables('diagnosticsStorageAccountName')]",

テンプレートの新規作成

仮想ネットワーク作成時、
リソース作成時のテンプレート引き抜き機能を使用して、
テンプレートを新規作成。

テンプレートへのマージ

※ 仮想マシン等では、上記2つの方法を併用する。

依存関係の分析と設定

  • 依存関係設定

    • 基本的に、サブ・リソースは使用せず、
      親同士の依存関係に置き換えると良い。

    • 再び、Automation オプションを使用する場合、
      (既にあるリソースが前提になっているので)依存関係の修正が必要になることがある。

      • 定義にリソースを識別する固定値の ID が使用されている場合、
        resourceId 関数を使用した動的解決が必要になることがある。
      • また、依存関係設定は、親同士の依存関係に置き換えると良い。
  • dependsOn の ID の書き方
    文字列と関数の2種類あり、文字列を使用する方法では、
    簡便な記述ができるようになっているが、指定が曖昧になり易い。

    • 文字列:"Microsoft.Network/virtualNetworks/azrefarc-hub-vnet/subnets/mgmt"
    • 関数:"[resourceId(resourceGroup().name, 'Microsoft.Network/virtualNetworks/subnets', 'azrefarc-hub-vnet', 'mgmt')]"

補足(Bicep なら不要になる作業): この節が扱っている
dependsOn の手作業と resourceId の組み立ては、
ARM テンプレート(JSON)を書くうえで最も骨の折れる部分である。

Bicep では、他のリソースのプロパティを参照した時点で
依存関係が自動的に推論される
ため、原則 dependsOn を書かない。

resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = { ... }

resource nic 'Microsoft.Network/networkInterfaces@2023-05-01' = {
  properties: {
    ipConfigurations: [{
      properties: {
        // vnet を参照 → 自動的に vnet への依存が設定される
        subnet: { id: vnet.properties.subnets[0].id }
      }
    }]
  }
}

本ページの「親同士の依存関係に置き換える」という工夫も、
Bicep では意識せずに正しい形になる。

配置が成功するまで、trial and error。

補足(VPN Gateway が遅い理由): VPN Gateway の作成には
30〜45 分かかる(バックエンドで専用の VM が構成されるため)。
試行錯誤の最後に回す、という原文の判断は極めて実践的である。
同様に時間のかかるものとして、Azure Firewall、
Application Gateway、AKS がある。

現在は what-if で構文・参照の誤りを事前に潰せるため、
「作ってみて失敗する」回数自体を減らせる。

テンプレート化は構成が確定してから。

  • そもそもクラウドのインフラ構築は、
    「trial and error」な所があるため、
    序盤に着手すると手戻りが大きくなる可能性がある。

  • 故に、構築の序盤にはポータルを使用し、
    熟れてから、テンプレート化を開始するようにする。

補足(この結論が本ページの白眉): 「IaC は最初からやるべき」という
一般論に対し、**「構成が確定してから」**という現実的な指針を
示している点が本ページの価値である。

IaC (Infrastructure as Code) が述べる
「適切なターゲットに有効」「スケール・メリットが必要」という留保と
同じ趣旨であり、

  • 構成を探索する段階はポータル(速い、試しやすい)
  • 構成が固まった段階でテンプレート化(再現性、監査性)

という段階分けが実務に即している。
なお、この判断は同じ環境を何面も作る予定があるかで変わる。
最初から複数環境が確定しているなら、早めにコード化した方がよい。

参考

Microsoft Azure

Microsoft Learn

Qiita

nakama

FgCF > ゼロトラスト型マルチクラウド IT 環境 > Azure による仮想データセンタ構築手法
> 共通技術 > ネットワーク基盤の構成方法 > ARM テンプレートの利用方法

※ 体系・pwd は FgCF (Financial-grade Cloud Fundamentals) を参照。

SIOS Tech. Lab


Tags: 移行, インフラストラクチャ, クラウド, セキュリティ, Azure, IaC

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONE / TODO

Clone this wiki locally