Tạo Windows VM Template trên Proxmox với Sysprep và VirtIO Drivers: Clone hàng loạt máy ảo trong vài phút

Virtualization tutorial - IT technology blog
Virtualization tutorial - IT technology blog

Mình đã từng tốn cả buổi sáng setup từng máy Windows một cho team dev — copy ISO, cài lại từ đầu, activate, cài driver, cấu hình timezone… Sau lần đó mình quyết định làm một lần, dùng mãi mãi với VM Template + Sysprep.

Mình chạy homelab với Proxmox VE quản lý 12 VM và container — đây là playground để test mọi thứ trước khi đưa lên production. Workflow template này tiết kiệm cực nhiều thời gian: clone xong một VM Windows sạch mất chưa tới 2 phút, hostname và SID tự generate mới hoàn toàn.

Quick Start: Tạo template trong 5 bước

Đây là flow cốt lõi — nắm được cái này là làm được ngay:

  1. Tạo VM mới → cài Windows từ ISO
  2. Cài VirtIO drivers (storage, network, balloon, guest agent)
  3. Chạy Sysprep với tùy chọn Generalize + Shutdown
  4. Sau khi VM shutdown → Right-click → Convert to Template
  5. Clone khi cần → VM mới sạch tinh, tự gen SID mới

Chuẩn bị 2 thứ trước khi bắt đầu:

  • ISO Windows: Windows 10/11 hoặc Windows Server
  • VirtIO ISO: tải file virtio-win.iso từ repo Fedora (stable release)

Tạo VM chuẩn để làm Template

Cấu hình VM tối ưu ngay từ đầu

Khi tạo VM trong Proxmox, có vài lựa chọn ảnh hưởng lâu dài đến template:

  • Machine type: chọn q35 (hỗ trợ PCIe, tốt hơn i440fx)
  • BIOS: OVMF (UEFI) nếu muốn Secure Boot; SeaBIOS nếu cần compat cũ
  • Storage controller: VirtIO Block hoặc SCSI với VirtIO SCSI single
  • Network: VirtIO (paravirtualized) — throughput tốt nhất
  • CPU: host hoặc x86-64-v2-AES để tối ưu hiệu năng

Một lưu ý quan trọng: đừng đặt RAM/CPU quá cao trong template. Khi clone sẽ điều chỉnh theo từng use case — template chỉ cần đủ để cài và chạy Sysprep.

Gắn 2 ISO cùng lúc vào VM

Trước khi cài Windows, gắn cả 2 ISO vào VM:

VM → Hardware → Add → CD/DVD Drive
  IDE 0: Windows.iso     (boot drive chính)
  IDE 2: virtio-win.iso  (CD/DVD Drive thứ 2)

Nếu dùng VirtIO storage controller, Windows installer sẽ không thấy ổ cứng khi chọn nơi cài. Lúc đó chọn Load driver và trỏ vào đĩa VirtIO: viostor\amd64\w10 (hoặc w11/2k22 tùy version Windows).

Cài VirtIO Drivers: Bước không được bỏ qua

Nhiều người bỏ sót bước này rồi sau khi clone xong thấy máy không có mạng hoặc chạy chậm bất thường. Sau khi Windows cài xong, mở Device Manager sẽ thấy một đống thiết bị chưa nhận driver — đó là VirtIO devices chưa được Windows nhận ra.

Cài toàn bộ driver một lần với Guest Tools

Cách nhanh nhất: chạy installer tổng hợp từ đĩa VirtIO:

D:\virtio-win-guest-tools.exe

File này cài luôn toàn bộ: balloon driver, network adapter (NetKVM), storage controller (viostor/vioscsi), memory ballooning, QEMU guest agent, serial driver… Xong một phát, không cần cài từng thứ.

Bật QEMU Guest Agent trên Proxmox

Sau khi cài xong guest tools, vào Proxmox → VM → Options → QEMU Guest Agent → Enable. Tính năng này cho phép Proxmox đọc IP của VM, thực hiện shutdown sạch từ host, và freeze filesystem khi backup — rất cần thiết cho production.

# Kiểm tra service guest agent đang chạy chưa
Get-Service QEMU-GA

Sysprep: Tạo “khuôn” cho mọi VM clone

Sysprep là tool của Microsoft để generalize Windows — xóa machine-specific info (SID, hostname, activation state, event logs…) để mỗi lần clone ra là một máy hoàn toàn mới về mặt identity. Thiếu bước này, clone ra 10 máy vẫn cùng SID — domain join sẽ fail hoặc gây conflict.

Cách nhanh: GUI Sysprep

C:\Windows\System32\Sysprep\sysprep.exe

Chọn các tùy chọn sau:

  • System Cleanup Action: Enter System Out-of-Box Experience (OOBE)
  • Generalize: ✅ bắt buộc tick vào
  • Shutdown Options: Shutdown

Sysprep chạy xong VM tự shutdown. Lúc này tuyệt đối không boot lại VM — convert thành template ngay lập tức.

Cách automation: Unattend.xml

Nếu muốn bỏ qua hoàn toàn OOBE (màn hình setup ban đầu sau khi clone), tạo file 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>

Đặt file này vào C:\Windows\System32\Sysprep\unattend.xml, rồi chạy Sysprep từ command line:

C:\Windows\System32\Sysprep\sysprep.exe /oobe /generalize /shutdown /unattend:unattend.xml

Convert VM thành Template và Clone

# Từ Proxmox Shell — dùng VM ID thực tế của bạn
qm template 101

# Hoặc trên Web UI:
# Right-click VM → Convert to Template

VM chuyển sang icon khác (hình tờ giấy) và không thể start trực tiếp — chỉ clone được. Khi cần deploy:

# Full clone — VM độc lập hoàn toàn (khuyến nghị cho production)
qm clone 101 201 --name win10-dev-01 --full true --storage local-lvm

# Linked clone — nhanh hơn, tiết kiệm disk nhưng phụ thuộc template
qm clone 101 202 --name win10-test-01

Nâng cao: Automation deploy hàng loạt bằng Python

Khi cần deploy 5-10 VM cùng lúc, dùng Proxmox API thay vì click tay:

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()

# Deploy 5 VM song song
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 token tạo trong Proxmox: Datacenter → API Tokens → Add. Dùng token thay vì password — giới hạn quyền được, revoke dễ dàng.

Tips thực tế từ kinh nghiệm dùng hàng ngày

1. Giữ template gọn nhẹ

Chỉ cài những gì mọi VM đều cần: VirtIO drivers, QEMU Guest Agent, Windows Updates thiết yếu. Phần mềm riêng của từng VM (Visual Studio, SQL Server, IIS…) cài sau khi clone — đừng nhét hết vào template.

2. Đặt tên template có versioning

win10-22h2-virtio-v1-template
win2022-dc-virtio-v2-template

Khi rebuild template (sau đợt patch lớn), giữ version cũ lại. Rollback dễ dàng nếu bản mới có vấn đề.

3. Snapshot “pre-sysprep” trước khi generalize

# Tạo snapshot trước khi chạy Sysprep
qm snapshot 101 pre-sysprep --description "Drivers installed, before sysprep"

Nếu Sysprep fail hoặc muốn thêm gì đó vào template, rollback về snapshot này — không phải cài lại từ đầu.

4. Chạy Windows Update trước Sysprep

Update hết patch, reboot đủ lần, rồi mới Sysprep. Template đã có patch mới thì VM clone ra ít phải update hơn — tiết kiệm thời gian đáng kể khi deploy cùng lúc nhiều máy.

5. Test clone trước khi dùng thật

Clone thử 1 VM, boot lên kiểm tra kỹ trước khi dùng template cho production:

# Kiểm tra SID — phải KHÁC với SID của template gốc
whoami /user

# Kiểm tra hostname đã thay đổi
hostname

# Kiểm tra network adapter nhận driver VirtIO chưa
Get-NetAdapter

Mình từng quên tick Generalize trong Sysprep — clone ra 10 máy cùng SID, domain join fail toàn bộ. Mất thêm nửa buổi để xử lý. Test kỹ một lần, tiết kiệm nhiều lần sau.

6. Linked clone cho lab, full clone cho production

Linked clone tạo trong vài giây, tiết kiệm disk — dùng cho VM test tạm thời trên homelab. Full clone hoàn toàn độc lập — dùng cho production hoặc VM cần lưu lâu dài. Đừng dùng linked clone cho production vì xóa template là mất hết VM clone từ nó.

Share: