Runbook — Windows Server 2022 Template di Incus Cluster#

Cluster: trim-computes-shr-incus-01 s/d 04 (Lenovo ThinkAgile HX630, Debian 13, Incus 7.2 Zabbly) Storage: lvmcluster (sanlock/lvmlockd) di QNAP iSCSI — pool-qnap-hdd-01 (cluster-wide), pool-iso-and-templates (node-local, incus-01) Terakhir diperbarui: 25 Juli 2026


1. Ringkasan & Keputusan Arsitektur#

Template Windows Server 2022 dibuat sebagai VM stopped pasca-sysprep di project Templates. Deployment VM baru dilakukan via incus copy / OpenTofu source_instance, BUKAN via incus publish + image.

Kenapa jalur copy, bukan publish:

  1. Bug lvmcluster — di storage lvmcluster, volume VM disimpan sebagai QCOW2 container di dalam LV. incus publish (build sebelum fix PR lxc/incus#3705) meng-export volume sebagai raw, sehingga image berisi file QCOW2 mentah. Instance dari image tersebut gagal boot: BdsDxe: failed to load Boot0002 ... Not Found → jatuh ke PXE, dan firmware File Explorer kosong total (tidak ada ESP terbaca). Referensi: forum thread 26990.
  2. Copy lebih ringan — mekanisme copy instance lebih cepat daripada unpack image besar (konfirmasi maintainer Incus).
  3. Snapshot delete juga masih bugged di build yang sama (qemu-img commit dengan path kosong) — sehingga snapshot template ditunda sampai fix rilis (lihat §11).

Setelah fix #3705 masuk paket Zabbly: publish boleh dipakai sebagai arsip versi immutable (lihat §11), jalur copy tetap jadi jalur deploy harian.


2. Prasyarat#

  • Akses root/sudo ke node incus-01 (ISO node-local ada di sini).
  • ISO Windows Server 2022 (SERVER_EVAL_x64FRE_en-us) dan ISO virtio-win-latest sudah tersedia sebagai custom volume di pool pool-iso-and-templates.
  • Project Templates sudah ada. Catatan: project ini memakai features.storage.volumes: "true" → punya namespace volume sendiri, volume di project default TIDAK terlihat dari sini.
  • Ruang kosong cukup di pool-qnap-hdd-01 untuk root disk 66GiB.

Cek cepat:

incus storage volume list pool-iso-and-templates --all-projects
incus project show Templates | grep -E "storage.volumes|images"

3. Siapkan ISO di Project Templates#

Karena namespace volume terpisah, copy kedua ISO dari default ke Templates (copy, bukan move — biar tetap bisa dipakai project lain):

incus storage volume copy pool-iso-and-templates/SERVER_EVAL_x64FRE_en-us \
  pool-iso-and-templates/SERVER_EVAL_x64FRE_en-us --target-project Templates

incus storage volume copy pool-iso-and-templates/virtio-win-latest \
  pool-iso-and-templates/virtio-win-latest --target-project Templates

Rationale: device disk tidak bisa menunjuk volume lintas project. Kalau attach error Storage volume not found padahal volume ada, cek dulu project dan lokasi node-nya — dua penyebab paling umum.


4. Create VM Template#

WAJIB pin ke incus-01 (--target) karena ISO-nya node-local. Tanpa target, scheduler bisa menaruh VM di node lain dan attach ISO gagal Storage volume not found.

incus init trim-vm-shr-tx-template-win2022 --empty --vm --project Templates \
  --target trim-computes-shr-incus-01 \
  -c limits.cpu=4 -c limits.memory=8GiB \
  -s pool-qnap-hdd-01 \
  -d root,size=66GiB

Set image.os=Windows — WAJIB, ini yang menentukan isi agent drive nanti (Windows vs Linux) dan menyesuaikan behavior QEMU untuk guest Windows:

incus config set trim-vm-shr-tx-template-win2022 image.os=Windows --project Templates

Opsional (vTPM, tidak wajib untuk Win2022):

incus config device add trim-vm-shr-tx-template-win2022 vtpm tpm --project Templates

Gotcha flag -d: formatnya device,key=value — SATU pasang key=value per flag. -d root,size=66GiB,pool=... akan error validation. Pool dipisah ke flag -s.

Gotcha move antar node: incus move --target untuk VM yang sudah dibuat bisa gagal target instance root disk size is smaller than the migration source — LV di lvmcluster di-round up ke extent boundary (66GiB → 66.01g), validasi migrasi menolak. Kalau VM masih kosong, lebih cepat delete + init ulang dengan --target yang benar.


5. Attach ISO Installer & Driver#

incus config device add trim-vm-shr-tx-template-win2022 install disk \
  pool=pool-iso-and-templates source=SERVER_EVAL_x64FRE_en-us boot.priority=10 --project Templates

incus config device add trim-vm-shr-tx-template-win2022 drivers disk \
  pool=pool-iso-and-templates source=virtio-win-latest --project Templates

6. Install Windows#

Start dan buka console VGA:

incus start trim-vm-shr-tx-template-win2022 --project Templates
incus console trim-vm-shr-tx-template-win2022 --type=vga --project Templates

6a. Masalah: WinPE tidak melihat disk maupun CD virtio#

Di step “Load driver”, dialog Browse hanya menampilkan Boot (X:) — tidak ada CD drive sama sekali.

Penyebab: semua storage device (disk 66GB + kedua ISO) menempel di bus virtio-scsi, dan WinPE belum punya driver vioscsi. Firmware EDK2 bisa boot dari ISO (punya driver sendiri), tapi begitu WinPE mengambil alih — buta total. Telur-ayam: driver ada di CD yang tidak terbaca karena butuh driver itu sendiri.

Solusi (pilih salah satu):

Opsi A — pindahkan ISO virtio ke bus USB (tercepat; WinPE punya driver USB built-in):

incus stop trim-vm-shr-tx-template-win2022 --project Templates --force
incus config device set trim-vm-shr-tx-template-win2022 drivers io.bus=usb --project Templates
incus start trim-vm-shr-tx-template-win2022 --project Templates

Opsi B — repack ISO installer dengan distrobuilder (driver di-inject ke boot.wim/install.wim, masalah hilang dari akar):

sudo distrobuilder repack-windows --windows-version=w2k22 \
  --drivers=virtio-win.iso SERVER_EVAL_x64FRE_en-us.iso win2022-virtio.iso
incus storage volume import pool-iso-and-templates win2022-virtio.iso win2022-virtio \
  --type=iso --project Templates
# lalu swap device "install" ke volume baru ini

6b. Load driver di installer#

Di pemilihan disk: Load driver → Browse → CD virtio-win:

  • vioscsi\2k22\amd64 → disk 66GB muncul, DVD installer terbaca lagi
  • NetKVM\2k22\amd64 → network langsung hidup di first boot

Lanjutkan instalasi sampai masuk desktop.


7. Post-Install (urutan penting)#

7a. VirtIO Guest Tools#

Jalankan virtio-win-guest-tools.exe dari CD virtio — install semua driver sisanya (Balloon, serial, QXL, dsb) sekali jalan.

7b. Driver viosock (prasyarat komunikasi agent)#

Kalau guest-tools melewatkannya (cek Device Manager: unknown device / PCI Simple Communications Controller bertanda seru), install manual dari PowerShell/CMD admin:

pnputil /add-driver D:\viosock\2k22\amd64\viosock.inf /install

Verifikasi: Device Manager → System devices → VirtIO Socket tanpa tanda seru.

7c. Incus Agent (Windows)#

Dari host, attach agent drive:

incus config device add trim-vm-shr-tx-template-win2022 agent disk source=agent:config --project Templates
incus restart trim-vm-shr-tx-template-win2022 --project Templates

Kalau isi CD agent berupa file Linux (install.sh, folder systemd) — berarti image.os=Windows belum di-set (§4). Set, lalu restart VM: drive akan berisi incus-agent.exe + install.ps1.

Di dalam Windows (PowerShell admin, sesuaikan drive letter):

powershell -ExecutionPolicy Bypass -File E:\install.ps1

Restart VM, lalu verifikasi dari host — IP muncul = vsock → agent → host jalan penuh:

incus info trim-vm-shr-tx-template-win2022 --project Templates
incus exec trim-vm-shr-tx-template-win2022 --project Templates -- cmd /c hostname

PENTING: device agent (CD-ROM) TIDAK boleh di-detach — diakses setiap boot untuk refresh agent + credentials TLS. Ini bagian permanen template; semua clone otomatis mewarisinya. Catatan: jam guest harus sinkron wajar dengan host (agent pakai TLS cert).

7d. Windows Update + software standar#

  • Windows Update sampai tuntas (di template, bukan di tiap clone).
  • Install software/agent standar perusahaan.

7e. Yang JANGAN dilakukan di template#

  • ❌ Join domain
  • ❌ Set IP statis
  • ❌ Aktivasi lisensi final

Semua itu urusan per-clone setelah deploy. Template harus netral.


8. Fallback Bootloader (anti masalah NVRAM)#

UEFI NVRAM (boot entries) itu per-instance dan tidak ikut ter-copy sempurna di semua jalur. Windows hanya mendaftarkan \EFI\Microsoft\Boot\bootmgfw.efi via NVRAM entry — kalau entry hilang, firmware fallback ke \EFI\Boot\bootx64.efi yang TIDAK di-install Windows di fixed disk. Kita isi manual supaya disk self-bootable di firmware manapun:

mountvol S: /S
copy /Y S:\EFI\Microsoft\Boot\bootmgfw.efi S:\EFI\Boot\bootx64.efi
mountvol S: /D

mountvol /S me-mount EFI System Partition (FAT32 tersembunyi) ke drive letter pilihan. Huruf S arbitrary. Cek dulu dir S:\EFI kalau ragu.


9. Sysprep — Langkah Terakhir di Dalam Guest#

C:\Windows\System32\Sysprep\sysprep.exe /generalize /oobe /shutdown /mode:vm
  • /generalize — buang SID, machine-specific state → tiap clone dapat identitas baru
  • /oobe — clone boot ke Out-of-Box Experience
  • /mode:vm — skip hardware re-detection (semua clone di virtual hardware identik, first boot jauh lebih cepat)

VM shutdown sendiri setelah selesai.

⚠️ JANGAN PERNAH start template ini lagi. Sekali boot, generalize-nya terpakai (dan ada rearm limit). Kalau butuh update template → lihat §12.


10. Finalisasi dari Host#

Detach ISO installer & driver (agent drive TETAP terpasang):

incus config device remove trim-vm-shr-tx-template-win2022 install --project Templates
incus config device remove trim-vm-shr-tx-template-win2022 drivers --project Templates

Proteksi template:

incus config set trim-vm-shr-tx-template-win2022 security.protection.delete=true --project Templates
incus config set trim-vm-shr-tx-template-win2022 boot.autostart=false --project Templates

Test clone (wajib sebelum dipakai produksi)#

incus copy trim-vm-shr-tx-template-win2022 test-win-01 \
  --project Templates --target-project Staging --target trim-computes-shr-incus-01
incus start test-win-01 --project Staging

Kriteria lulus:

  1. Boot masuk OOBE (region → EULA → password Administrator baru). Langsung ke login screen lama = sysprep gagal, ulangi dari §9 (template harus di-rebuild).
  2. incus info test-win-01 --project Staging menampilkan IP (agent + viosock ikut ter-clone).
  3. whoami /user → SID berbeda dari template.

Bersihkan: incus stop test-win-01 --project Staging && incus delete test-win-01 --project Staging

Ekspektasi durasi copy: lvmcluster = LV non-thin, tidak ada CoW — copy adalah salinan blok penuh via qemu-img (~140 MB/s di pool HDD lewat iSCSI). Belasan menit per clone itu NORMAL. Tips: selalu sertakan --target yang sama dengan lokasi eksekusi supaya read-write satu node; pool SSD (RAID10 SA500) akan memangkas waktu signifikan. Monitor: incus operation list --project <proj> + iostat -xm 2 (metadata operation tidak menampilkan persentase — normal).


11. Deployment#

OpenTofu (jalur utama)#

resource "incus_instance" "win_vm" {
  name     = var.vm_name
  type     = "virtual-machine"
  project  = "Staging"
  profiles = var.profiles

  source_instance = {
    project = "Templates"
    name    = "trim-vm-shr-tx-template-win2022"
    # snapshot = "clean"   # aktifkan setelah fix #3705 rilis, lihat bawah
  }
}

Tiap apply VM baru = belasan menit (block copy) — tofu terlihat “hang”, itu normal.

Manual#

incus copy trim-vm-shr-tx-template-win2022 <nama-vm> \
  --project Templates --target-project <project> --target <node>

Setelah fix PR #3705 masuk paket Zabbly#

Cek build: apt policy incus (Zabbly rebuild dengan version string tetap “7.2” — bandingkan TANGGAL di Installed: vs Candidate:). Upgrade rolling per node, tunggu incus cluster list ONLINE sebelum lanjut node berikutnya.

Lalu:

  1. Snapshot beku: incus snapshot create trim-vm-shr-tx-template-win2022 clean --project Templates → aktifkan snapshot = "clean" di tofu. Deploy selalu dari titik beku walau template tak sengaja berubah.
  2. Publish sebagai arsip versi (opsional, hybrid):
incus publish trim-vm-shr-tx-template-win2022 --alias win2022-template-2026.07 --project Templates
# WAJIB verifikasi sebelum dipercaya:
incus image export win2022-template-2026.07 /tmp/win-img --project Templates
file /tmp/win-img*
# "DOS/MBR boot sector; GPT" = sah ✅ | "QEMU QCOW2 Image" = masih bugged ❌, hapus image

12. Update Template (siklus rebuild)#

Template pasca-sysprep tidak boleh di-boot, jadi update = rebuild:

  1. Copy template ke VM kerja baru: incus copy trim-vm-shr-tx-template-win2022 win2022-work --project Templates
  2. Boot win2022-work (dia akan lewat OOBE sekali), update/ubah sesuai kebutuhan
  3. Ulangi §8–§10 pada win2022-work
  4. Setelah test clone lulus: rename/tukar peran — win2022-work jadi template baru, template lama diarsip (publish ber-tanggal, setelah fix) atau dihapus (security.protection.delete=false dulu)

13. Troubleshooting#

GejalaPenyebabSolusi
Instance dari image publish: BdsDxe ... Not Found → PXE, Boot From File kosongBug publish qcow2-in-raw di lvmclusterJangan pakai publish sebelum fix #3705; deploy via copy (§11)
incus snapshot delete / incus delete (VM ber-snapshot): qemu-img commit -f qcow2 : Could not open ''Bug path resolution snapshot-delete lvmcluster; aktivasi LV manual TIDAK menolongSebelum fix: hapus record snapshot via incus admin sql (backup dump dulu!) + lvremove LV snapshot, lalu delete VM normal
Attach ISO: Storage volume not found (volume terlihat ada)(a) Volume di project lain — features.storage.volumes=true memisah namespace; (b) VM di node berbeda dari volume node-local(a) incus storage volume copy ... --target-project; (b) cek incus info <vm> | grep Location, samakan dengan lokasi volume
incus move --target: root disk size is smaller than the migration sourceLV rounding lvmcluster (66GiB vs 66.01g)VM kosong: delete + init ulang dengan --target; VM berisi: naikkan size root device dulu
Installer Windows: tidak ada disk & CD di Load driverWinPE tanpa driver vioscsi, semua device di virtio-scsi§6a — io.bus=usb untuk ISO virtio, atau repack distrobuilder
CD agent berisi file Linux (install.sh, systemd)image.os belum Windowsincus config set <vm> image.os=Windows + restart VM
Agent tidak konek (tidak ada IP di incus info)Driver viosock belum terpasang / jam guest jauh dari host / agent drive ter-detach§7b–7c; sinkronkan jam; pasang kembali device agent
Copy terasa hang, operation metadata kosongNormal — lvmcluster non-thin, block copy penuh; metadata memang tidak ada progressMonitor iostat -xm 2 di node source & target; JANGAN Ctrl+C
Clone boot ke login screen lama (bukan OOBE)Template sempat ter-boot setelah sysprep, atau sysprep tidak jalanRebuild template (§12)

14. Referensi#