Runbook Deployment — Incus Cluster + QNAP Shared Storage#

Trimegah Compute Shared — Panduan Eksekusi Berurutan

Ikuti urutan ini persis saat deploy node baru / rebuild. Setiap tahap punya gerbang verifikasi — jangan lanjut ke tahap berikutnya sebelum gerbang lolos.

Prasyarat baca dulu: dokumen referensi lengkap incus-cluster-documentation.md (arsitektur, IP mapping, FAQ, lessons learned). Runbook ini adalah versi “jalankan saja”, dokumen referensi adalah versi “pahami kenapa”.


TAHAP 1 — Storage Pool & LUN di QNAP#

  1. Storage Manager -> Storage Pool – pastikan pool sumber (HDD/SSD) tersedia dengan kapasitas cukup.
  2. iSCSI & Fibre Channel -> LUNs -> Create LUN:
    • Type: Block-Based LUN
    • Capacity: sesuai rencana (contoh: 31.5T), Thin provisioning
    • Storage Settings (Advanced):
      • Compression: ON
      • Deduplication: OFF (jangan pernah ON – RAM killer)
      • SSD read cache: OFF (kecuali ada SSD tier)
      • Fast clone: ON
      • Alert threshold: 80%
      • ZIL synchronized I/O mode: Auto
      • Performance profile (block size): 32K – Generic/VMware (bukan 64K Hyper-V, bukan 4K/8K kecuali khusus DB)

Gerbang: LUN tampil di daftar LUNs dengan status normal, belum di-map ke target manapun.


TAHAP 2 — iSCSI Target di QNAP#

  1. iSCSI & Fibre Channel -> iSCSI -> Create iSCSI Target:
    • Alias: Target-Computes (atau sesuai konvensi)
    • Allow clustered access to this target: CENTANG (wajib untuk multi-initiator/cluster)
    • CHAP: Enable, catat username/password ke password manager
    • CRC Checksums (data/header digest): OFF
  2. Map LUN dari Tahap 1 ke target ini.
  3. Edit Target -> Network Portal: bind hanya ke adapter storage (bukan semua interface).
  4. Edit Target -> Advanced/Access: pastikan multiple sessions diizinkan.

Gerbang: discovery dari satu node uji berhasil menampilkan target; LUN ter-map (cek di halaman LUNs, kolom mapping).


TAHAP 3 — QNAP High Availability Cluster (opsional, jika 2 NAS)#

Lewati tahap ini jika hanya 1 NAS. Jika akan dibentuk, lakukan SEBELUM node Incus mulai produksi – perubahan IP di tahap ini memutus sesi iSCSI yang sudah ada.

  1. Prasyarat kedua NAS:
    • Model & versi QuTS hero identik (h5.3.0+), versi HA Manager sama, total RAM sama
    • Hapus SnapSync job, LUN import/export job, immutable snapshot/schedule (tidak didukung HA)
    • 2-step verification admin passive node: disable
  2. Heartbeat interface (kedua NAS): pilih 1 adapter dedicated, DHCP, tanpa VLAN/virtual switch, tanpa trunking Balance-rr/alb/tlb (hanya Active-Backup jika di-bond; disarankan 1 kabel polos). Hasil sehat: IP link-local 169.254.x.x.
  3. Cluster connection interface (kedua NAS): bond ke switch (LAG terpisah per NAS), static IP, satu subnet, MTU jumbo bila jalur storage. Verifikasi: ping -M do -s 8972 antar IP fisik kedua NAS.
  4. Jalankan wizard HA Manager dari NAS yang akan jadi active:
    • Cluster connection -> pilih interface bond
    • Heartbeat connection -> pilih interface direct
    • Masukkan kredensial admin passive node
    • Cluster IP: gunakan IP portal iSCSI yang sudah dikenal node (floating) – agar node TIDAK perlu ubah konfigurasi apa pun setelah HA aktif
    • Konfirmasi: seluruh data passive node akan dihapus
  5. Tunggu status Good dan initial sync selesai (bisa berjam-jam – jadwalkan di luar jam sibuk).

Gerbang: Dashboard HA Manager status Good; cluster IP dapat di-ping; port iSCSI (3260) merespons di cluster IP.

Catatan: HA menghilangkan peran passive node sebagai backup independen (mirror != backup). Rantai backup (incus export dsb) tetap wajib terpisah.


TAHAP 4 — Install Incus + Web UI (per node)#

# Repo Zabbly
mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.zabbly.com/key.asc -o /etc/apt/keyrings/zabbly.asc
gpg --show-keys --fingerprint /etc/apt/keyrings/zabbly.asc
# verifikasi: 4EFC 5906 96CB 15B8 7C73 A3AD 82CC 8797 C838 DCFD

cat > /etc/apt/sources.list.d/zabbly-incus-stable.sources << 'EOF'
Enabled: yes
Types: deb
URIs: https://pkgs.zabbly.com/incus/stable
Suites: trixie
Components: main
Architectures: amd64
Signed-By: /etc/apt/keyrings/zabbly.asc
EOF

apt update && apt full-upgrade -y

apt install -y incus incus-extra incus-base incus-ui-canonical \
  open-iscsi lvm2-lockd sanlock multipath-tools \
  btrfs-progs thin-provisioning-tools \
  bridge-utils ifenslave sudo

usermod -aG incus-admin <user-admin>
usermod -aG sudo <user-admin>

Jaringan (ringkas – detail lengkap di dokumen referensi):

  • Management (eno1np0): static, MTU 1500
  • Trunk VM (br-vm di atas eno2np1): bridge-vlan-aware yes, bridge-vids 2-4094, MTU 1500 – host permisif, whitelist VLAN ada di switch
  • Storage (bond-storage): LACP 2 link, static IP sesuai IP Mapping resmi, MTU 9000
ping -M do -s 8972 -c3 <IP-QNAP>   # validasi jumbo sebelum lanjut

Web UI:

incus config set core.https_address=<IP-management-node-ini>:8443

Bind ke IP management node itu sendiri (contoh: 10.25.3.50:8443 untuk node-01), BUKAN wildcard 0.0.0.0 — binding wildcard membuat API/UI Incus ikut ter-expose di jaringan storage (bond-storage), yang seharusnya murni untuk iSCSI/lease traffic. Jalankan perintah ini secara LOKAL di tiap node (bukan via --target dari node lain), dan verifikasi dulu IP node itu sendiri (ip -4 addr show <mgmt-if>) sebelum set — kesalahan copy-paste IP node lain adalah penyebab umum error saat join (lihat Troubleshooting: “not covered by”).

Pengecualian sementara: jika sedang troubleshoot error Server address "X" is not covered by "Y" from "cluster.https_address" saat join, 0.0.0.0:8443 boleh dipakai sesaat untuk melewati masalah — tapi kembalikan ke IP management spesifik setelah node berhasil join dan cluster stabil.

Verifikasi: ss -tlnp | grep 8443 harus menunjukkan IP spesifik, bukan 0.0.0.0:8443.

Auth trust (hanya perlu di node pertama cluster — node berikutnya mewarisi trust store setelah join): buka https://<IP-node-01>:8443 -> Create certificate -> import .pfx ke browser -> incus config trust add-certificate <file>.crt di server -> quit browser total -> reload.

Gerbang: incus version menampilkan versi; UI dapat diakses dan login dengan certificate; ping -M do -s 8972 ke QNAP berhasil.


TAHAP 5 — Mounting LUN via iSCSI (per node)#

# Identitas initiator -- UNIK per node
echo "InitiatorName=iqn.2026-07.id.co.trimegah:incus-0X" > /etc/iscsi/initiatorname.iscsi

# CHAP + auto-login
cat >> /etc/iscsi/iscsid.conf << 'EOF'
node.session.auth.authmethod = CHAP
node.session.auth.username = <chap-user>
node.session.auth.password = <chap-pass>
node.startup = automatic
EOF

systemctl restart iscsid open-iscsi

iscsiadm -m discovery -t st -p <IP-QNAP-atau-cluster-IP>
iscsiadm -m node --login
lsblk    # LUN muncul (ukuran sesuai Tahap 1)
iscsiadm -m session -P1 | grep -E 'Portal|State'   # LOGGED_IN

Jika error 24 (auth gagal): update record secara eksplisit –

iscsiadm -m node -T <IQN-target> -o update -n node.session.auth.username -v <user>
iscsiadm -m node -T <IQN-target> -o update -n node.session.auth.password -v '<pass>'
iscsiadm -m node -T <IQN-target> -o update -n node.startup -v automatic
iscsiadm -m node --login

PENTING: pasang multipath (Tahap 6) SEBELUM LVM/lockd menyentuh device ini.

Gerbang: lsblk menampilkan device baru dengan ukuran LUN yang benar; iscsiadm -m session menunjukkan LOGGED_IN.


TAHAP 6 — Multipath (per node)#

Tujuan: nama device stabil (/dev/mapper/<alias>) tidak terpengaruh pergeseran nama /dev/sdX. Wajib jika dual-fabric; pilihan sadar jika single-fabric (lihat dokumen referensi untuk trade-off).

# identifikasi device LUN yang baru login (cocokkan ukuran dari lsblk):
ls -l /dev/disk/by-path/ | grep iscsi
lsblk

# ambil WWID -- HARUS SAMA di semua node untuk LUN yang sama
WWID=$(/lib/udev/scsi_id -g -u /dev/sdX)     # ganti sdX sesuai device LUN
echo "WWID = $WWID"

cat > /etc/multipath.conf << EOF
defaults {
    user_friendly_names yes
    find_multipaths strict
    polling_interval    5
    no_path_retry       queue
}
multipaths {
    multipath {
        wwid  $WWID
        alias qnap-hdd-01
    }
}
EOF
grep wwid /etc/multipath.conf   # pastikan terisi 36xxx..., BUKAN kosong/path string

systemctl enable --now multipathd
multipath -a $WWID
systemctl restart multipathd

multipath -ll                   # qnap-hdd-01 (36...) ... status=active ready
ls -l /dev/mapper/qnap-hdd-01   # symlink ke dm-X
lsblk                           # sdX kini punya child qnap-hdd-01

Gerbang: multipath -ll menampilkan alias dengan status active ready; /dev/mapper/qnap-hdd-01 ada. Untuk LUN kedua dst, tambah blok multipath {} baru dengan WWID & alias berbeda (qnap-ssd-01, dst) di file config yang sama.

Catatan: no_path_retry fail wajib – mode queue-selamanya bertabrakan buruk dengan mekanisme lease sanlock di Tahap 7.


TAHAP 7 — Buat Storage LVM Cluster di Incus (node PERTAMA saja)#

Hanya dijalankan sekali, dari node pertama yang membentuk cluster. Node berikutnya bergabung ke lockspace yang sudah ada (Tahap 8), bukan mengulang tahap ini.

7.1 – Aktifkan lock daemon#

sed -i 's/# use_lvmlockd = 0/use_lvmlockd = 1/' /etc/lvm/lvm.conf
sed -i 's/# scan_lvs = 0/scan_lvs = 1/' /etc/lvm/lvm.conf
lvmconfig global/use_lvmlockd    # WAJIB: use_lvmlockd=1

sed -i 's/# host_id = 0/host_id = 1/' /etc/lvm/lvmlocal.conf   # node pertama = 1

systemctl enable --now wdmd sanlock lvmlockd
systemctl status wdmd sanlock lvmlockd --no-pager | grep Active

7.2 – Buat shared VG di atas mapper (bukan /dev/sdX!)#

vgcreate --shared -v vg-qnap-hdd-01 /dev/mapper/qnap-hdd-01 2>&1 | grep -E 'sanlock|lvmlock|created'

WAJIB muncul: “Enabling sanlock global lock” + “Creating logical volume lvmlock”, proses memakan belasan detik. Instan & tanpa pesan tersebut = gagal diam-diam, ulangi (lihat Troubleshooting).

vgs -o+vg_locktype           # vg-qnap-hdd-01 | attr wz--ns | LockType: sanlock
vgchange --lockstart vg-qnap-hdd-01
lvmlockctl -i                # lockspace lvm_vg-qnap-hdd-01 dengan LK GL + LK VG

Gerbang: lvmlockctl -i menampilkan lockspace tanpa pesan error apapun (khususnya “storage errors for sanlock leases”).

7.3 – LV storage lokal (per node)#

LV LV_STORAGE_LOCAL_INCUS (contoh 300G) seharusnya sudah dibuat saat partitioning OS (Tahap 4). Bersihkan signature bila bekas percobaan:

wipefs -a /dev/<hostname>-vg/LV_STORAGE_LOCAL_INCUS

7.4 – Create storage pool di Incus (dari node ini saja)#

incus storage create pool-local lvm \
  source=/dev/<hostname-node-ini>-vg/LV_STORAGE_LOCAL_INCUS \
  --target <hostname-node-ini>

incus storage create pool-qnap-hdd-01 lvmcluster \
  source=vg-qnap-hdd-01 --target <hostname-node-ini>

incus storage create pool-local lvm
incus storage create pool-qnap-hdd-01 lvmcluster

incus profile device add default root disk path=/ pool=pool-local
incus storage list    # keduanya CREATED

Gerbang: incus storage list menampilkan kedua pool berstatus CREATED; vgs menunjukkan pool-local berukuran sesuai LV (jika kecil = source salah, lihat Troubleshooting).


TAHAP 8 — Join Cluster Incus (node kedua dan seterusnya)#

Lakukan Tahap 4-6 dulu di node baru (install, mount LUN, multipath) sebelum tahap ini.

8.1 – Generate token (dari node PERTAMA)#

incus cluster remove trim-computes-shr-incus-0X --force 2>/dev/null   # bersihkan sisa percobaan
incus cluster add trim-computes-shr-incus-0X
# -> salin token UTUH; token SEKALI PAKAI dan kedaluwarsa cepat

8.2 – Aktifkan lock daemon di node baru (BUKAN vgcreate!)#

sed -i 's/# use_lvmlockd = 0/use_lvmlockd = 1/' /etc/lvm/lvm.conf
sed -i 's/# scan_lvs = 0/scan_lvs = 1/' /etc/lvm/lvm.conf
sed -i 's/# host_id = 0/host_id = X/' /etc/lvm/lvmlocal.conf   # X unik per node!

systemctl enable --now wdmd sanlock lvmlockd
vgchange --lockstart vg-qnap-hdd-01     # VG sudah ada -- JANGAN vgcreate
lvmlockctl -i                            # lockspace ACTIVE tanpa error

Gerbang sebelum lanjut: lvmlockctl -i bersih. Jika “storage errors for sanlock leases” muncul, JANGAN lanjut join – cek bond/MTU/multipath dulu.

8.3 – Join via preseed (bukan wizard interaktif)#

Wizard interaktif incus admin init rawan salah-tafsir key source di setup ini. Gunakan preseed.

cat > /root/join.yaml << 'EOF'
cluster:
  enabled: true
  server_address: <IP-management-node-baru>:8443
  cluster_token: PASTE_TOKEN_DISINI
  member_config:
  - entity: storage-pool
    name: pool-local
    key: source
    value: /dev/<hostname-node-baru>-vg/LV_STORAGE_LOCAL_INCUS
  - entity: storage-pool
    name: pool-qnap-hdd-01
    key: source
    value: vg-qnap-hdd-01
EOF

sed -i "s|cluster_token:.*|cluster_token: <token-dari-8.1>|" /root/join.yaml
cat /root/join.yaml | incus admin init --preseed

Gerbang: perintah selesai tanpa error. Jika “No matching cluster join operation found” -> token sudah hangus, ulangi 8.1 dan 8.3 dalam satu tarikan.

8.4 – Validasi#

incus cluster list        # kedua node ONLINE, "Fully operational"
incus storage list        # kedua pool CREATED di kedua member
vgs -o+vg_locktype         # vg-qnap-hdd-01 sanlock, terbaca di node baru

Gerbang akhir Tahap 8: dua baris ONLINE di incus cluster list.


TAHAP 9 — Uji Fungsional Shared Storage#

incus launch images:debian/13/cloud ct-join-test -s pool-qnap-hdd-01 \
  -p default --target trim-computes-shr-incus-0X
incus list    # LOCATION = node baru

incus stop ct-join-test
incus move ct-join-test --target trim-computes-shr-incus-01
incus start ct-join-test
incus list    # LOCATION berpindah dalam hitungan detik

Untuk VM (live migration sambil running):

incus launch images:debian/13/cloud vm-lm-test --vm -s pool-qnap-hdd-01 \
  -p default --target trim-computes-shr-incus-01
incus move vm-lm-test --target trim-computes-shr-incus-0X
incus list    # LOCATION berpindah, STATE tetap RUNNING

Gerbang: relocate/migration berhasil tanpa error, data instance utuh setelah pindah.


TAHAP 10 — Boot-Order Persistence (per node)#

cat > /etc/systemd/system/lvmlockstart.service << 'EOF'
[Unit]
Description=Start LVM lockspaces
After=lvmlockd.service sanlock.service iscsi.service multipathd.service
Requires=lvmlockd.service sanlock.service

[Service]
Type=oneshot
ExecStart=/usr/sbin/vgchange --lockstart
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

mkdir -p /etc/systemd/system/incus.service.d
cat > /etc/systemd/system/incus.service.d/deps.conf << 'EOF'
[Unit]
After=lvmlockstart.service
Requires=lvmlockstart.service
EOF

systemctl daemon-reload
systemctl enable lvmlockstart

Gerbang: reboot terjadwal satu kali; setelah boot, iscsiadm -m session -> multipath -ll -> lvmlockctl -i -> incus list semua sehat tanpa intervensi manual.


Prosedur Pemulihan — Restart Bersih Lock Stack (sanlock/lvmlockd/wdmd)#

Gunakan prosedur ini saat muncul error seperti “storage errors for sanlock leases”, “VG lock skipped”, “invalid lockspace found”, atau saat operasi LVM/Incus ke pool shared gagal padahal jalur fisik (bond, MTU, iSCSI session) sudah dikonfirmasi sehat. Ini BUKAN indikasi data rusak — sanlock/lvmlockd sengaja menolak operasi (fail loud) daripada membiarkan dua node menulis bersamaan ke volume yang sama (fail silent, yang justru berbahaya).

Tiga service dan urutannya (wajib berurutan dengan jeda, tidak boleh start bersamaan):

ServicePeranKenapa urutannya begitu
wdmdWatchdog Multiplexing Daemon — akses ke /dev/watchdog0, eksekusi fencing (reset paksa node) bila lease tidak ter-renew tepat waktuHarus hidup PALING DULU — sanlock butuh daftar ke wdmd
sanlockLease manager — baca/tulis lease ke LUN, tentukan node mana yang berhak aksesButuh wdmd sudah siap untuk registrasi watchdog
lvmlockdJembatan antara perintah LVM (vgs/lvcreate/dll) dengan sanlockButuh sanlock sudah siap untuk diajak komunikasi

Rantai: wdmd → sanlock → lvmlockd → vgchange --lockstart → incus/lvcreate/vgs. Start/stop tanpa jeda antar layer adalah penyebab paling umum lockspace tidak sinkron (“invalid lockspace found” di journalctl sanlock, padahal lvmlockctl -i di lvmlockd terlihat normal — dua daemon tidak sepakat soal state).

Langkah 0 — Diagnosa dulu, JANGAN langsung restart (semua perintah di bawah read-only, aman dijalankan kapan saja)#

lvmlockctl -i                          # lihat lockspace + status
sanlock client status | grep lvm_vg    # cek dari sisi sanlock, harus SEPAKAT dengan lvmlockd
vgs -o+vg_locktype                     # cek ada baris "Skipping global lock" atau tidak

Tentukan tingkat keparahan sebelum bertindak:

Gejala dari Langkah 0ArtinyaTindakan
lvmlockctl -i normal, sanlock client status juga normal, vgs sesekali lambat/timeoutKemungkinan transientUlangi setelah beberapa detik sebelum menyentuh service apa pun
lvmlockctl -i menampilkan lockspace tapi sanlock client status kosong/tidak matchDua daemon tidak sepakat soal stateLanjut ke Langkah 1 (cek fisik) lalu Langkah 2 (restart bersih)
Ada teks eksplisit “storage errors for sanlock leases” / “invalid lockspace found” / lock_san acquire error -28Confirmed bermasalah, sering dipicu gangguan I/O ke LUNWajib cek fisik (Langkah 1) dulu sebelum restart — restart tanpa membenahi fisik akan berulang

Langkah 1 — Cek jalur fisik SEBELUM restart service apa pun#

Lock stack menolak beroperasi (fail loud) bila tidak yakin bisa membaca/menulis lease dengan andal — akar masalah paling sering ada di jalur di bawahnya, bukan di daemon itu sendiri:

ping -M do -s 8972 -c3 <IP-QNAP>
cat /proc/net/bonding/bond-storage | grep -E 'MII Status|Partner Mac'
multipath -ll    # bila memakai multipath: semua alias harus active ready

Bila ada yang tidak sehat di sini, perbaiki jalur fisiknya terlebih dahulu — restart lock stack tanpa membenahi fisik hanya menyembuhkan gejala sesaat dan akan error lagi.

Langkah eksekusi (restart bersih — setelah Langkah 0 dan 1 dicek)#

# 1. Matikan urut, DENGAN JEDA
systemctl stop lvmlockd
sleep 2
systemctl stop sanlock wdmd
sleep 2

# 2. Pastikan bersih — tidak ada proses/mapping nyangkut
ps aux | grep -E 'sanlock|lvmlockd' | grep -v grep
dmsetup ls | grep lvmlock
# Jika ada mapping vg--<nama>-lvmlock yang nyangkut & Open count 0:
#   dmsetup remove vg--<nama>-lvmlock

# 3. Nyalakan urut, DENGAN JEDA
systemctl start wdmd
sleep 2
systemctl start sanlock
sleep 2
systemctl start lvmlockd
sleep 3

# 4. Lockstart, beri waktu (bisa sampai beberapa menit, jangan buru-buru cek)
vgchange --lockstart vg-qnap-hdd-01
sleep 15
lvmlockctl -i
sanlock client status | grep lvm_vg
vgs -o+vg_locktype    # HARUS TANPA baris "Skipping global lock"

Bila ada instance produksi berjalan di pool shared saat kejadian ini terjadi: incus stop <instance> dulu sebelum menyentuh service lock stack di atas — restart lock stack berpotensi membuat I/O instance yang sedang menulis ke volume shared gagal sesaat.

Verifikasi dua daemon sepakat (sering terlewat — lvmlockctl -i bisa terlihat normal padahal sanlock sendiri tidak punya catatan lockspace tersebut):

sanlock client status
# harus muncul baris: s lvm_vg-qnap-hdd-01:<host_id>:/dev/mapper/vg--<nama>-lvmlock:0

Jika terjadi berulang — cek node lain juga#

Karena semua node berbagi satu lockspace yang sama di LUN yang sama, restart lock stack di SATU node (misal saat setup multipath/LUN baru) dapat membuat lockspace global (LK GL) terganggu di node lain yang sedang aktif menggunakannya. Bila error muncul kembali dalam waktu singkat setelah dipulihkan, cek SEMUA node lain sebelum mengulang prosedur di atas:

# di setiap node lain:
lvmlockctl -i
sanlock client status | grep lvm_vg
systemctl status sanlock lvmlockd --no-pager | grep -E 'Active|since'
# perhatikan timestamp "since" — service yang baru saja restart di node lain
# adalah kandidat kuat pemicu gangguan lockspace di node ini
journalctl -u wdmd --since -30min --no-pager | grep -iE 'error|warn|closed|reopen'

Jika ditemukan node lain dengan gejala serupa (lockspace tidak sinkron), lakukan prosedur restart bersih di SEMUA node yang bermasalah — bukan hanya satu — sebelum mencoba operasi storage lagi.

Aturan “JANGAN” — wajib dipegang selama pemulihan#

  1. Jangan matikan fencing/watchdog untuk “menghindari” masalah. Fencing (reset paksa node oleh wdmd/sanlock) adalah proteksi anti-korupsi data, bukan bug yang harus dihilangkan — lihat dokumen referensi bagian perilaku kegagalan storage.
  2. Jangan gunakan vgremove --config 'global/use_lvmlockd=0' kecuali benar-benar yakin VG tersebut kosong/bekas percobaan gagal. Perintah ini membypass proteksi lock sepenuhnya — salah sasaran (misal menimpa VG produksi) berakibat fatal.
  3. Jangan restart wdmd/sanlock/lvmlockd/multipathd di jam produksi tanpa rencana — lihat aturan operasional di bawah.

Aturan operasional untuk mencegah kejadian berulang#

  • Jangan restart wdmd/sanlock/lvmlockd/multipathd di jam produksi tanpa rencana. Bila perlu (menambah LUN, upgrade, dll), jadwalkan maintenance window: hentikan instance kritis di pool shared dulu, baru lakukan perubahan.
  • Perubahan pada satu node yang menyentuh lock stack berpotensi memengaruhi seluruh cluster yang berbagi VG shared yang sama — bukan hanya lokal ke node tersebut.
  • Pertimbangkan healthcheck berkala (masuk ke monitoring existing, misal Uptime Kuma) untuk mendeteksi lockspace bermasalah sebelum mengganggu deployment:
    lvmlockctl -i | grep -qi "invalid\|error" && echo "ALERT: lockspace vg-qnap-hdd-01 bermasalah di $(hostname)"

TAHAP 11 — Ulangi untuk Node Berikutnya#

Untuk node ketiga dan seterusnya, ulangi Tahap 4 -> 5 -> 6 -> 8 -> 9 -> 10 (lewati Tahap 7 – pool sudah ada). Tahap 1-3 (QNAP) hanya sekali di awal kecuali menambah LUN baru (ulangi Tahap 1-2 untuk LUN tambahan, tambahkan device baru di /etc/multipath.conf semua node, buat VG shared baru dengan nama berbeda misal vg-qnap-ssd-01).


TAHAP 12 — Reverse Proxy (Nginx Proxy Manager) + SSO via Authentik (OIDC)#

Tujuan: akses web UI cluster lewat satu domain (https://incus-cl01.t1.trimegah.cloud/) dengan load balancing ke 4 node, dan login personal (bukan client certificate bersama) via Authentik SSO.

12.1 — Dua metode auth Incus, dua kebutuhan proxy yang berbeda#

Metode authCara kerjaKebutuhan reverse proxy
Client certificate (mTLS) — defaultBrowser & Incus melakukan TLS handshake langsung, cert diverifikasi di lapisan ituTLS tidak boleh di-terminate di proxy — wajib mode stream (TCP passthrough) di nginx, atau proxy tidak dipakai sama sekali
OIDC (Authentik) — direkomendasikan untuk banyak adminBrowser redirect standar (Authorization Code + PKCE), bukan mTLSReverse proxy HTTP normal bisa dipakai — TLS boleh di-terminate di nginx

Dokumen ini menggunakan jalur OIDC — reverse proxy HTTP standar, bukan stream/passthrough.

12.2 — Upstream 4 node di Nginx Proxy Manager (NPM)#

PENTING — konvensi nama file NPM: folder data/nginx/custom/ NPM hanya meng-include file dengan nama TETAP: root_top.conf, events.conf, http_top.conf, http.conf, stream.conf, root.conf. File dengan nama lain (termasuk <domain>.conf) TIDAK PERNAH DIBACA meskipun nginx -t menyatakan syntax valid — karena file tersebut memang tidak pernah di-parse. Verifikasi selalu dengan nginx -T | grep <domain> untuk memastikan config benar-benar termuat, jangan hanya percaya nginx -t.

Definisikan upstream (boleh di file terpisah yang statis namanya sesuai konvensi di atas, contoh server_backend.conf sudah lazim dipakai untuk keperluan lain di instalasi ini — tempatkan definisi upstream di http.conf yang sama dengan server block untuk kesederhanaan):

cat > /opt/proxymanager/data/nginx/custom/http.conf << 'EOF'
upstream app_incus {
    hash $remote_addr consistent;
    server 10.25.3.50:8443  max_fails=3 fail_timeout=30s;
    server 10.25.3.51:8443  max_fails=3 fail_timeout=30s;
    server 10.25.3.52:8443  max_fails=3 fail_timeout=30s;
    server 10.25.3.53:8443  backup;
}

server {
    listen 443 ssl;
    http2 on;
    server_name incus-cl01.t1.trimegah.cloud;

    ssl_certificate     /etc/letsencrypt/live/<id-cert-wildcard>/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<id-cert-wildcard>/privkey.pem;

    location / {
        proxy_pass https://app_incus;
        proxy_ssl_verify off;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_read_timeout 600s;
    }
}
EOF

Kenapa hash $remote_addr consistent, bukan least_conn: flow OIDC bersifat multi-step (redirect ke Authentik, lalu callback kembali ke Incus). Bila load balancer mengarahkan request awal dan request callback ke node berbeda, validasi state/session cookie bisa gagal (securecookie: the value is not valid) karena setiap node menangani session secara independen. hash $remote_addr consistent menjaga satu client cenderung konsisten ke node yang sama sepanjang flow.

Wajib: cari container NPM dengan docker ps — nama container belum tentu proxymanager, sering <project>-app-1 (contoh: proxymanager-app-1). Gunakan nama yang benar untuk semua perintah docker exec/docker restart, atau perintah akan gagal/ke-Ctrl+C tanpa efek apa pun tanpa keliatan errornya.

docker ps | grep -i proxy    # cari nama container yang benar
docker exec <nama-container> nginx -t
docker restart <nama-container>
sleep 5
docker exec <nama-container> nginx -T 2>/dev/null | grep -A20 "incus-cl01"   # WAJIB muncul!

Gerbang: nginx -T | grep <domain> menampilkan server block lengkap (bukan kosong); openssl s_client -connect 127.0.0.1:443 -servername <domain> </dev/null 2>&1 | grep subject menampilkan CN cert yang benar (bukan error alert unrecognized name — error itu artinya SNI domain belum dikenali nginx, biasanya karena file config belum ter-include, lihat catatan konvensi nama file di atas).

Firewall 4 node: pastikan 8443 di-allow dari IP server NPM (update nftables bila diperlukan).

12.3 — Setup Authentik sebagai Identity Provider#

Jalankan Authentik (disarankan sebagai VM terpisah, bukan container — Docker Compose di dalam LXC rawan isu nesting/cgroup). Ringkasan instalasi resmi (Docker Compose):

mkdir -p /opt/authentik && cd /opt/authentik
wget https://goauthentik.io/docker-compose.yml
echo "PG_PASS=$(openssl rand -base64 36 | tr -d '\n')" >> .env
echo "AUTHENTIK_SECRET_KEY=$(openssl rand -base64 60 | tr -d '\n')" >> .env
echo "AUTHENTIK_TAG=2025.12" >> .env    # pin versi, jangan pakai :latest
docker compose pull
docker compose up -d

Buka http://<IP>:9000/if/flow/initial-setup/ (trailing slash wajib) untuk membuat akun akadmin.

Buat Provider (Applications → Providers → Create → OAuth2/OpenID Provider):

  • Client Type: Public — WAJIB. Incus menggunakan Authorization Code + PKCE tanpa client secret. Bila provider terlanjur dibuat sebagai Confidential, ganti field Client Type ke Public langsung di provider yang sama (field ini ternyata dapat diedit, tidak perlu membuat ulang provider).
  • Redirect URI: https://incus-cl01.t1.trimegah.cloud/oidc/callback — harus persis (skema, host, path, tanpa/dengan trailing slash harus sama persis dengan yang akan dikirim Incus).
  • Grant Types: minimal Authorization Code harus tercentang (wajib). Refresh token disarankan tetap dicentang. Grant types lain (Implicit, Hybrid, Client credentials, Password) dapat di-uncheck sebagai hardening — tidak dipakai oleh Incus dan bukan penyebab error bila dibiarkan tercentang, jadi tidak prioritas untuk diubah di awal.
  • Catat Client ID yang dihasilkan.

Buat Application (Applications → Applications → Create):

  • Slug menentukan path issuer URL: https://<domain-authentik>/application/o/<slug>/. Catat slug persis — ini yang paling sering salah tebak (default slug bisa panjang/otomatis, contoh: incus-bitera-cluster-01, bukan sekadar incus).
  • Bind ke Provider yang baru dibuat.

Verifikasi issuer sebelum konfigurasi Incus:

curl -s https://<domain-authentik>/application/o/<slug>/.well-known/openid-configuration | python3 -m json.tool

Harus mengembalikan JSON (authorization_endpoint, token_endpoint, dll). Bila 404, slug di URL tidak sesuai — cek ulang field Slug di Application, bukan nama Provider.

12.4 — Konfigurasi OIDC di Incus (cluster-wide, jalankan sekali)#

incus config set oidc.issuer=https://<domain-authentik>/application/o/<slug>/
incus config set oidc.client.id=<client-id-dari-authentik>

Tidak ada oidc.client.secret — ini bukan kelalaian, Incus memang tidak menggunakannya (Public client + PKCE, lihat 12.3).

Gerbang: buka https://incus-cl01.t1.trimegah.cloud/ di jendela incognito (hindari cache cookie/cert dari percobaan sebelumnya) → halaman login menampilkan tombol “Login with SSO” → klik → redirect ke Authentik → login → kembali ke Incus UI dengan identitas personal (bukan lagi client certificate bersama).

Catatan: CLI (incus command) dan komunikasi antar-node cluster tetap menggunakan client certificate seperti biasa — OIDC hanya berlaku untuk jalur web UI/browser. Trust store certificate existing tidak perlu dicabut.


TAHAP 13 — Prosedur Penambahan LUN Baru (di Cluster yang Sudah Produksi)#

Berlaku saat menambah LUN kedua/berikutnya (misal tier SSD) ke cluster yang sudah punya instance berjalan di LUN existing. Berbeda dari Tahap 1-7 (LUN pertama, cluster masih kosong) — di sini ada instance produksi yang harus tetap sehat selama proses.

13.1 — Perlu maintenance window?#

Secara teknis, sebagian besar langkah non-disruptive (pembuatan LUN di QNAP, rescan iSCSI, penambahan VG baru — lockspace baru tidak mengganggu lockspace existing karena sanlock mendukung banyak lockspace independen). Namun tetap jadwalkan maintenance window ringan (jam traffic rendah, tim standby, notifikasi) — bukan karena langkahnya pasti gagal, tapi karena satu langkah di prosedur ini (systemctl restart multipathd bila diperlukan) berpotensi mengganggu LUN existing yang sedang produksi, sesuai yang pernah terjadi saat penambahan tier SSD (lihat Prosedur Pemulihan Lock Stack).

Checklist sebelum mulai:

# di SEMUA node, catat baseline SEBELUM mulai — untuk pembanding setelah selesai:
lvmlockctl -i
multipath -ll
incus cluster list

13.2 — Buat LUN & target di QNAP (non-disruptive)#

Sama seperti Tahap 1-2, LUN baru di-map ke target iSCSI yang sudah ada (tidak perlu target baru) — perhatikan block size sesuai jenis media (contoh: SSD tier bisa memakai profil block size lebih kecil, 16K, sesuai kebutuhan workload).

13.3 — Rescan di setiap node (aman, tanpa logout/login)#

iscsiadm -m session --rescan
lsblk    # LUN baru muncul, misal /dev/sdc

13.4 — Tambahkan ke multipath — TANPA restart penuh bila memungkinkan#

ls -l /dev/disk/by-path/ | grep iscsi
WWID=$(/lib/udev/scsi_id -g -u /dev/sdc)   # sesuaikan device
echo "WWID = $WWID"

Sebelum edit — konfirmasi WWID HDD existing, JANGAN sampai berubah/salah ketik:

grep -A3 "alias.*qnap-hdd-01" /etc/multipath.conf

Catat nilai wwid yang tampil — nilai ini harus persis sama di config baru, tidak boleh diketik ulang dari ingatan/tebakan.

Tambahkan blok BARU ke /etc/multipath.conf yang sudah ada (jangan timpa blok LUN lama):

PENTING — syntax: setiap parameter (wwid, alias, no_path_retry) WAJIB di baris terpisah. Menggabungkan beberapa parameter dalam satu baris (misal alias qnap-hdd-01 no_path_retry fail) membuat parser multipath gagal membaca konfigurasi dengan benar.

defaults {
    user_friendly_names yes
    find_multipaths strict
}
multipaths {
    multipath {
        wwid            <wwid-lama-hdd — SAMA PERSIS dengan hasil konfirmasi di atas>
        alias           qnap-hdd-01
        no_path_retry   fail
    }
    multipath {
        wwid            <wwid-baru-ssd>
        alias           qnap-ssd-01
        no_path_retry   fail
    }
}

Validasi syntax SEBELUM apply:

multipath -t 2>&1 | grep -A5 "qnap-hdd-01\|qnap-ssd-01"    # dump config, pastikan dua-duanya terbaca benar

Apply tanpa mengganggu map existing — coba live-reconfigure dulu:

multipath -a $WWID
multipathd reconfigure    # reload live, BUKAN restart daemon
multipath -ll             # WAJIB: qnap-hdd-01 (LAMA) tetap active ready, DAN qnap-ssd-01 (BARU) active ready

Gerbang paling penting — cek yang LAMA dulu, bukan cuma yang baru: bila qnap-hdd-01 ikut berubah status (faulty, hilang dari daftar, dsb) setelah multipathd reconfigure, STOP — jangan lanjut ke pembuatan VG SSD sampai HDD kembali sehat (multipath -ll dan lvmlockctl -i normal). Menjalankan langkah berikutnya di atas HDD yang sedang tidak stabil berisiko pada instance produksi yang memakainya.

Bila reconfigure tidak tersedia/gagal dan terpaksa systemctl restart multipathd — ini titik yang wajib didahului stop instance produksi di pool shared existing:

incus stop <instance-produksi-di-pool-shared>
systemctl restart multipathd
sleep 5
multipath -ll             # verifikasi KEDUANYA sehat sebelum lanjut
lvmlockctl -i              # lockspace existing HARUS tetap bersih
incus start <instance-produksi>

Gerbang: kedua alias multipath (lama dan baru) berstatus active ready; lvmlockctl -i pada lockspace existing tidak menunjukkan error apa pun dibanding baseline 13.1.

13.5 — Buat shared VG baru (dari SATU node)#

Lockspace baru tidak mengganggu lockspace existing — sanlock mendukung banyak lockspace independen secara bersamaan.

vgcreate --shared -v vg-qnap-ssd-01 /dev/mapper/qnap-ssd-01 2>&1 | grep -E 'sanlock|lvmlock|created'
# WAJIB muncul "Enabling sanlock global lock" + "Creating logical volume lvmlock"

vgs -o+vg_locktype              # vg-qnap-ssd-01 | wz--ns | sanlock
vgchange --lockstart vg-qnap-ssd-01
lvmlockctl -i                    # SEKARANG ADA DUA lockspace — verifikasi DUA-DUANYA sehat

Node lain — cukup gabung lockspace, JANGAN vgcreate lagi:

vgchange --lockstart vg-qnap-ssd-01
lvmlockctl -i

Catatan penting — host_id TIDAK PERLU diubah: host_id adalah identitas per-node, bukan per-VG/per-LUN. Satu node memakai host_id yang sama untuk semua lockspace yang ia ikuti (node-01 tetap host_id=1 baik di vg-qnap-hdd-01 maupun vg-qnap-ssd-01). Yang wajib unik adalah host_id antar-node (node-01≠node-02≠dst), bukan antar-VG. Jangan sentuh /etc/lvm/lvmlocal.conf sama sekali pada prosedur ini. Verifikasi normal setelah VG baru ditambahkan menunjukkan dua baris dengan host_id sama di node yang sama:

sanlock client status | grep lvm_vg
# s lvm_vg-qnap-hdd-01:1:/dev/mapper/vg--qnap--hdd--01-lvmlock:0
# s lvm_vg-qnap-ssd-01:1:/dev/mapper/vg--qnap--ssd--01-lvmlock:0    <- host_id 1 sama, ini BENAR

13.6 — Buat storage pool di Incus (dari satu node, target ke semua member yang sudah join)#

incus storage create pool-qnap-ssd-01 lvmcluster source=vg-qnap-ssd-01 --target trim-computes-shr-incus-01
incus storage create pool-qnap-ssd-01 lvmcluster source=vg-qnap-ssd-01 --target trim-computes-shr-incus-02
incus storage create pool-qnap-ssd-01 lvmcluster source=vg-qnap-ssd-01 --target trim-computes-shr-incus-03
incus storage create pool-qnap-ssd-01 lvmcluster source=vg-qnap-ssd-01 --target trim-computes-shr-incus-04
incus storage create pool-qnap-ssd-01 lvmcluster
incus storage list    # pool baru CREATED, pool lama TETAP CREATED

13.7 — Update boot-order unit (Tahap 10) bila perlu#

lvmlockstart.service yang sudah ada (ExecStart=/usr/sbin/vgchange --lockstart, tanpa nama VG) sudah otomatis melakukan lockstart untuk semua VG shared yang terdaftar sistem — tidak perlu diedit untuk menambahkan VG baru.

13.8 — Validasi akhir#

# di SEMUA node, bandingkan dengan baseline 13.1:
lvmlockctl -i          # dua lockspace, keduanya bersih
multipath -ll           # dua alias, keduanya active ready
incus cluster list      # semua tetap ONLINE
incus list              # instance produksi existing tetap RUNNING tanpa gangguan

# uji fungsional pool baru:
incus launch images:debian/13/cloud ct-ssd-test -s pool-qnap-ssd-01 -p default
incus list
incus delete ct-ssd-test --force

Gerbang akhir: tidak ada perbedaan status pada lockspace/instance existing dibanding baseline sebelum prosedur dimulai; pool baru berfungsi normal untuk instance uji.


TAHAP 14 — Struktur Project (Split by Category) & Template VM Rocky Linux 9#

14.1 — Struktur project per environment#

Project dipisah per environment agar image, profile, network, dan storage bisa diisolasi tanpa perlu cluster/server terpisah:

incus project create Staging --config features.images=false --config features.networks=false
incus project create Production --config features.images=false --config features.networks=false

features.images=false dan features.networks=false membuat project baru berbagi image cache dan definisi network dari project default — jadi image yang sudah di-import/publish di default (termasuk template custom seperti Tahap 14.3) langsung terlihat di semua project, tidak perlu re-import per environment.

Gotcha yang WAJIB dicek setiap kali membuat project baru: project baru dengan features.profiles=true (default) memiliki profile default yang kosong — tidak otomatis mewarisi root disk device dari profile default milik project default. Tanpa ini, instance apa pun gagal dibuat dengan error Failed getting root disk: No root device could be found.

# WAJIB dijalankan setiap membuat project baru, SEBELUM launch instance pertama:
incus profile device add default root disk path=/ pool=pool-qnap-hdd-01 --project Staging
incus profile device add default root disk path=/ pool=pool-qnap-hdd-01 --project Production

Penggunaan:

incus launch <image> <nama> -p default -p net-vlan502-share --project Staging
incus list --project Staging

14.2 — Konvensi penamaan profile cloud-init#

Profile cloud-init per jenis OS diberi nama eksplisit, contoh: trim-cloudinit-rockylinux (menggantikan nama lama trim-vm-tx-shr-cloud-init-based yang kurang deskriptif). Profile ini menyimpan cloud-init.user-data berisi definisi user standar:

  • Tiga user service: super, ansible, trim-pam — masing-masing dengan SSH key dan password hash yescrypt, akses sudo
  • Paket dasar (tanpa qemu-guest-agent — Incus tidak menggunakan QEMU guest agent, ia punya incus-agent sendiri; menyertakan qemu-guest-agent tidak berguna dan membingungkan saat troubleshooting)

Catatan penting soal update hash/config di profile: incus profile copy adalah snapshot satu kali, BUKAN link/sync berkelanjutan. Mengubah cloud-init.user-data di profile default project TIDAK otomatis merambat ke salinan profile yang sudah di-copy ke project lain. Selalu verifikasi dan update eksplisit di tiap project:

incus profile get <nama-profile> cloud-init.user-data --project <environment> | grep passwd
# bandingkan dengan sumber yang benar; bila beda:
incus profile set <nama-profile> cloud-init.user-data="$(cat rocky-userdata.yaml)" --project <environment>

14.3 — Template VM Rocky Linux 9: masalah cloud-init & workaround#

Status: known issue, belum terselesaikan sepenuhnya di root cause-nya — didokumentasikan agar tidak perlu didiagnosis ulang dari nol.

Gejala: VM Rocky Linux 9 (image GenericCloud qcow2) yang di-launch tidak menjalankan cloud-init sama sekali — bukan gagal sebagian, tapi tidak berjalan sama sekali. Ciri-ciri yang mengonfirmasi:

  • Boot log tidak menampilkan satu pun baris cloud-init init/cloud-config/cloud-final
  • Login prompt menampilkan localhost login: — hostname tidak pernah ter-set
  • Kolom IPv4 kosong di incus list — konfigurasi network dari cloud-init tidak pernah diproses
  • User (super, dll) tidak ter-create kecuali sudah “baked-in” langsung di image

Root cause (rantai kegagalan): Rocky Linux 9 tidak menyertakan modul kernel 9p → Incus fallback ke 9p saat virtiofsd tidak berhasil di-spawn untuk VM tersebut → incus-agent tidak bisa terinstal dari config drive → socket /dev/incus/sock tidak pernah muncul di guest → ds-identify (cloud-init) tidak menemukan datasource apa pun → seluruh modul cloud-init di-skip diam-diam. Kondisi ini tetap terjadi meski binary virtiofsd tersedia di host (/opt/incus/bin/virtiofsd dari Zabbly maupun /usr/libexec/virtiofsd dari apt) — virtiofsd memang tidak ter-spawn oleh Incus untuk VM ini (share tag config tidak muncul di guest). Root cause pastinya belum ditemukan — ini bukan kesalahan konfigurasi yang jelas, melainkan kombinasi Incus + Rocky 9 kernel yang belum kompatibel sepenuhnya di virtiofs.

Workaround yang berhasil — kustomisasi image offline dengan virt-customize (bake-in sebelum import), BUKAN mengandalkan cloud-init saat runtime:

virt-customize -a rocky-9-generic-cloud.qcow2 \
  --selinux-relabel \
  --run-command 'useradd -m -G wheel super' \
  --ssh-inject super:file:/path/to/super.pub \
  --password 'super:password:<yescrypt-hash>' \
  --run-command 'echo "super ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/super' \
  # ulangi pola serupa untuk user ansible dan trim-pam
  --run-command 'timedatectl set-timezone Asia/Jakarta' \
  --install <paket-tambahan-tanpa-qemu-guest-agent>

incus image import rocky-9-generic-cloud.qcow2 --alias rocky9-baked

Alternatif — perbaiki template yang sudah terlanjur dipublish tanpa cloud-init clean: bila template dipublish dari VM yang sempat boot dan menjalankan cloud-init sebelumnya, user seperti super sudah ada di dalam image dengan password/state LAMA. Cloud-init tidak menimpa password user yang sudah ada (module users hanya mengeset password saat membuat user baru) — jadi mengubah hash di profile tidak berpengaruh pada VM baru dari template lama:

# via console (tanpa perlu agent/network):
incus console <nama-vm>
# manual masuk, install agent dari config drive bila memungkinkan:
sudo mkdir -p /run/incus_agent
sudo mount -t 9p config /run/incus_agent
# jika gagal, coba: sudo mount -t 9p -o trans=virtio,access=0 config /run/incus_agent
cd /run/incus_agent && sudo ./install.sh
sudo reboot

# verifikasi agent aktif dari host:
incus exec <nama-vm> -- echo ok

# WAJIB sebelum publish ulang — bersihkan state cloud-init lama:
incus exec <nama-vm> -- cloud-init clean --logs --machine-id
incus stop <nama-vm>
incus publish <nama-vm> --alias trim-vm-tx-shr-template-rocky9-v2 --project default

Bila VM tidak bisa login sama sekali (tidak ada user valid, agent tidak jalan) — masuk lewat GRUB rescue:

incus console <nama-vm> --project <environment>
# di terminal lain, restart VM-nya:
incus restart <nama-vm> --project <environment>
# saat GRUB muncul (cepat), tekan 'e' pada entry pertama, tambahkan di akhir baris "linux ...":
#   rd.break
# lalu Ctrl+X untuk boot dengan parameter tersebut

Checklist sebelum publish template Rocky Linux 9 baru:

[ ] VM sumber sudah di-cloud-init clean --logs --machine-id (hindari state/password lama ikut ter-bake)
[ ] incus-agent terinstal dan terverifikasi jalan (incus exec ... -- echo ok berhasil)
[ ] Hostname, user, network sesuai yang diharapkan sebelum di-stop
[ ] Publish dengan alias versi baru (v2, v3, dst) — jangan menimpa alias lama agar rollback mudah

TAHAP 15 — Operasional Deploy VM: Launch, Tambah Disk, Tambah Network#

15.1 — Launch VM dari template/image#

incus launch <alias-template-atau-image> <nama-vm> --vm \
  -s pool-qnap-hdd-01 -p default -p net-vlan502-share \
  --project <environment>

# contoh dari template custom (Tahap 14.3):
incus launch trim-vm-tx-shr-template-rocky9-v2 my-vm --vm \
  -s pool-qnap-hdd-01 -p default -p net-vlan526-database \
  --project Production

Untuk static IP di VM (nama interface guest ≠ nama device — wajib match: macaddress, lihat dokumen referensi §2.9):

MAC=$(incus config get my-vm volatile.eth526.hwaddr --project Production)
incus config set my-vm cloud-init.network-config="
version: 2
ethernets:
  nic0:
    match: {macaddress: '$MAC'}
    addresses: [10.25.111.x/24]
    gateway4: 10.25.111.1
    nameservers: {addresses: [<DNS>]}
" --project Production
incus restart my-vm --project Production

15.2 — Menambah disk tambahan ke VM (running, tanpa stop)#

Berbeda dari container — VM butuh custom volume (block device terkelola), bukan sekadar path host. Wajib dua langkah: buat volume dengan tipe block dulu, baru attach sebagai device.

Kesalahan paling umum — jangan lewatkan --type=block:

# SALAH — default tipe volume adalah filesystem, akan gagal saat di-attach ke VM:
incus storage volume create pool-qnap-hdd-01 <nama-volume> size=500GiB --project <env>
# error saat attach: "Custom filesystem volumes require a path to be defined"

# BENAR:
incus storage volume create pool-qnap-hdd-01 <nama-volume> --type=block size=500GiB --project <env>

Kesalahan umum kedua — urutan argumen config device add:

# SALAH — nama device dan tipe "disk" harus DUA kata terpisah:
incus config device add <vm> disk pool=... source=...
# error: "Unsupported device type" (karena "disk" terbaca sebagai nama device, bukan tipe)

# BENAR — <nama-device-bebas> lalu kata "disk" (tipe), baru properti:
incus config device add <vm> <nama-device> disk pool=pool-qnap-hdd-01 source=<nama-volume> --project <env>

Prosedur lengkap menambah 1 disk (ulangi per disk untuk beberapa disk sekaligus):

incus storage volume create pool-qnap-hdd-01 <vm>-vol-disk2 --type=block size=500GiB --project <env>
incus config device add <vm> disk2 disk pool=pool-qnap-hdd-01 source=<vm>-vol-disk2 --project <env>

Bila ingin lebih ringkas, bungkus sebagai shell function:

incus_attach_disk() {
  local vm=$1 dev=$2 size=$3 pool=$4 project=$5
  incus storage volume create "$pool" "${vm}-vol-${dev}" --type=block size="$size" --project "$project" && \
  incus config device add "$vm" "$dev" disk pool="$pool" source="${vm}-vol-${dev}" --project "$project"
}
# pakai:
incus_attach_disk my-vm disk2 500GiB pool-qnap-hdd-01 Production
incus_attach_disk my-vm disk3 250GiB pool-qnap-hdd-01 Production

Verifikasi:

incus config device list <vm> --project <env>
incus storage volume show pool-qnap-hdd-01 <vm>-vol-disk2 --project <env> | grep content_type   # harus: block

Di dalam guest, disk baru tidak selalu langsung terdeteksi otomatis:

lsblk    # cek device baru
# bila belum muncul, rescan bus:
echo 1 > /sys/class/scsi_host/host0/scan
lsblk -o NAME,SIZE   # cocokkan ukuran untuk mapping yang benar (urutan /dev/vdX tidak dijamin sesuai urutan penambahan)

Catatan penting soal web UI: menurut dokumentasi Incus, disk device officially mendukung hotplug untuk VM maupun container — bila form web UI memaksa instance di-stop terlebih dahulu untuk menambah disk, itu kemungkinan keterbatasan versi incus-ui-canonical yang terpasang (cek apt list --installed | grep incus-ui-canonical vs incus version, upgrade bila memungkinkan), bukan batasan platform Incus. CLI di atas selalu bekerja tanpa perlu stop.

Resize disk yang SUDAH ada (berbeda dari menambah disk baru):

incus config device set <vm> root size=100GiB --project <env>

Device-nya sendiri tidak perlu stop, tapi kernel guest mungkin perlu langkah manual untuk mengenali ukuran baru (partprobe, lalu resize2fs/xfs_growfs sesuai filesystem) atau reboot — ini keterbatasan guest OS, bukan Incus.

15.3 — Menambah network device ke VM (running)#

Mengikuti konvensi eth<VID> (lihat dokumen referensi §2.9) — kombinasi profile VLAN apa pun bisa di-stack tanpa konflik nama device:

# via profile (direkomendasikan, konsisten dengan konvensi):
incus profile add <vm> net-vlan527-observability --project <env>

# atau device manual langsung (tanpa profile):
incus config device add <vm> eth527 nic nictype=bridged parent=br-vm vlan=527 --project <env>

Untuk VM (bukan container), tambahkan alamat IP via cloud-init dengan match: macaddress seperti pada 15.1 — nama device Incus (eth527) tidak otomatis menjadi nama interface di dalam guest VM.

Verifikasi:

incus config device list <vm> --project <env>
incus exec <vm> -- ip a --project <env>   # container
# atau dari console/exec dalam VM: ip a

15.4 — Melepas disk atau network device#

incus config device remove <vm> disk2 --project <env>
# volume TIDAK otomatis terhapus (custom volume independen dari lifecycle instance) — hapus terpisah bila memang tidak diperlukan lagi:
incus storage volume delete pool-qnap-hdd-01 <vm>-vol-disk2 --project <env>

Troubleshooting Cepat#

GejalaPenyebabAksi
iSCSI login error 24CHAP belum terisi di recordiscsiadm -o update per field, login ulang
vgcreate --shared sukses tapi instan/silentSilent fallback, VG tidak benar-benar sharedHapus (vgremove --config 'global/use_lvmlockd=0' -f), restart wdmd/sanlock/lvmlockd, ulangi
“Global lock failed: check that global lockspace is started”Lockspace belum ada (bootstrap pertama) atau belum lockstartBootstrap: bypass --config 'global/use_lvmlockd=0' HANYA sebelum VG shared pertama ada. Lainnya: vgchange --lockstart
“storage errors for sanlock leases” / lock_san acquire error -28I/O ke lease area LUN bermasalah – bond pincang, MTU mismatch, atau device geser tanpa multipathCek ping -M do -s 8972, cek Partner MAC bond, pasang/reload multipath, restart wdmd+sanlock+lvmlockd
“Device or resource busy” saat lockstart (dm lvmlock)dm lama bentrok dengan mapping baru setelah transisi ke multipathdmsetup remove vg--<nama>-lvmlock, ulangi lockstart
pvcreate menyebut /dev/loop0Field source dikosongkan di wizard, jatuh ke loop file defaultHapus pool, define ulang dengan source= eksplisit
Pool lvm ukurannya hanya beberapa GBSource salah – pool dibuat di loop file root FSincus storage delete, hapus loop img (/var/lib/incus/disks/), define ulang dengan source LV benar
“Config key ‘source’ is cluster member specific” saat wizard interaktifKelakuan wizard incus admin init pada key source di setup iniGunakan preseed (Tahap 8.3), bukan wizard interaktif
“No matching cluster join operation found”Token sudah hangusGenerate token baru, langsung preseed tanpa jeda
“A volume group already exists called X” saat joinVG bekas percobaan sebelumnya belum dibersihkanvgremove VG bekas (pastikan bukan VG produksi!), ulangi
Pool ERRORED, “Storage pool directory already exists”Direktori bangkai dari storage delete sebelumnyaHapus direktori /var/lib/incus/storage-pools/<pool>/ yang kosong, commit ulang
Command di 2 terminal node berbeda bersamaan -> “not in pending state”Race conditionSelalu jalankan rangkaian incus storage create --target + commit dari SATU node/terminal
Nama device LUN berpindah (sdb->sdc->sdd)Normal – iSCSI/kernel tidak menjamin nama stabilTidak perlu tindakan bila sudah pakai multipath alias / rantai LVM-by-UUID
“Server address X is not covered by Y from cluster.https_address”core.https_address di node yang join ter-set ke IP node lain (copy-paste error)incus config get core.https_address di node gagal → set ulang incus config set core.https_address=0.0.0.0:8443 → ulangi preseed
sudo: command not foundDebian minimal tidak menyertakan sudoapt install sudo, atau su - (dengan strip – tanpa strip PATH kehilangan /usr/sbin)
ERR_SSL_UNRECOGNIZED_NAME_ALERT di browser saat akses domain reverse proxyFile custom nginx (NPM) memakai nama file yang TIDAK di-include (bukan http.conf/http_top.conf/dst) — config tidak pernah ter-parse meski nginx -t bilang OKRename file ke http.conf (satu-satunya nama yang di-include untuk server block custom); verifikasi dengan nginx -T | grep <domain>, bukan hanya nginx -t
docker exec/docker restart seperti tidak berefek, tidak ada error jelasNama container salah tebak (bukan proxymanager, sering <project>-app-1)docker ps dulu untuk memastikan nama container yang benar sebelum menjalankan perintah apa pun ke dalamnya
failed to get state: securecookie: the value is not valid saat OIDC callbackLoad balancer (nginx) mengarahkan request awal dan callback OAuth ke node Incus yang berbeda; state/session tidak konsisten antar nodeGanti metode load balancing upstream dari least_conn ke hash $remote_addr consistent agar client tetap ke node yang sama sepanjang flow
failed to exchange token: oauth2: "invalid_client" saat OIDC callbackProvider di Authentik masih Client Type Confidential — Incus tidak mengirim client secret (Public client + PKCE)Ubah Client Type provider ke Public (field ini dapat diedit langsung, tidak perlu membuat ulang provider), simpan, coba lagi
OpenID Provider Configuration Discovery has failed / HTTP 404 saat login SSOPath oidc.issuer di Incus tidak sesuai slug Application di Authentik (slug ≠ nama Provider)Cek field Slug di Applications → Applications, verifikasi manual dengan curl .../application/o/<slug>/.well-known/openid-configuration sebelum set ke Incus
“Custom filesystem volumes require a path to be defined” saat attach disk ke VMVolume dibuat tanpa --type=block (default filesystem, butuh path)Hapus volume, buat ulang dengan --type=block sebelum di-attach
“Unsupported device type” saat config device addUrutan argumen salah — nama device dan tipe disk harus dua kata terpisah (<vm> <nama-device> disk ..., bukan <vm> disk ...)Perbaiki urutan argumen sesuai contoh Tahap 15.2
multipath.conf tidak terbaca benar / alias tidak muncul di multipath -llBeberapa parameter (wwid, alias, no_path_retry) digabung dalam satu baris, bukan baris terpisahPastikan setiap parameter di baris sendiri (lihat format Tahap 13.4); validasi dengan multipath -t sebelum apply

Checklist Ringkas Per Node Baru#

[ ] OS install + partitioning (termasuk LV_STORAGE_LOCAL_INCUS)
[ ] Hostname + /etc/hosts
[ ] Repo Zabbly + paket (Tahap 4)
[ ] Network: mgmt, br-vm (vids 2-4094, MTU 1500), bond-storage (MTU 9000)
[ ] Validasi jumbo ping ke QNAP
[ ] iSCSI: initiator unik, CHAP, login (Tahap 5)
[ ] Multipath: WWID sama, alias sama semua node (Tahap 6)
[ ] lvm.conf: use_lvmlockd=1, scan_lvs=1 | lvmlocal.conf: host_id UNIK
[ ] wdmd/sanlock/lvmlockd running
[ ] lockstart vg-qnap-hdd-01 -> lvmlockctl -i bersih
[ ] Token dari node-01 -> preseed join (Tahap 8)
[ ] incus cluster list -> ONLINE
[ ] Uji relocate/migration (Tahap 9)
[ ] Systemd boot-order units (Tahap 10)
[ ] Reboot drill -- validasi auto-recovery
[ ] Reverse proxy 4-node + domain aktif, nginx -T menampilkan config (Tahap 12.2)
[ ] Authentik terpasang, provider Public + Application dengan slug tercatat (Tahap 12.3)
[ ] oidc.issuer + oidc.client.id di Incus, login SSO berhasil dari incognito (Tahap 12.4)
[ ] Penambahan LUN baru (bila ada): baseline lockspace dicatat sebelum mulai (Tahap 13.1)

TAHAP 2 — Durbality Test#

Test Plan — Performa & Ketahanan Cluster Incus + LVM Shared Storage#

roomit Compute Shared

Dokumen ini untuk validasi SEBELUM cluster dipakai workload produksi. Jalankan skenario performa dulu (baseline angka), baru skenario terburuk (chaos test). Catat semua hasil — angka baseline ini yang jadi acuan kalau nanti “kok lambat” atau “kok aneh”.

Prasyarat: cluster ONLINE semua node, tidak ada instance produksi (pakai instance uji khusus, hapus setelah selesai), beri tahu tim lain sebelum uji ketahanan (beberapa skenario sengaja mematikan storage/node).


BAGIAN 1 — Skenario Performa#

Test 1.1 — Baseline jaringan (host ke QNAP)#

# di QNAP (kalau ada iperf3) atau di node lain sebagai server:
iperf3 -s

# di node yang diuji:
iperf3 -c <IP-QNAP-atau-node-lain> -t 20 -P 4

Catat: throughput agregat (Mbps/Gbps), retransmit count. Ini batas atas teoritis — storage nggak akan pernah lebih cepat dari ini.

Jumbo check bersamaan:

ping -M do -s 8972 -c10 172.16.145.69

0% loss = jalur bersih untuk test berikutnya.

Test 1.2 — Block device mentah (host langsung ke LV shared, TANPA filesystem)#

Ini mengukur murni performa iSCSI+LVM tanpa overhead filesystem guest. Jalankan di LV TEST yang dibuang setelah selesai — jangan di LV instance yang dipakai.

lvcreate -L 5G -n lv-benchmark-test vg-qnap-hdd-01

# sequential write
dd if=/dev/zero of=/dev/vg-qnap-hdd-01/lv-benchmark-test bs=1M count=2000 oflag=direct status=progress

# sequential read
dd if=/dev/vg-qnap-hdd-01/lv-benchmark-test of=/dev/null bs=1M iflag=direct status=progress

# random I/O (kalau ada fio — lebih representatif untuk pola VM)
apt install -y fio
fio --name=randwrite --filename=/dev/vg-qnap-hdd-01/lv-benchmark-test \
    --rw=randwrite --bs=4k --size=2G --direct=1 --numjobs=4 --iodepth=16 --runtime=60 --group_reporting

fio --name=randread --filename=/dev/vg-qnap-hdd-01/lv-benchmark-test \
    --rw=randread --bs=4k --size=2G --direct=1 --numjobs=4 --iodepth=16 --runtime=60 --group_reporting

lvremove -f vg-qnap-hdd-01/lv-benchmark-test    # bersihkan setelah selesai

Catat: MB/s sequential, IOPS + latency random (avg, p99). Ini baseline realistis pool HDD — expect IOPS random rendah (ratusan, bukan ribuan) karena HDD, bukan SSD.

Test 1.3 — Di dalam guest (container & VM)#

incus launch images:debian/13/cloud perf-ct -s pool-qnap-hdd-01 -p default
incus launch images:debian/13/cloud perf-vm --vm -s pool-qnap-hdd-01 -p default

# di dalam masing-masing (incus exec / console):
apt install -y fio
fio --name=seqwrite --filename=/testfile --rw=write --bs=1M --size=1G --direct=1 --runtime=30 --group_reporting
fio --name=randwrite --filename=/testfile --rw=randwrite --bs=4k --size=512M --direct=1 --iodepth=16 --runtime=30 --group_reporting
rm /testfile

Bandingkan dengan Test 1.2 — selisih besar berarti ada overhead di layer virtualisasi (nictype/disk cache mode) yang layak diselidiki. Bandingkan juga container vs VM (VM biasanya sedikit lebih rendah karena virtio layer tambahan).

Test 1.4 — Kontensi multi-node (concurrent access ke pool shared)#

Menguji apakah lock manager (sanlock/lvmlockd) menciptakan bottleneck saat beberapa node menulis ke pool yang sama bersamaan.

# siapkan 1 instance uji per node (4 instance), pool sama, jalankan BERSAMAAN:
# di masing-masing node/instance:
fio --name=concurrent --filename=/testfile --rw=randwrite --bs=4k --size=1G \
    --direct=1 --iodepth=8 --runtime=60 --group_reporting

Catat: IOPS per-node saat 4 node menulis bersamaan vs IOPS single-node (Test 1.3). Penurunan wajar (kontensi I/O fisik), tapi kalau turun drastis (>80%) atau ada error timeout, itu sinyal masalah lock/network.

Test 1.5 — Waktu live migration#

incus launch images:debian/13/cloud vm-migrate-test --vm -s pool-qnap-hdd-01 \
  --target trim-computes-shr-incus-01
# tunggu boot penuh, lalu ukur:
time incus move vm-migrate-test --target trim-computes-shr-incus-02

Catat: durasi total, dan dari dalam VM (ping kontinu ke gateway selama migrasi) — berapa lama paket drop. Ini angka RTO riil kalau nanti dipakai buat maintenance/evacuate manual.

Ringkasan yang harus dicatat sebagai baseline#

MetrikHasil
Network throughput node↔QNAP___ Gbps
Sequential write/read (block mentah)___ / ___ MB/s
Random write/read IOPS (block mentah)___ / ___ IOPS, latency p99 ___ ms
Sequential/random di guest (container)___
Sequential/random di guest (VM)___
IOPS per-node saat 4 node concurrent___
Live migration downtime (ping drop)___ detik

BAGIAN 2 — Skenario Terburuk (Chaos Test)#

PERINGATAN: beberapa skenario ini SENGAJA mematikan storage/network/node. Jalankan di luar jam kerja, informasikan tim, dan pastikan tidak ada workload produksi nyata di cluster. Siapkan akses fisik/IPMI untuk setiap node sebelum mulai (jaga-jaga node perlu direset manual).

Setiap skenario: Tujuan → Langkah → Ekspektasi → Kriteria Lulus → Cara Pulih.

Skenario A — Cabut satu kabel bond-storage (redundansi LACP)#

Tujuan: buktikan bond LACP menyerap kegagalan 1 link tanpa gangguan.

Langkah: cabut fisik salah satu dari 2 kabel bond-storage di satu node (atau ifdown enp59s0f0).

Ekspektasi: cat /proc/net/bonding/bond-storage menunjukkan 1 slave down, agregator tetap ada di slave lain; iSCSI session tetap LOGGED_IN; instance di node itu tidak terganggu.

Kriteria lulus: iscsiadm -m session tetap LOGGED_IN, tidak ada I/O error di dmesg, ping ke QNAP tetap 0% loss (lewat link yang tersisa).

Cara pulih: colok kembali kabel, ip link set enp59s0f0 up bila perlu, verifikasi kedua slave up lagi.

Skenario B — Cabut KEDUA kabel bond-storage > 80 detik (uji fencing sanlock)#

Tujuan: validasi mekanisme fencing bekerja sesuai desain — bukan mencari cara menghindarinya.

Langkah: cabut kedua kabel bond-storage di SATU node, biarkan lebih dari ~80 detik.

Ekspektasi: node tersebut di-RESET PAKSA oleh wdmd/sanlock (watchdog fencing). Ini BUKAN bug — ini fitur anti-korupsi data.

Kriteria lulus: node reboot otomatis; setelah boot kembali dan kabel tersambung, chain boot-order (iscsi login → lockstart → incus) pulih sendiri TANPA intervensi manual; incus cluster list kembali ONLINE; instance yang sempat berjalan di node itu bisa di-start lagi (baik otomatis bila cluster.healing_threshold sudah diset, atau manual bila belum).

Cara pulih: tunggu boot selesai, jalankan verifikasi Tahap 10 runbook (iscsiadm -m sessionmultipath -lllvmlockctl -iincus list).

Catatan: ukur durasi total dari kabel putus sampai node ONLINE kembali — ini SLA riil untuk skenario storage terputus di produksi nanti.

Skenario C — QNAP mati total (single NAS, sebelum HA aktif)#

Tujuan: memahami blast radius saat satu-satunya NAS storage mati (SPOF yang sudah didokumentasikan di risiko arsitektur).

Langkah: matikan QNAP (power off terjadwal, atau cabut kedua kabel bond QNAP ke switch).

Ekspektasi: SEMUA node kehilangan akses ke pool-qnap-hdd-01 secara bersamaan; setelah ~80 detik, SEMUA node ter-fencing (reset) karena kehilangan lease bersamaan. Ini skenario paling destruktif yang mungkin terjadi di desain saat ini.

Kriteria lulus: semua node reboot otomatis, dan begitu QNAP menyala kembali, chain boot-order di SEMUA node pulih sendiri tanpa intervensi manual satu per satu.

Cara pulih: nyalakan QNAP, tunggu iSCSI target ready, tunggu semua node selesai boot-order chain, verifikasi incus cluster list semua ONLINE.

Catatan penting: skenario ini adalah alasan utama kenapa QNAP HA Manager (Tahap 3 runbook) dan rantai backup independen (incus export) menjadi prioritas — skenario C menunjukkan dampak nyata SPOF, bukan sekadar teori.

Skenario D — Node mati mendadak (kill paksa) saat instance jalan di pool shared#

Tujuan: verifikasi instance bisa “diselamatkan” (dipindah/dinyalakan ulang) di node lain setelah node asal mati, karena data ada di storage shared.

Langkah: jalankan instance uji di node-X (pool shared), lalu matikan node-X paksa (cabut power / echo b > /proc/sysrq-trigger untuk simulasi crash, BUKAN shutdown normal).

Ekspektasi: node-X hilang dari incus cluster list (statusnya OFFLINE, bukan otomatis dievakuasi kecuali cluster.healing_threshold sudah dikonfigurasi). Instance yang tadinya di node-X berstatus tidak diketahui/error sampai ditangani manual.

Langkah pemulihan manual:

incus cluster list                      # node-X: OFFLINE
incus list                               # instance yang ada di node-X
# Karena data instance ada di pool SHARED (bukan pool-local), aman untuk:
incus start <instance> --target trim-computes-shr-incus-0Y   # start di node lain

Kriteria lulus: instance berhasil dinyalakan di node lain dengan data utuh (bukan corrupt) TANPA perlu restore dari backup.

Catatan: kalau instance ada di pool-local (bukan shared), skenario ini akan GAGAL total — data hilang bersama node. Ini validasi konkret kenapa workload penting harus di pool shared, bukan pool-local.

Skenario E — Kehilangan kuorum (2 dari 4 node dqlite mati bersamaan)#

Tujuan: memahami perilaku cluster saat kuorum database hilang (dqlite butuh mayoritas — 3 dari 4).

Langkah: matikan 2 node bersamaan (sisakan 2 ONLINE).

Ekspektasi: cluster kehilangan kuorum tulis — operasi manajemen (incus launch, incus config set, dll) kemungkinan GAGAL atau timeout di 2 node yang tersisa, meskipun instance yang SUDAH BERJALAN tetap jalan (data plane tidak bergantung kuorum, hanya control plane).

Kriteria lulus: instance existing tetap berjalan tanpa gangguan; begitu 1 node kembali online (kuorum 3/4 pulih), operasi manajemen kembali normal tanpa perlu restart apa pun.

Catatan: jangan uji dengan mematikan 3 dari 4 sekaligus di cluster produksi nanti — pastikan pemahaman ini jadi acuan kebijakan maintenance (jangan pernah maintenance 2 node bersamaan dalam cluster 4-node).

Skenario F — Thin pool mendekati penuh (over-provisioning HDD)#

Tujuan: memahami perilaku saat thin pool LVM/QNAP mendekati kapasitas (karena thin provisioning, penggunaan aktual bisa mendekati fisik sebelum terlihat dari sisi Incus).

Langkah: buat beberapa volume besar berisi data acak sampai utilisasi pool QNAP mendekati 80% (ambang alert yang sudah di-set di Tahap 1).

Ekspektasi: alert QNAP di 80% muncul; tulis lanjutan masih berhasil sampai benar-benar penuh, baru gagal dengan error yang jelas (bukan silent corruption).

Kriteria lulus: error saat pool penuh adalah error I/O yang jelas (ENOSPC atau serupa) di level guest, BUKAN korupsi data/filesystem.

Cara pulih: hapus volume uji, verifikasi ruang kembali (thin provisioning — pastikan fstrim/discard jalan agar ruang benar-benar dikembalikan ke pool, bukan hanya di level guest).

Skenario G — CHAP/target iSCSI salah sesaat (simulasi gangguan konfigurasi)#

Tujuan: verifikasi perilaku reconnect saat sesi iSCSI terganggu karena masalah auth sesaat (misal QNAP restart service iSCSI).

Langkah: restart service iSCSI di QNAP (bukan seluruh NAS), amati node.

Ekspektasi: sesi iSCSI di node drop sebentar, node.startup=automatic membuat iscsid mencoba reconnect otomatis; bila QNAP kembali dalam window toleransi, tidak perlu intervensi manual.

Kriteria lulus: iscsiadm -m session kembali LOGGED_IN otomatis tanpa perlu iscsiadm -m node --login manual.


Rekap Kriteria Kelulusan Sebelum Go-Live Produksi#

[ ] Baseline performa tercatat (Bagian 1) — jadi acuan monitoring ke depan
[ ] Skenario A (1 kabel putus) — lulus, tanpa gangguan
[ ] Skenario B (2 kabel putus, fencing) — lulus, node pulih otomatis
[ ] Skenario C (QNAP mati total) — dipahami dampaknya, mendorong prioritas HA QNAP
[ ] Skenario D (node crash) — instance di pool shared berhasil diselamatkan
[ ] Skenario E (kuorum hilang) — dipahami, jadi kebijakan maintenance (jangan 2 node bersamaan)
[ ] Skenario F (pool hampir penuh) — error jelas, bukan silent corruption
[ ] Skenario G (iSCSI reconnect) — otomatis pulih
[ ] Semua node kembali ONLINE dan bersih setelah seluruh rangkaian test
[ ] Instance uji dihapus, tidak ada sisa test yang tertinggal di storage