DEV Community

Hakan İSMAİL
Hakan İSMAİL

Posted on

Quorum Kaybını Tetiklemek, QDevice Kurmak ve Shared Storage'a Geçmek (Modül 2)

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
Enter fullscreen mode Exit fullscreen mode

pve-c'de:

pvecm status
Enter fullscreen mode Exit fullscreen mode
Nodes:            1
Quorate:          No
Total votes:      1
Quorum:           3 Activity blocked
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
touch: cannot touch '/etc/pve/test-readonly.txt': Permission denied
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
Clusters with an odd node count are not officially supported!
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Tek kalan pve-a'da:

pvecm status
Enter fullscreen mode Exit fullscreen mode
Nodes:            1
Total votes:      3
Quorum:           3
Quorate:          Yes
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

İ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
Enter fullscreen mode Exit fullscreen mode

pve-c'de doğruladım:

Nodes:            1
Quorate:          No
Total votes:      1
Quorum:           3
Enter fullscreen mode Exit fullscreen mode

Gerçekten quorum'suz. Şimdi:

pvecm expected 1
pvecm status
Enter fullscreen mode Exit fullscreen mode

Beklenmedik bir şey oldu:

Expected votes:   3
Quorum:           2
Quorate:          No
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

/etc/exports:

/srv/nfs/proxmox-shared 192.168.122.0/24(rw,sync,no_subtree_check,no_root_squash,insecure)
Enter fullscreen mode Exit fullscreen mode
sudo systemctl enable --now rpcbind nfs-server
sudo exportfs -arv
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Servisler çalışıyordu, export tanımlıydı, portlar (2049, 111) dinliyordu; sorun firewalld'ın aktif olmasıydı:

sudo firewall-cmd --get-active-zones
Enter fullscreen mode Exit fullscreen mode
libvirt
  interfaces: virbr-coro virbr0
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Bu düzeltmeden sonra manuel mount çalıştı, touch ve ls başarılı oldu.

nfs-shared Depolamasının Web UI da Görünümü

Proxmox'a Eklemek ve Disk Taşımak

pvesm add nfs nfs-shared --server 192.168.122.1 --export /srv/nfs/proxmox-shared --content images
Enter fullscreen mode Exit fullscreen mode
Name              Type     Status     Total (KiB)      Used (KiB) Available (KiB)        %
nfs-shared         nfs     active       486256640        72509440       412091392   14.91%
Enter fullscreen mode Exit fullscreen mode

VM 100'ün diskini taşıdım:

qm move-disk 100 scsi0 nfs-shared
Enter fullscreen mode Exit fullscreen mode

nfs-shared Depolamasına Taşıdığımız Diskin Görünümü

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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