同じ構成の VM を簡単に複製してみる


# やりたいこと

とあるイベントで開発環境として VM を提供することになり、手作業は面倒なので簡単に複製できないかといろいろ作業した内容をまとめます。

[とあるイベント (宣伝)](#宣伝)

# VM の複製方法

以下の2つの方法がある。

1. スナップショットを使う方法
1. イメージ (キャプチャ) を使う方法

## スナップショットを使う方法

VM にアタッチされる OS ディスクのスナップショットを作成して、そのスナップショットから新しく OS ディスクを作成して、そのディスクを別の VM にアタッチする方法。

複製元の VM の**完全な**複製を行いたい場合に適している。複製した VM のコンピュータ名や管理者も完全に複製されるため、個人的にはバックアップ的な意味合いが強いと思っている。

### 特徴

- イメージを使う方法では**一般化**という作業が必要で、一般化した VM はそれ以降使用できなくなるがスナップショットの場合だとそのまま継続して使用可能
- コンピュータ名や管理者も完全に複製される
- 複製元の VM と複製した VM の同時利用には注意が必要 (Windows ライセンスなど)

https://learn.microsoft.com/ja-jp/azure/virtual-machines/snapshot-copy-managed-disk?tabs=portal

## イメージを使う方法

ベースとなる VM からイメージを作成して、そのイメージから VM を複製する方法 (Market Place にあるイメージを使うのと同じ)。イメージを作成する際には、**一般化**を行いコンピュータ名や管理者名を削除する (VM の複製時に新しく設定される)。

必要なアプリケーションなどをインストールするなどして、事前に作成した環境を配布するような場合に適している。ただし、ユーザレベルのインストールは一般化の際に削除する必要があるので、システムレベルでのインストールが必要。

### 特徴

- イメージに含められるのは、システムレベルでインストールしたアプリケーションや設定のみ
- コンピュータ名や管理者名が新規に設定されるので、同時利用に問題がない
- 一般化した複製元の VM はそれ以降使用できなくなる

https://learn.microsoft.com/ja-jp/azure/virtual-machines/capture-image-resource

https://learn.microsoft.com/ja-jp/azure/virtual-machines/generalize

## 今回は

同時利用が前提になるので、イメージを使う方法とした。

# 手順

大まかな手順としては以下。

1. ベースとなる VM を作成する
1. ベース VM に必要なアプリケーションをインストールする
1. インストール後、ベース VM を一般化する
1. 一般化した VM から複製するイメージを作成する
1. 作成したイメージから必要な数だけ VM を作成する
1. 複製した VM 上でベースイメージに含められなかったアプリケーションをインストールする

最終的にスクリプト化したいので、CLI で作成していく。

# ベース VM の作成

NSG のルールは後で作成するのでここでは設定しない。

```sh
az vm create --name vm-base \
             --resource-group **** \
             --location japaneast \
             --image MicrosoftWindowsServer:WindowsServer:2022-Datacenter:latest \
             --admin-username **** \
             --admin-password **** \
             --size Standard_D4_v3 \
             --os-disk-name vm-base-osdisk \
             --storage-sku StandardSSD_LRS \
             --vnet-name vm-base-vnet \
             --subnet vm-base-snet \
             --public-ip-address vm-base-pip \
             --nsg vm-base-nsg \
             --nsg-rule None
```

# NSG ルールの作成

特定の IP からのみアクセス許可する場合には NSG を設定する。以下は特定 IP からの RDP を許可するルール。

```sh
az network nsg rule create --resource-group **** \
                           --nsg-name vm-base-nsg \
                           --name Allow-Specified-Ip \
                           --access Allow \
                           --protocol Tcp \
                           --direction Inbound \
                           --priority 100 \
                           --source-address-prefix *.*.*.*/* \
                           --source-port-range "*" \
                           --destination-port-range 3389
```

# 必要なアプリケーションをインストールする

ベース VM に接続してアプリケーションをインストールする。割愛。

# ベース VM を一般化する

今回使った VM は Windows のものなので、Windows でのやり方。以下のドキュメントを参考に一般化する。

https://learn.microsoft.com/ja-jp/azure/virtual-machines/generalize#windows

一般化の際にエラーとなる場合は、以下の記事を参考にユーザレベルのインストールや設定を削除する。

https://qiita.com/chanken/items/da3f2b539f8855934923

ベース VM 上で一般化できたら、一般化を適用する (タグ付け的な)。

```sh
az vm generalize --name vm-base \
                 --resource-group ****
```

# イメージを作成する

一般化したベース VM からイメージを作成する。

```sh
az image create --name vm-image-base \
                --resource-group **** \
                --source vm-base
```

# イメージから VM の複製

複製する VM で利用する VNET や Subnet、NSG は共用とした。

```sh
az vm create --name vm-01 \
             --resource-group **** \
             --location japaneast \
             --image vm-image-base \
             --admin-username **** \
             --admin-password **** \
             --size Standard_D4_v3 \
             --os-disk-name vm-01-osdisk \
             --storage-sku StandardSSD_LRS \
             --vnet-name vm-common-vnet \
             --public-ip-address vm-01-pip \
             --nsg vm-common-nsg \
             --nsg-rule None \
             --subnet vm-common-snet
```

# NSG ルールの作成

特定の IP からのみアクセス許可する場合には NSG を設定する。以下は特定 IP からの RDP を許可するルール。

```sh
az network nsg rule create --resource-group **** \
                           --nsg-name vm-common-nsg \
                           --name Allow-Specified-Ip \
                           --access Allow \
                           --protocol Tcp \
                           --direction Inbound \
                           --priority 100 \
                           --source-address-prefix *.*.*.*/* \
                           --source-port-range "*" \
                           --destination-port-range 3389
```

複製した VM に接続すると、ベース VM でインストールしていたアプリケーションなどが既にインストールされている状態になっている！

# 自動シャットダウンの設定

スケジュールでのシャットダウンを設定する。`--time` は UTC での指定なので注意。以下は18時に自動的にシャットダウンする設定。

```sh
az vm auto-shutdown --resource-group **** \
                    --name vm-01 \
                    --time 0900
```

# その他

- 各リージョンで、vCPU のクォータ上限があるので注意
  - 確認は Portal or 以下コマンドで

  ```sh
  az vm list-usage --location "Japan East" -o table
  ```

- パブリック IP の確認は以下コマンドが便利。

  ```sh
  az vm list-ip-addresses --resource-group **** \
                          --query "[].virtualMachine[].{Name:name, PublicIp:network.publicIpAddresses[0].ipAddress}" -o table
  ```

# 宣伝

とあるイベントというのは、以下の新卒向けワークショップです！
定期的に開催する予定ですので、ご興味のある方はぜひお申し込みください！

https://paiza.jp/feedback/recruiter_interview_27