Azure Resource Manager で作成した仮想マシンをキャプチャーする

Azure のリソース管理手法が充実してきて、すごくワクワクしております。

この投稿では、Azure リソースマネージャー(ARM)配下に仮想マシンを作成して、マスターイメージとしてキャプチャーする手順について解説します。

実際の操作方法は動画でも紹介していますので、以下をご覧ください。なお、この動画は Part 7 なのですが、全手順はこちらで参照可能です。

Azure 上にリソースを作成する場合、2つの方法が用意されています。

  • 従来通りの方法(クラシック)
  • リソースマネージャー(ARM)を使用する方法

image

ARM を有用性については別途きちんと解説したいと思いますが、1 つ利点を挙げるとすればリソース管理の容易さと視認性向上です。

SIer の SE であれば、お客様先に展開するサーバーの構成なんてのは大体決まっているもんで、通常はそれを展開するために手順書なんてものを作ったりします。まぁそれでも間違えたりなんだりで手戻りが発生するわけです。じゃ、スクリプトで自動化するか?なんて意見が出たとしても、意外にスクリプトって理解している人が少ないという。スクリプトは視認性が悪いって面もありますし、個人のクセが色濃くでてしまうので引継ぎしづらいって面もあります。

ARM を使用すると、Azure 内のリソースの属性や、リソース間の関係性を明確に宣言することができます。ARM で作成した仮想マシンや、仮想ネットワーク、仮想ディスク等をテンプレートとして保存しておくと、同じ環境がいつでも簡単に作成できるわけです。PowerShell に DSC(Desired State Configuration)という機能がありますが、DSCがサーバー内のリソース構成を宣言したテンプレートであるのに対し、ARM は Azure 内のリソース構成を宣言したものです。宣言という言い方はわかりずらいですかね。「定義」とでも読み替えてください。

ただ、現時点では難点(というか未実装な部分)がいくつかあります。例えば、仮想ネットワークにゲートウェイを作ることができないとか、仮想マシンをキャプチャしてイメージを作成できないとか。これらはPowerShell を使うと可能ではありますが、残念ながら Azure ポータルからは行えません。

で、本題ですが。

ちょっと ARM 配下の VM をキャプチャしなければならない状況になりまして、せっかくなのでここで手順を簡単にご紹介しておきたいと思います。まだ Preview の機能ですので、今後変更される可能性があることをご承知おきください。

  1. VMをリソースマネージャー配下に作成する
  2. 日本語化等、必要な作業を行う
  3. Sysprep して一般化しシャットダウンする
  4. キャプチャする

1. VM をリソースマネージャー配下に作成する

仮想マシンをリソースマネージャーに作成するには、新ポータルか ARM Explorer、または PowerShell を使用する必要があります。従来のポータルでは作成できないので注意しましょう。今回は新ポータルで行います。まず新ポータルを開いてください。

https://portal.azure.com/

[新規] – [Compute] – [Windows Server 2012 R2] を選択したら、「デプロイモデルの選択」で「リソースマネージャー」を選択し「作成」をクリックします。

image

仮想マシンの作成はクラシックタイプとさほど変わりありませんが、作成された仮想マシンを見てみると、強く「リソース単位」を意識していることが分かります。

image

2. 日本語化等、必要なカスタマイズを行う

作成した仮想マシンは「仮想マシン(クラシック)」ではなく、「仮想マシン」にカテゴライズされるので注意してください。

仮想マシンに接続して、必要なカスタマイズを行います。

日本語化する場合には言語パックをインストールする必要があります。ここで注意しなければならないのは、「すべてのユーザーが日本語環境を利用できるようにしておく」ということです。そうでないと、VMを展開後、新規に作成されたユーザーは英語環境のままになってしまいます。

image

image

3. Sysprep を行う

カスタマイズが完了したら、Sysprep して、シャットダウンしておきます。

image

4. 仮想マシンをキャプチャしてイメージ化する

ARM 配下の VMをキャプチャしてイメージングするには、2つの方法が用意されています。

  • Windows PowerShell または Azure CLI を使用する
  • Azure Resource Explorer(preview) を使用する

今回は後者を使用することにします。実は、現時点で Azure Resource Explorer は2種類存在しています。1つは Azure 新ポータル内に実装されているもので、リソースの状態を見ることはできますが、まだ各メソッドが実装されていません。

imageimage

もう一つは https://resources.azure.com/ で、おそらく前者のリソースエクスプローラーには最終的にこちらの機能が移植されるのでしょう。イメージをキャプチャする際にも、現時点ではこちらを使用する必要があります。

image

キャプチャするには、後者の エクスプローラーで作成した仮想マシンを検索します。結果候補のカッコ内に Microsoft Compute/virtualMachines などと書かれていますが、これはリソースのタイプです。Microsoft Compute/virtualMachine は仮想マシンを示しており、まさに今回のターゲットです。

image

ターゲットとなる仮想マシンに移動したら、はじめに右上の「ReadWrite」をクリックして更新できるようにします。次に、「Action」タブをクリックします。最後に、Capture の右側に書かれている Json 形式の定義体を変更します。vhdprefix とは作成されるイメージのファイル名です。ここで指定した文字列が、ファイル名の頭につきます。destinationCotainerName はVHDファイルが保存されるコンテナです。overwriteVhds は同じ VHD ファイルがあった場合に上書きするかどうかを指定します。ここでは Fase を指定しています。

image

以上を指定し終えたら、「Capture」をクリックします。

キャプチャされたVHDファイルは、仮想マシンと同じストレージアカウントに保存され、以下のようなURLになります。

https://<ストレージアカウント>.blob.core.windows.net/system/Microsoft.Compute/
Images/<指定したコンテナ>/<指定したPrefix>-osDisk.f8e46109-43a4-4555-b85a-6e32bdaa52a9.vhd

これで、今後新規にARM配下に仮想マシンを作成する際は、このイメージを使用できます。

ただ、現時点では一筋縄ではいかないのがつらいところで、上記イメージを作成するための「リソーステンプレート」を作成するひつようがあります。例えば、以下のようなものです。これをAzure ポータルまたは PowerShell から投入することで、新しい仮想マシンを展開できます。

実際の展開については次回

※ 以下のテンプレートはここからダウンロードできます。参考まで。 https://blogs.technet.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-56-58/ARM_5F00_Template.txt

{  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",   "contentVersion": "1.0.0.0",   "parameters": {     "osMasterImageUri": {     "type": "string",     "metadata": {          "description": "マスターイメージのURI"      }    },     "vmName": {      "type": "string",      "metadata": {        "description": "仮想マシンの名前"      }    },    "osType": {      "type": "string",      "allowedValues": [        "Windows",        "Linux"      ],      "defaultValue" :"Windows",      "metadata": {        "description": "OSのタイプ"      }    },    "adminUserName": {     "type": "string",        "metadata": {          "description": "管理者ユーザーID"      }    },    "adminPassword": {     "type": "securestring",        "metadata": {          "description": "管理者ユーザーIDのパスワード"      }    },    "vmSize": {      "type": "string",      "allowedValues": [        "Standard_A1",        "Standard_A2"      ],      "defaultValue" :"Standard_A1",      "metadata": {        "description": "仮想マシンのサイズ"      }    },    "StorageAccountName": {      "type": "string",      "metadata": {        "description": "ストレージアカウントの名前"      }    },    "existingVirtualNetworkName": {      "type": "string",      "metadata": {        "description": "仮想ネットワーク"      }    },    "subnetName": {      "type": "string",      "metadata": {        "description": "サブネット名"      }    }  },    "variables": {    "api-version": "2015-06-15",    "location": "[resourceGroup().location]",    "publicIPAddressType": "Dynamic",    "vnetID": "[resourceId('Microsoft.Network/virtualNetworks', parameters('existingVirtualNetworkName'))]",    "subnetRef": "[concat(variables('vnetID'),'/subnets/', parameters('subnetName'))]",    "nicName": "[concat(parameters('vmName'),'-nic')]",    "publicIPAddressName": "[concat(parameters('vmName'),'-pip')]",    "osDiskVhdName": "[concat('https://',parameters('StorageAccountName'),'.blob.core.windows.net/vhds/',parameters('vmName'),'osDisk.vhd')]"  },  "resources": [    {      "apiVersion": "[variables('api-version')]",      "type": "Microsoft.Network/publicIPAddresses",      "name": "[variables('publicIPAddressName')]",      "location": "[variables('location')]",      "tags": {        "displayName": "PublicIPAddress"      },      "properties": {        "publicIPAllocationMethod": "[variables('publicIPAddressType')]"      }    },    {      "apiVersion": "[variables('api-version')]",      "type": "Microsoft.Network/networkInterfaces",      "name": "[variables('nicName')]",      "location": "[variables('location')]",      "dependsOn": [        "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"        ],       "tags": {        "displayName": "NetworkInterface"           },      "properties": {        "ipConfigurations": [          {            "name": "ipconfig1",            "properties": {              "privateIPAllocationMethod": "Dynamic",              "publicIPAddress": {                "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"              },              "subnet": {                "id": "[variables('subnetRef')]"              }            }          }        ]      }    },    {      "apiVersion": "[variables('api-version')]",      "type": "Microsoft.Compute/virtualMachines",      "name": "[parameters('vmName')]",      "location": "[variables('location')]",      "tags": {        "displayName": "VirtualMachine"      },      "dependsOn": [        "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"      ],      "properties": {        "hardwareProfile": {          "vmSize": "[parameters('vmSize')]"        },      "osProfile": {          "computername": "[parameters('vmName')]",          "adminUsername": "[parameters('adminUsername')]",          "adminPassword": "[parameters('adminPassword')]"                },       "storageProfile": {          "osDisk": {            "name": "[concat(parameters('vmName'),'-osDisk')]",            "osType": "[parameters('osType')]",            "caching": "ReadWrite",            "createOption": "FromImage",            "image": {                  "uri": "[parameters('osMasterImageUri')]"            },            "vhd": {                  "uri": "[variables('osDiskVhdName')]"            }          }        },        "networkProfile": {          "networkInterfaces": [            {              "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('nicName'))]"            }          ]        }      }    }  ]}