大量の Azure VM を展開してみる


Azure がついに 7 周年らしいですね。おめでとうございます。(私は 20 歳で触り始めたので、気づけば 6 年以上使っていることに…。)

さて、昨日同僚から、「明日のトレーニングで使う VM を 40 台作りたい」と相談を受けて、片手間でデプロイしたので、落書き程度にメモを残しておきます。

1. 展開方法

詳しく話を聞くと、RDS 環境のトレーニング用に VM 5 台 (CB, SH1, SH2, Web, Client) x8 セットが明日までに欲しいとのこと。

パッと思いつく方法としては、以下の 4 通りくらいでしょうか。

  • ポータルからポチポチする (論外)
  • Azure PowerShell で単純にループさせてシリアルでデプロイする (遅い)
  • Azure PowerShell でパラレルでデプロイする (面倒)
  • JSON テンプレートを使う

どの方法でも作れますが、今日はデプロイに時間をかけられないので JSON にしました。(夕方相談を受けて、明日使うということだったので。)

なお、余談ですが PowerShell で複数リソースをパラレル展開する方法は以下にメモってあります。ただ、これも作成するリソース数が増えると、エラーを吐きやすくなってデバッグが面倒なので、今回は候補から除外。

2. JSON テンプレートの作り方

使い慣れていない人に PowerShell とか JSON テンプレートって言うとあからさまに嫌な顔されるんですが、一回作って慣れてしまえば大したことはないです。

JSON が初めての人は、横着せずに以下全部きっちり目を通しましょう。これだけ知っていれば十分なので。

で、具体的にどう作るかというと、既存のテンプレートをパクってきて切り貼りします。

 

今回は VM を大量に複製したいので、名前に loop と入った以下をベースにします。

このまま [Deploy to Azure] ボタンでサクっとデプロイできるのですが、40 と入れると 5 台までしか作れないとエラーになります。生の JSON を開いてみると、以下の通り numberOfInstances のパラメーターが maxValue 5 となっているので、40 などに書き換えてしまいましょう。

なお、運用環境の場合は 1 つのストレージ (20000 IOPS 上限) に大量の VHD (500 IOPS 上限) を配置するとパフォーマンスに影響があるので、適切にストレージを分割する必要があります。あと、Premium ストレージについては 35 TB の容量制限もあるので気を付けましょう。

    "numberOfInstances": {
      "type": "int",
      "defaultValue": 2,
      "minValue": 2,
      "maxValue": 5,
      "metadata": {
        "description": "Number of VMs to deploy, limit 5 since this sample is using a single storage account"
      }
    },

 

次に Visualize ボタンを押して含まれるリソースを確認すると以下が入っていることがわかります。リソース名に copyindex() とついている VM と NIC は、1 つしか定義されていませんが、ループさせて必要数だけ作成されるようになっています。

生の JSON をさらに深堀してみると、例えば NIC は以下のように定義されています。name は nic0, nic1, nic2… などとなるように、copyindex() でループのカウンタ (0, 1, 2…) をセットして、concat で文字列を結合しています。また、copy セクションで count として設定されている数だけループするように定義してあります。(ここでは、あとで任意の値が設定できるよう、numberOfInstances というパラメーターが入っています。)

    {
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat('nic', copyindex())]",
      "apiVersion": "2016-03-30",
      "location": "[resourceGroup().location]",
      "copy": {
        "name": "nicLoop",
        "count": "[parameters('numberOfInstances')]"
      },
      "dependsOn": [
        "[variables('virtualNetworkName')]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnet1Ref')]"
              }
            }
          }
        ]
      }
    },

 

同じく VM についても 1 台分しか定義されていませんが、ループさせて numberOfInstances 台だけ展開されるようになっています。その他、コンピューター名やVHD のパス、NIC の ID なども copyIndex() を使って定義されていることに気を付けましょう。

    {
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat('myvm', copyIndex())]",
      "apiVersion": "2016-03-30",
      "location": "[resourceGroup().location]",
      "copy": {
        "name": "virtualMachineLoop",
        "count": "[parameters('numberOfInstances')]"
      },
      "dependsOn": [
        "nicLoop",
        "[variables('storageAccountName')]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "Standard_D1_v2"
        },
        "osProfile": {
          "computerName": "[concat('vm', copyIndex())]",
          "adminUsername": "[parameters('adminUsername')]",
          "adminPassword": "[parameters('adminPassword')]"
        },
        "storageProfile": {
          "imageReference": "[variables('imageReference')]",
          "osDisk": {
            "name": "osdisk",
            "vhd": {
              "uri": "[concat(reference(variables('StorageAccountName'), '2016-01-01').primaryEndpoints.blob, 'vhds/osdisk', copyIndex(), '.vhd')]"
            },
            "caching": "ReadWrite",
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',concat('nic', copyindex()))]"
            }
          ]
        }
      }
    }

各パラメーターを一通り見てみると、実は Public IP が付与されていないことが判明します。このままでは直接 RDP できないので、他の Public IP 付きの VM を展開するテンプレートから Public IP の定義と、NIC の依存関係の部分をパクってきます。

なお、この際にリソース名等に使われている変数 (variables) が定義されていなかったりするので、concat(‘pip’, copyIndex()) などへ変更し、Public IP と NIC を紐づけるなど、ベースのテンプレートと整合性が取れるように微修正します。

    {
      "apiVersion": "2016-03-30",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[variables('publicIPAddressName')]",
      "location": "[resourceGroup().location]",
      "properties": {
        "publicIPAllocationMethod": "Dynamic",
        "dnsSettings": {
          "domainNameLabel": "[parameters('dnsLabelPrefix')]"
        }
      }
    },
    {
      "apiVersion": "2016-03-30",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[variables('nicName')]",
      "location": "[resourceGroup().location]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
        "[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig1",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
              },
              "subnet": {
                "id": "[variables('subnetRef')]"
              }
            }
          }
        ]
      }
    },

とまあ、こんな具合でそれっぽいテンプレートが出来上がったら、ポータルの [新規] – [テンプレートのデプロイ] に張り付けて、デプロイしてみましょう。(コンピューター名を役割ごとに別で定義したかったので、以下では VM やら NIC、Public IP を 5 台分コピーして定義しています)

 

大体どっかしら間違っていて、展開前の検証フェーズで失敗すると思います。エラーに表示された内容やキーワードを頼りに、カッコがそろっているか、パラメーターが前後と整合性がとれているかなどを確認しましょう。あとは修正とデプロイを繰り返して、期待したものが出来上がるまで微調整すれば終わりです。

 

3. 余談

大量の VM を展開する際は、サブスクリプションのクォータに気を付けましょう。足りない場合は引き上げ申請をすればいいんですが、数日~1 週間程度かかるので、急ぎの場合はリージョンを変えればいいと思います。(ARM はリージョン毎にクォーター設定されているので。)

ちなみに、クォーターはプレビュー ポータル (https://preview.portal.azure.com) のサブスクリプション ブレードから細かく見れるようになっています。(そのうち一般のポータルにも来るはず?)

 

あと、JSON の編集は Visual Studio もしくは Visual Studio Code を使うとかなり便利です。

 

そんなこんなで、実質 2 時間くらいで無事デプロイが終わりました。クラウドの時代なので、このくらい片手間でサクっと出来ると便利ですね。業務効率化は正義!


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です