以前、開発チーム向けにWindowsマシンを1台ずつセットアップするのに午前中まるまるかかったことがある。ISOのコピー、再インストール、ライセンス認証、ドライバーのインストール、タイムゾーンの設定……。それ以来、一度だけ作業してあとはずっと使い回せるVMテンプレート+Sysprepの仕組みを取り入れることにした。
私のホームラボはProxmox VEで12台のVMとコンテナを管理している。本番環境に持ち込む前に何でもテストできるプレイグラウンドだ。このテンプレートワークフローは時間を大幅に節約してくれる。クリーンなWindows VMのクローンが2分以内で完成し、ホスト名とSIDは自動的に新たに生成される。
クイックスタート:5ステップでテンプレートを作成
これが核となるフロー。これを押さえれば即実践できる:
- 新しいVMを作成 → ISOからWindowsをインストール
- VirtIOドライバーをインストール(ストレージ、ネットワーク、balloon、Guest Agent)
- Generalize + ShutdownオプションでSysprepを実行
- VMシャットダウン後 → 右クリック → Convert to Template
- 必要なときにクローン → 新しいVMはクリーンな状態で新しいSIDが自動生成される
開始前に2つ準備しておく:
- Windows ISO:Windows 10/11またはWindows Server
- VirtIO ISO:FedoraリポジトリからStableリリースの
virtio-win.isoをダウンロード
テンプレート用VMの適切な作成
最初から最適なVM設定を行う
ProxmoxでVMを作成する際、テンプレートに長期的な影響を与えるいくつかの選択肢がある:
- Machine type:
q35を選択(PCIe対応、i440fxより優れている) - BIOS:Secure Bootを使用する場合はOVMF(UEFI)、旧来の互換性が必要な場合はSeaBIOS
- ストレージコントローラー:VirtIO BlockまたはVirtIO SCSI singleを使ったSCSI
- ネットワーク:VirtIO(準仮想化) — 最も優れたスループット
- CPU:パフォーマンス最適化のために
hostまたはx86-64-v2-AES
重要な注意点:テンプレートにRAM/CPUを高く設定しすぎないこと。クローン時にユースケースに合わせて調整できる。テンプレートはインストールとSysprepの実行に必要な最低限のリソースで十分だ。
VMに2つのISOを同時にマウントする
Windowsをインストールする前に、VMに両方のISOをマウントする:
VM → Hardware → Add → CD/DVD Drive
IDE 0: Windows.iso (メインのブートドライブ)
IDE 2: virtio-win.iso (2枚目のCD/DVDドライブ)
VirtIOストレージコントローラーを使用する場合、インストール先を選択する際にWindowsインストーラーがハードディスクを認識できない。その場合はLoad driverを選択し、VirtIOディスクを指定する:viostor\amd64\w10(Windowsのバージョンに応じてw11/2k22など)。
VirtIOドライバーのインストール:省略できない重要なステップ
このステップを省略すると、クローン後にネットワークが使えなかったり、異常なほど動作が遅くなることがある。Windowsのインストール完了後にデバイスマネージャーを開くと、ドライバーが当たっていないデバイスが大量にある。これらはWindowsに認識されていないVirtIOデバイスだ。
Guest Toolsで一括ドライバーインストール
最速の方法:VirtIOディスクから統合インストーラーを実行する:
D:\virtio-win-guest-tools.exe
このファイルがすべてを一括インストールする:balloonドライバー、ネットワークアダプター(NetKVM)、ストレージコントローラー(viostor/vioscsi)、メモリバルーニング、QEMUゲストエージェント、シリアルドライバーなど。一度の実行で完了し、個別にインストールする必要はない。
ProxmoxでQEMU Guest Agentを有効化する
Guest Toolsのインストール後、Proxmox → VM → Options → QEMU Guest Agent → Enableと進む。この機能によりProxmoxはVMのIPアドレスを読み取り、ホストから安全なシャットダウンを実行でき、バックアップ時にファイルシステムをフリーズできる。本番環境では必須の設定だ。
# QEMU Guest Agentサービスが起動しているか確認
Get-Service QEMU-GA
Sysprep:すべてのクローンVMの「型」を作る
SysprepはMicrosoftのツールで、Windowsを一般化(generalize)するために使用する。マシン固有の情報(SID、ホスト名、アクティベーション状態、イベントログなど)を削除し、クローンするたびに完全に新しいIDを持つマシンを作り出す。このステップを省略すると、10台クローンしても全機同じSIDになり、ドメイン参加に失敗するかコンフリクトが発生する。
簡単な方法:GUI Sysprep
C:\Windows\System32\Sysprep\sysprep.exe
以下のオプションを選択する:
- System Cleanup Action:Enter System Out-of-Box Experience (OOBE)
- Generalize:✅ 必須チェック
- Shutdown Options:Shutdown
Sysprepが完了するとVMは自動的にシャットダウンする。この時点で絶対にVMを再起動しないこと — すぐにテンプレートに変換する。
自動化する方法:Unattend.xml
クローン後のOOBE(初回セットアップ画面)を完全にスキップしたい場合は、unattend.xmlファイルを作成する:
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="specialize">
<component name="Microsoft-Windows-Shell-Setup"
processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35"
language="neutral" versionScope="nonSxS">
<TimeZone>Tokyo Standard Time</TimeZone>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup"
processorArchitecture="amd64"
publicKeyToken="31bf3856ad364e35"
language="neutral" versionScope="nonSxS">
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideLocalAccountSetupPage>true</HideLocalAccountSetupPage>
<ProtectYourPC>3</ProtectYourPC>
<SkipMachineOOBE>true</SkipMachineOOBE>
</OOBE>
</component>
</settings>
</unattend>
このファイルをC:\Windows\System32\Sysprep\unattend.xmlに配置し、コマンドラインからSysprepを実行する:
C:\Windows\System32\Sysprep\sysprep.exe /oobe /generalize /shutdown /unattend:unattend.xml
VMをテンプレートに変換してクローンする
# ProxmoxシェルからVMの実際のIDを指定して実行
qm template 101
# またはWeb UIから:
# 右クリック → Convert to Template
VMのアイコンが変わり(紙のアイコン)、直接起動できなくなる — クローンのみ可能だ。デプロイが必要な場合:
# フルクローン — 完全に独立したVM(本番環境に推奨)
qm clone 101 201 --name win10-dev-01 --full true --storage local-lvm
# リンクドクローン — 高速でディスク節約だがテンプレートに依存
qm clone 101 202 --name win10-test-01
応用編:PythonでVMを一括自動デプロイ
5〜10台のVMを同時にデプロイする場合は、手動でクリックするよりProxmox APIを使う方が効率的だ:
import requests
import urllib3
urllib3.disable_warnings()
PVE_HOST = "https://proxmox.local:8006"
TOKEN_ID = "root@pam!deploy"
TOKEN_SECRET = "your-api-token-secret"
headers = {
"Authorization": f"PVEAPIToken={TOKEN_ID}={TOKEN_SECRET}"
}
def clone_vm(template_id: int, new_id: int, name: str, storage: str = "local-lvm"):
url = f"{PVE_HOST}/api2/json/nodes/pve/qemu/{template_id}/clone"
data = {
"newid": new_id,
"name": name,
"full": 1,
"storage": storage,
}
resp = requests.post(url, headers=headers, json=data, verify=False)
resp.raise_for_status()
return resp.json()
# 5台のVMを並行してデプロイ
for i in range(1, 6):
result = clone_vm(101, 200 + i, f"win10-worker-{i:02d}")
print(f"Clone VM {200 + i}: task {result['data']}")
APIトークンはProxmoxで作成する:Datacenter → API Tokens → Add。パスワードの代わりにトークンを使うことで、権限を制限でき、簡単に無効化できる。
日々の運用で得た実践的なTips
1. テンプレートをスリムに保つ
すべてのVMに必要なもの(VirtIOドライバー、QEMU Guest Agent、重要なWindows Update)だけをインストールする。VM固有のソフトウェア(Visual Studio、SQL Server、IISなど)はクローン後にインストールする — テンプレートに詰め込まないこと。
2. バージョン管理付きのテンプレート名を付ける
win10-22h2-virtio-v1-template
win2022-dc-virtio-v2-template
大きなパッチ適用後にテンプレートを再ビルドする際は、古いバージョンを残しておく。新しいバージョンに問題があった場合に簡単にロールバックできる。
3. Generalize前に「pre-sysprep」スナップショットを作成する
# Sysprep実行前にスナップショットを作成
qm snapshot 101 pre-sysprep --description "Drivers installed, before sysprep"
Sysprepが失敗した場合やテンプレートに何か追加したい場合、このスナップショットに戻ることができる — 最初からインストールし直す必要はない。
4. Sysprep前にWindows Updateを適用する
すべてのパッチを適用し、必要な回数だけ再起動してからSysprepを実行する。最新パッチが適用済みのテンプレートからクローンしたVMは、アップデートが少なくて済む。複数台を同時にデプロイする際に大幅な時間節約になる。
5. 本番使用前にクローンをテストする
テンプレートを本番環境で使用する前に、1台のVMをクローンして起動し、詳しく確認する:
# SIDを確認 — 元のテンプレートのSIDと異なるはず
whoami /user
# ホスト名が変更されているか確認
hostname
# ネットワークアダプターがVirtIOドライバーを認識しているか確認
Get-NetAdapter
以前、SysprepでGeneralizeにチェックを入れ忘れたことがある。10台クローンしたところ全機同じSIDになり、ドメイン参加が全滅した。その後処理に半日かかった。一度しっかりテストすれば、後何度も節約できる。
6. ラボにはリンクドクローン、本番にはフルクローン
リンクドクローンは数秒で作成でき、ディスクを節約できる — ホームラボの一時的なテスト用VMに使う。フルクローンは完全に独立している — 本番環境や長期保存が必要なVMに使う。本番環境にリンクドクローンを使わないこと。テンプレートを削除するとそこからクローンしたすべてのVMが失われる。

