Seri: Proxmox VE Cluster ve Corosync
Modül 1'de cluster'ı kurdum, canlı migration'ın çalıştığını kanıtladım, ve bir node çökünce VM'in kendiliğinden başka bir yerde açılmadığını gösterdim. Bu modülde asıl arkasındaki mekanizmaya iniyorum: quorum. Ne zaman kaybediliyor, pmxcfs'i nasıl etkiliyor, QDevice bu denklemi nasıl değiştiriyor, ve "quorum'u zorla" demenin (pvecm expected) gerçekten ne kadar tehlikeli olduğunu, kendim tetiklemeye çalışarak öğrendim. Sona da, Modül 1'de yarım kalan bir şeyi tamamladım: gerçek bir shared storage kurup, migration'ın --with-local-disks olmadan nasıl çalıştığını gösterdim.
Bu modülde bir hipotezimin yanlış çıktığını da saklamayacağım; yanlış çıkması, doğru sonuçtan daha fazla şey öğretti.
Quorum Nedir, Neden Var?
Quorum, dağıtık bir sistemde bir işlemi (özellikle konfigürasyon değişikliği) gerçekleştirmek için gereken minimum oy sayısı. Proxmox VE'de her node varsayılan olarak bir oy taşıyor. Formül basit: quorum = floor(toplam_oy / 2) + 1. Ağ bölünmesi (partition) olduğunda, sadece çoğunluğa sahip taraf işlemeye devam edebiliyor; bu, split-brain'i (iki tarafın da "ben doğruyum" deyip aynı kaynağı bağımsız yönetmeye çalışmasını) önlüyor.
3 node'lu cluster'ımızda quorum eşiği 2 (3'ün çoğunluğu). Bir node izole olursa, kalan iki node çoğunluğu oluşturduğu için çalışmaya devam ediyor; izole olan tek node ise azınlıkta kalıp durabiliyor.
Uygulama 1: Quorum Kaybını Gerçekten Tetiklemek
Bunu Modül 1'deki node çökertme testinden farklı yapmak istedim: orada tüm node'u (virsh destroy) öldürmüştüm, burada sadece Corosync ağını kesip node'u canlı tutuyorum; management ağı hâlâ açık, SSH ile erişebiliyorum.
Fiziksel host'tan pve-c'nin corosync-net arayüzünü düşürdüm:
sudo virsh domif-setlink pve-c vnet15 down
pve-c'de:
pvecm status
Nodes: 1
Quorate: No
Total votes: 1
Quorum: 3 Activity blocked
Beklendiği gibi: tek başına kalan pve-c, quorum eşiğini (3, bu noktada QDevice henüz yoktu) karşılayamıyor.
pmxcfs'e yazmayı denedim:
touch /etc/pve/test-readonly.txt
touch: cannot touch '/etc/pve/test-readonly.txt': Permission denied
Modül 1'de gördüğüm "read-only file system" davranışının bir başka görünümü; burada hata mesajı farklı (Permission denied vs Read-only file system) ama sonuç aynı: quorum'suz bir node, konfigürasyona yazamıyor.
Çoğunluk tarafında (pve-a, iki node) durum farklıydı: Quorate: Yes olarak kaldı, hiç kesinti yaşamadı. Bu, quorum mekanizmasının tam olarak tasarlandığı gibi çalıştığının kanıtı: azınlık durur, çoğunluk devam eder.
Ağı geri açtım (up), birkaç saniye içinde cluster kendiliğinden 3/3 quorate'e döndü.
Uygulama 2: QDevice'i Devreye Almak
qdevice-1 VM'ine Modül 0'da zaten corosync-qnetd paketini kurmuştum, ama hiç yapılandırmamıştım. Şimdi gerçekten devreye alma zamanı.
Beklenmedik Uyarı: Odd Node Count
pvecm qdevice setup 192.168.122.20
Clusters with an odd node count are not officially supported!
Bu beni şaşırttı. Araştırınca öğrendim: pvecm, node sayısı tek olduğunda varsayılan olarak duruyor. Sebep, QDevice'in iki farklı algoritması var: çift node sayısı için varsayılan ffsplit (her node'a eşit davranıp QDevice'e her zaman tam 1 oy veren), tek node sayısı için ise --force ile devreye giren lms (Last Man Standing). 3 node'lu cluster'ım tek sayı olduğu için bu uyarıyı tetikledi.
pvecm qdevice setup 192.168.122.20 --force
Bu sefer kurulum tamamlandı: sertifikalar üç node'a da dağıtıldı, corosync-qdevice.service her node'da otomatik enable + start edildi.
lms Algoritmasının Etkisini Doğrulamak
pvecm status
Expected votes: 5
Total votes: 5
Quorum: 3
Membership information
Nodeid Votes Qdevice Name
0x00000001 1 A,V,NMW 10.10.10.11
0x00000002 1 A,V,NMW 10.10.10.12
0x00000003 1 A,V,NMW 10.10.10.13 (local)
0x00000000 2 Qdevice
Burada dikkatimi çeken şey: Qdevice satırında 2 oy var, 1 değil. ffsplit'te QDevice her zaman 1 oy verirken, lms'de N-1 oy veriyor (N = node sayısı). Bizim durumumuzda 3-1=2. corosync.conf'a bakınca bunu doğruladım:
quorum {
device {
model: net
net {
algorithm: lms
host: 192.168.122.20
tls: on
}
}
}
Toplam matematik: 3 node × 1 + QDevice × 2 = 5 oy, quorum eşiği 3.
Uygulama 3: QDevice'in Değerini Kanıtlamak
Modül 1'de, tek bir node çoğunluğu asla oluşturamıyordu. QDevice'in asıl var oluş sebebi, bunu belirli senaryolarda değiştirmek. Test ettim: iki node'u aynı anda çökerttim.
sudo virsh destroy pve-b
sudo virsh destroy pve-c
Tek kalan pve-a'da:
pvecm status
Nodes: 1
Total votes: 3
Quorum: 3
Quorate: Yes
Matematik: pve-a (1 oy) + QDevice (2 oy) = 3, eşik de 3. Quorate: Yes. QDevice olmadan bu imkansız olurdu; tek bir node kendi başına asla çoğunluk oluşturamaz.
Kanıtı tamamlamak için:
touch /etc/pve/qdevice-test.txt
Başarılı oldu; dosya /etc/pve altında göründü. Modül 1'deki "tek node = read-only" bulgusunun tam tersi; burada tek node ama QDevice sayesinde quorate, pmxcfs yazılabilir.
İki node'u da geri getirdim, birkaç dakika içinde cluster tam olarak (5 oy, 3 node) toparlandı.
Uygulama 4: Split-Brain'i Tetiklemeye Çalışmak
pvecm expected komutu, bir node'u zorla "quorate" göstermenin bir yolu; teoride tehlikeli, çünkü izole bir node kendini haklı sanıp bağımsız kararlar almaya başlayabilir. Bunu bilerek tetiklemeye çalıştım.
İlk Deneme: Yanlış Anlaşılan Bir Hata
pve-c'yi izole ettim, ama down komutundan hemen sonra yanlışlıkla up'ı da çalıştırdım; izolasyon çok kısa sürdü. pve-c'de:
pvecm expected 1
Hiçbir hata almadım, ama sonraki denemede (hem pve-c'de hem pve-a'da):
Unable to set expected votes: CS_ERR_INVALID_PARAM
İlk başta bunun QDevice'e özgü bir kısıtlama olduğunu düşündüm. Yanılmışım. Gerçek sebep daha basit: votequorum_setexpected API'si, sadece zaten quorum'suz olan bir partition'ı kurtarmak için çalışıyor; zaten quorate olan bir partition'ın oy eşiğini manuel düşürmene izin vermiyor. Bizim denemelerimiz, node zaten (kısa izolasyondan sonra ya da QDevice'in sağladığı fazladan oyla) quorate durumdayken yapıldığı için reddedildi. Bu, QDevice'in özel bir davranışı değil, corosync'in her zaman var olan bir güvenlik kuralı.
İkinci Deneme: Doğru İzolasyon
Bu sefer pve-c'yi gerçekten izole tuttum, geri açmadım:
sudo virsh domif-setlink pve-c vnet15 down
pve-c'de doğruladım:
Nodes: 1
Quorate: No
Total votes: 1
Quorum: 3
Gerçekten quorum'suz. Şimdi:
pvecm expected 1
pvecm status
Beklenmedik bir şey oldu:
Expected votes: 3
Quorum: 2
Quorate: No
1 istedim, sistem 3 verdi. Ve pve-c (1 oy) bu yeni eşiği (2) bile karşılayamadığı için Quorate: No kaldı, touch yine Permission denied verdi.
Bu Neden Oldu?
Bunu araştırdım. Proxmox'un kurucu geliştiricilerinden Thomas Lamprecht, 2018 tarihli bir mailing list yazışmasında Corosync'in expected_votes davranışını şöyle açıklıyor:
"Highest expected can not be smaller then the actual online quorate nodes."
Yani Corosync, expected_votes değerini online ve quorate node sayısının altında tutmuyor. Thomas'ın verdiği örneğe göre, manuel olarak expected_votes: 16 ayarlanmışsa ve 28 node online/quorate durumdaysa, Corosync 16 yerine 28'i kullanıyor. Bunu kabaca şu şekilde ifade ediyor:
expected = max(user_set_expected, #nodes_quorate_online)
Ancak online/quorate node sayısı manuel olarak belirlenen değere eşit veya daha düşükse, Corosync'in bu değeri koruması mümkün. Thomas ayrıca last_man_standing etkinleştirildiğinde, yeterli node kaldığı sürece belirli bir süre sonunda highest expected değerinin aşağı doğru yeniden hesaplanabileceğini belirtiyor. Proxmox Lists
Bunun QDevice'in lms algoritmasından kaynaklandığını düşünüyorum; muhtemelen QDevice'in oy hesaplaması sağlıklı kalabilsin diye expected_votes'un cluster'da tanımlı gerçek node sayısının (3) altına hiç düşürülmesine izin verilmiyor, o an kaç node'un online olduğundan bağımsız olarak. Ama bunu kaynak koda bakmadan kesin olarak iddia edemem; bu, dokümante edilmiş bir davranıştan çok, gözlemlenip mantıklı görünen bir çıkarım.
Sonuç ne olursa olsun, pratik etkisi net: split-brain'i kasıtlı olarak tetiklemeye çalıştım, QDevice'li ortamda başaramadım.
Toparlamak
pvecm expected 5
sudo virsh domif-setlink pve-c vnet15 up
Birkaç saniye sonra cluster tam olarak (5 oy, 3 node, Quorate: Yes) geri döndü.
Uygulama 5: Shared Storage ile Migration'ı Yeniden Denemek
Modül 1'de canlı migration'ı test ederken --with-local-disks flag'ini kullanmak zorunda kalmıştım; çünkü VM'in diski shared storage'da değil, sadece kaynak node'un yerel LVM'sindeydi. Bir arkadaşımın önerisiyle bunu düzeltmeye karar verdim: gerçek bir SAN/NAS kurmak yerine, kendi laptop'umu (CachyOS host) NFS sunucusu olarak kullanıp bunu üç node'a paylaşımlı storage olarak eklemek.
Baştan söylemek isterim: bu, gerçek bir shared storage değil, homelab için taklit edilmiş bir tanesi. Kullandığım no_root_squash ve insecure export seçenekleri, gerçek bir ortamda asla böyle bırakılmaz; root'un uzaktan tam yetkiyle yazmasına izin veriyor, güvenlik açısından savunmasız. Burada sadece lab kolaylığı için var.
NFS Sunucusunu Host'ta Kurmak
CachyOS (Arch tabanlı) olduğu için paket ismi Debian'dan farklı; tek paket hem sunucu hem client araçlarını içeriyor:
sudo pacman -S nfs-utils
sudo mkdir -p /srv/nfs/proxmox-shared
sudo chown nobody:nobody /srv/nfs/proxmox-shared
sudo chmod 777 /srv/nfs/proxmox-shared
/etc/exports:
/srv/nfs/proxmox-shared 192.168.122.0/24(rw,sync,no_subtree_check,no_root_squash,insecure)
sudo systemctl enable --now rpcbind nfs-server
sudo exportfs -arv
Beklenmedik Engel: Firewall
İlk mount denemesi pve-a'dan başarısız oldu:
mount.nfs: Connection refused for 192.168.122.1:/srv/nfs/proxmox-shared on /mnt/test-nfs
Servisler çalışıyordu, export tanımlıydı, portlar (2049, 111) dinliyordu; sorun firewalld'ın aktif olmasıydı:
sudo firewall-cmd --get-active-zones
libvirt
interfaces: virbr-coro virbr0
virbr0 (management) ve virbr-coro (corosync-net) ikisi de libvirt zone'undaydı, ama bu zone'a NFS servisleri hiç eklenmemişti:
sudo firewall-cmd --permanent --zone=libvirt --add-service=nfs
sudo firewall-cmd --permanent --zone=libvirt --add-service=rpc-bind
sudo firewall-cmd --permanent --zone=libvirt --add-service=mountd
sudo firewall-cmd --reload
Bu düzeltmeden sonra manuel mount çalıştı, touch ve ls başarılı oldu.
Proxmox'a Eklemek ve Disk Taşımak
pvesm add nfs nfs-shared --server 192.168.122.1 --export /srv/nfs/proxmox-shared --content images
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
nfs-shared nfs active 486256640 72509440 412091392 14.91%
VM 100'ün diskini taşıdım:
qm move-disk 100 scsi0 nfs-shared
Beklenmedik Bir Detay: Hayalet Disk Referansı
İlk migration denemesinde (pve-b'den pve-c'ye) log'da hâlâ "copying local disk images" adımı çıktı, 8GB'lık bir kopyalama yaptı; disk zaten NFS'te olması gerekirken. qm config 100'e baktığımda sebebi gördüm:
scsi0: nfs-shared:100/vm-100-disk-0.raw,...
unused0: local-lvm:vm-100-disk-0
move-disk diski gerçekten NFS'e taşımıştı, ama eski local-lvm referansını unused0 olarak arkada bırakmıştı. Migration da bağlı her diski (kullanılan/kullanılmayan farketmeksizin) taşımaya çalıştığı için bu hayalet referansı da kopyalamıştı. lvremove ile temizlemeye çalışınca üç node'da da "Failed to find logical volume" hatası aldım; migration'ın kendisi log'un sonunda zaten Logical volume "vm-100-disk-0" successfully removed demişti, yani gerçek disk çoktan silinmişti, sadece config'te unutulmuş bir referans kalmıştı:
qm unlink 100 --idlist unused0
Temiz Migration: Öncesi/Sonrası
Hayalet referans temizlendikten sonra tekrar denedim (pve-c'den pve-a'ya):
2026-08-14 09:06:34 starting migration of VM 100 to node 'pve-a'
2026-08-14 09:06:34 starting VM 100 on remote node 'pve-a'
2026-08-14 09:06:36 starting online/live migration
2026-08-14 09:06:37 average migration speed: 1.0 GiB/s - downtime 15 ms
2026-08-14 09:06:37 migration completed, transferred 158.5 MiB VM-state
2026-08-14 09:06:39 migration finished successfully (duration 00:00:05)
"Copying local disk images" adımı tamamen yok; disk hiç dokunulmadı, sadece VM'in bellek durumu (158.5 MiB) taşındı.
Modül 1 (local disk, --with-local-disks) |
Bu test (NFS shared storage) | |
|---|---|---|
| Disk kopyalama | Var, ~8 GB, ~13 saniye | Yok |
| Toplam süre | ~20 saniye | ~5 saniye |
| Downtime | 43 ms | 15 ms |
| Taşınan veri | Disk + VM state | Sadece VM state (158.5 MiB) |
Ping testi bu sırada da kesintisizdi; 40'tan fazla paket, hiç kayıp yok, gecikme 0.3-1.3ms aralığında sabit kaldı.
Bu karşılaştırma, --with-local-disks'in neden var olduğunu somutlaştırdı: o flag olmadan disk paylaşımlı değilse migration mümkün değil; flag'in kendisi de aslında bir kısayol değil, "diski de taşımak zorundayım çünkü paylaşımlı değil" itirafı. Gerçek shared storage'da bu ihtiyaç tamamen ortadan kalkıyor, migration da doğal olarak hızlanıyor.
Genel Değerlendirme
Bu modülde planladığımdan farklı bir sona vardım. Amacım split-brain riskini göstermekti; onun yerine, QDevice'in bu riski nasıl engellediğini gösterdim. Sanırım bu, orijinal planımdan daha iyi bir sonuç.
En çok üzerinde durduğum üç nokta:
Birincisi, ffsplit ve lms arasındaki oy farkı (1 vs N-1). Bu küçük bir detay gibi görünüyor ama gerçek bir kararı etkiliyor: tek sayılı bir cluster'da QDevice'in matematiği, çift sayılı bir cluster'dakinden temelden farklı çalışıyor.
İkincisi, pvecm expected'in "zaten quorate olan bir partition'ı düşüremezsin" kuralı. İlk denemem bu yüzden başarısız oldu, ve bunu QDevice'e yanlış bağladım; doğrusunu bulmak için araştırmam gerekti. Yanlış bir hipotezle başlayıp onu düzeltmek, doğru hipotezle başlamaktan daha çok şey öğretti.
Üçüncüsü, ikinci (doğru) denemede gördüğüm 1'den 3'e yuvarlanma. Bunun tam mekanizmasını hâlâ %100 kesinlikle açıklayamıyorum; genel corosync davranışı bunu tam karşılamıyor, QDevice'e özgü bir şey olduğunu düşünüyorum ama kaynak koda inmeden kesin konuşamam. Bu belirsizliği olduğu gibi bırakmayı, uydurma bir kesinlik sunmaya tercih ettim.
Sonuç olarak: quorum kaybını gerçekten tetikledim, pmxcfs'in read-only davranışını iki farklı şekilde (host çökmesi, ağ izolasyonu) doğruladım, QDevice'i kurdum ve onun olmadan imkansız olacak bir senaryoyu ayakta tuttum, split-brain'i kasıtlı olarak tetiklemeye çalışıp başaramadım, ve son olarak Modül 1'deki --with-local-disks zorunluluğunu shared storage kurarak ortadan kaldırdım. Bu son kısım kendi başına küçük bir hikaye oldu: NFS kurulumu, firewall'ın gerçek engel olduğunu bulmam, ve migration'ın arkada bıraktığı hayalet disk referansını çözmem; hiçbiri planladığım gibi sorunsuz gitmedi, ama her biri gerçek bir öğrenme anıydı.
Bir sonraki modülde HA Manager'a geçiyorum: watchdog tabanlı fencing, node/resource affinity kuralları, ve Modül 1'de gördüğümüz "VM kendiliğinden açılmadı" sonucunu bu sefer tersine çevirmek.
Bu seri, resmi Proxmox VE dokümantasyonundan (pve.proxmox.com) ve topluluk kaynaklarından (pve-user mailing list, corosync/votequorum man sayfaları) derleniyor. Buradaki gözlemler bir homelab ortamına dayanıyor; production kararları için resmi dokümantasyon ve deneyimli sistem yöneticileri referans alınmalıdır.


Top comments (0)