<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hakan İSMAİL</title>
    <description>The latest articles on DEV Community by Hakan İSMAİL (@hakanbaban53).</description>
    <link>https://dev.to/hakanbaban53</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3593379%2F63770104-9eda-408d-bbe7-f9d3072ffe6e.jpeg</url>
      <title>DEV Community: Hakan İSMAİL</title>
      <link>https://dev.to/hakanbaban53</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hakanbaban53"/>
    <language>en</language>
    <item>
      <title>Proxmox Otomasyonu Faz 2: Serial ile Kimliklendirilmiş Depolama, Kesintisiz LVM + XFS</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Fri, 04 Sep 2026 06:15:59 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/proxmox-otomasyonu-faz-2-serial-ile-kimliklendirilmis-depolama-kesintisiz-lvm-xfs-4acb</link>
      <guid>https://dev.to/hakanbaban53/proxmox-otomasyonu-faz-2-serial-ile-kimliklendirilmis-depolama-kesintisiz-lvm-xfs-4acb</guid>
      <description>&lt;p&gt;Bir önceki fazda pipeline'ın temelini attık: tek bir &lt;code&gt;terraform apply&lt;/code&gt; Ubuntu 26.04 imajını indirip golden template'i kuruyor, cloud-init'li klonu (vm-test-01, VMID 200) ayağa kaldırıyor, ilk temas playbook'u Ansible'la yönetim kanalını açıyordu. VM hâlâ ayakta, guest agent çalışıyor, repo git'te. Ama o makine tek diskli ve production'da hiçbir DB sunucusu tek diskle çalışmıyor: &lt;code&gt;/var&lt;/code&gt;, log, data, backup ayrı LUN'larda, her biri kendi büyüme takvimiyle.&lt;/p&gt;

&lt;p&gt;Şeffaflık adına küçük bir not, inşa bölümlerine girmeden önce: bu rehberin arkasındaki saha oturumu, Faz 2'nin başında lab'ı sıfırdan kurdu. Yani buradaki transkriptleri taşıyan makine birebir Faz 1'in bitirdiği VM değildi; aynı pipeline'ın, aynı koddan ürettiği taze bir klondu. Ama rebuild'in kendisi bu rehberin en değerli iki sorun giderme satırını hediye etti: temizlik sırasında silinmeyip kalan bir template'e çarpan ilk apply ve ilk girişte karşılayan taze SSH host anahtarları. İkisi de aşağıda, gerçek transkriptleriyle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hedef: dört disk, kalıcı kimlik
&lt;/h2&gt;

&lt;p&gt;Faz 2'nin tamamı yine tek cümleye sığıyor: DB sınıfı bir iş yükünün dört diski Terraform'da tanımlanmalı, her diskin kalıcı bir kimliği olmalı, guest tarafı bu kimliklerden LVM üstünden XFS'e uzanan bir zincirle bağlanmalı ve büyüme isteği tek değişkenle, makine çalışırken çözülmeli.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bileşen&lt;/th&gt;
&lt;th&gt;Sürüm/Not&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Proxmox VE&lt;/td&gt;
&lt;td&gt;9.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terraform&lt;/td&gt;
&lt;td&gt;1.15.x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bpg/proxmox provider&lt;/td&gt;
&lt;td&gt;0.111.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ansible-core&lt;/td&gt;
&lt;td&gt;2.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yeni bağımlılık&lt;/td&gt;
&lt;td&gt;community.general, ansible.posix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dosya sistemi&lt;/td&gt;
&lt;td&gt;XFS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Kapsam, Faz 1'deki gibi bilinçli olarak dar tutuluyor; her hareketli parça tek başına doğrulanabilsin diye:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Faz 2'de var&lt;/th&gt;
&lt;th&gt;Sonraki fazlara ertelendi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Workload VM'de dört serial etiketli veri diski&lt;/td&gt;
&lt;td&gt;Golden template'in kendisine disk eklemek (kalıp sade kalıyor)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PV, VG, LV, XFS ve fstab'ı tek idempotent playbook'un yönetmesi&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/var&lt;/code&gt; gibi canlı dizinleri yeni disklere taşımak (canlı veri taşıma)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Online büyütme: tfvars düzenle, apply, playbook'u tekrar çalıştır&lt;/td&gt;
&lt;td&gt;Küçültme (tasarım gereği imkânsız: provider sert hata, XFS'in kendi sınırı)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Doğrulama çıktıları: lsblk, df, serial eşleşmesi&lt;/td&gt;
&lt;td&gt;Kullanım izleme (Zabbix Faz 3'te geliyor)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community collection'ları yönetilen bir bağımlılık olarak tutmak&lt;/td&gt;
&lt;td&gt;Terraform state'ten beslenen dinamik envanter (Faz 4)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Problem: disk tahmini ve elle büyütme
&lt;/h2&gt;

&lt;p&gt;Bu fazı şekillendiren gereksinimler sahadan geldi ve tekrar etmeye değer, çünkü başarının neye benzediğini tanımlıyorlar. O ortamdaki DB sunucuları OS diski dışında dört beş disk taşıyor: &lt;code&gt;/var&lt;/code&gt;, log, data, backup, her biri kendi LUN'unda, kendi büyüme takviminde. Bir müşteri &lt;code&gt;/data&lt;/code&gt;'ya yer istediğinde önce birinin hangi hipervizör diskinin gerçekten o olduğunu bulması, sonra doğru olanı büyütmesi, sonra guest içinde dosya sisteminin yeni alanı görmesi için bir komut zincirini adım adım işletmesi gerekiyordu.&lt;/p&gt;

&lt;p&gt;Sorunun özü, Linux'ta disk harflerinin bir kimlik değil, bir numaralandırma kazası olması. Kernel, SCSI aygıtlarını bus'ın tarama sırasına göre numaralandırıyor; bu sıra, sürücü probing'i ve aygıt kaydının zamanlamasının bir yan etkisi. Genelde konfigürasyon sırasıyla eşleşiyor, bu yüzden &lt;code&gt;/dev/sdb&lt;/code&gt; sinsi ve yanıltıcı bir güvenceye dönüşüyor: eşleşme, tam da bir gün artık geçerli olmayana kadar (tipik olarak bir reboot'tan, bir hotplug olayından ya da bir disk daha eklendiğinde) istikrarlı görünüyor. Sistemde &lt;code&gt;scsi3&lt;/code&gt;'ün, yapılandırdığınız üçüncü disk olduğuna dair hiçbir söz yok.&lt;/p&gt;

&lt;p&gt;Bunun sonucu, deneme-yanılmayla büyütmeydi: hipervizörde bir diski tanınabilir bir miktar büyüt, guest içinde hangi disk harfinin boyutunun değiştiğini gözle, ancak o zaman hangi diske dokunduğunu öğren. Bu deneme sürecini bir grup içindeki on sunucuyla çarpınca hata payı ciddileşiyor: yanlış diski büyütmek zararsız ama bir bakım penceresini boşa harcıyor; yanlış diski formatlamak ise bir veri kaybı olayı. Çözüm daha fazla dikkat değil, numaralandırmayı atlatan bir kimlik.&lt;/p&gt;

&lt;p&gt;Doğru disk bulunduktan sonra ritüelin kendisi beş komutluk bir silsileden ibaretti: partition'ı genişletmek için &lt;code&gt;growpart&lt;/code&gt; ya da &lt;code&gt;fdisk&lt;/code&gt;, LVM'e yeni boyutu öğretmek için &lt;code&gt;pvresize&lt;/code&gt;, mantıksal volümü büyütmek için &lt;code&gt;lvextend&lt;/code&gt;, dosya sistemini büyütmek için &lt;code&gt;xfs_growfs&lt;/code&gt;. Bu adımların hiçbiri zor değil; hepsi unutulması kolay, sıraya bağlı ve on terminal aynı anda açıkken yanlış aygıta karşı çalıştırılması kolay. Faz 2 bu ritüeli, beş komutu scriptleştirerek değil, "bu disk hangisi" sorusunu baştan belirsiz olmaktan çıkararak siliyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tasarım: kimlik serial'da
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Disk harfi, kernel'in diski nerede bulduğudur. Serial, diskin ne olduğudur. Diskleri ne olduklarıyla adresle.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bu tasarımdaki her disk, Terraform'da set edilen, Proxmox konfigürasyonundan geçen, QEMU tarafından guest'e sunulan ve kernel tarafından &lt;code&gt;lsblk&lt;/code&gt;'nin SERIAL kolonunda raporlanan bir serial string taşıyor. Serial, bütün yığını değişmeden dolaşıyor; onu bir etiket değil bir kimlik yapan da bu: tfvars dosyasında, PVE konfigürasyonunda ve guest'in kendi disklerine dair kernel görüşünde aynı değer.&lt;/p&gt;

&lt;p&gt;Saha testi bu zincire bir ders ekledi ve aşağıdaki tablo bu durumu bütün çıplaklığıyla gösteriyor:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Katman&lt;/th&gt;
&lt;th&gt;Değer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;terraform.tfvars&lt;/td&gt;
&lt;td&gt;&lt;code&gt;data_disk_size_gb = 20&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;terraform (vm.tf)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;disk { interface = "scsi3" serial = "data01" size = 20 }&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pve-a (&lt;code&gt;qm config 200&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;scsi3: nfs-shared:vm-200-disk-2,size=20,serial=data01&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pve-a (&lt;code&gt;qm showcmd 200&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;scsi-hd aygıt satırında &lt;code&gt;serial=data01&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;guest (&lt;code&gt;lsblk -o SERIAL&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sdc disk 20G data01&lt;/code&gt; ← kernel'in gördüğü&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ansible (02_storage.yml)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;dev: "/dev/sdc"&lt;/code&gt; (lsblk'den taze çözülmüş)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sonuç&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;vg_data/lv_data&lt;/code&gt;, &lt;code&gt;/srv/data&lt;/code&gt;'ya bağlı&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ders, son iki halkada yatıyor. Bu playbook'un ilk sürümü serial'leri klasik udev yolu &lt;code&gt;/dev/disk/by-id&lt;/code&gt; üzerinden çözüyordu; bu yığında o dizin serial-adlı girdileri hiç oluşturmadı. Kernel &lt;code&gt;lsblk&lt;/code&gt;'de dört serial'i de raporluyordu, by-id ise hiçbirini sunmuyordu; yani Ubuntu 26.04, virtio-scsi üzerinde bu symlink'leri garanti etmiyor. Playbook bu yüzden kernel görüşünü doğrudan okuyor; çözdüğü disk harfleri de tam bu yüzden güvenle kullanılabiliyor: LVM fiziksel volümleri UUID'yle takip ediyor, fstab &lt;code&gt;/dev/vg/lv&lt;/code&gt; device-mapper yollarını bağlıyor, eşleşme her çalıştırmada sıfırdan yeniden kuruluyor. Harf, playbook'un bir çalıştırma döngüsü süresince geçerli bir tutamaç; serial, VG ve LV ise kalıcı kimlikler.&lt;/p&gt;

&lt;p&gt;Tasarımın üç dayanağı, kod okunmadan varsayılmadı; bpg/proxmox 0.111.1'in kaynağından doğrudan alındı:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;İddia&lt;/th&gt;
&lt;th&gt;Kaynak kanıtı&lt;/th&gt;
&lt;th&gt;Tasarıma yansıması&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mevcut bir VM'e disk eklemek yeniden oluşturmaya zorlamıyor&lt;/td&gt;
&lt;td&gt;disk.go'daki disk bloğunda hiç ForceNew bayrağı yok&lt;/td&gt;
&lt;td&gt;Dört disk, çalışan VM 200'e yerinde ekleniyor; destroy yok, re-clone yok&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diski büyütmek online bir API çağrısı&lt;/td&gt;
&lt;td&gt;vm.go, boyut artışları için resize API'yi çağırıyor; yalnızca datastore taşımaları shutdownForDisksRequired işaretliyor&lt;/td&gt;
&lt;td&gt;Büyütme demosu reboot'suz çalışıyor; datastore'lar arası taşıma hâlâ kesinti isteyen tek depolama değişikliği&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Küçültme yüksek sesle reddediliyor&lt;/td&gt;
&lt;td&gt;vm.go "Cannot shrink ... it is not supported" hatasını döndürüyor&lt;/td&gt;
&lt;td&gt;Sadece-büyüme kuralı provider katmanında zaten dayatılıyor; playbook bununla savaşmak yerine uyum sağlıyor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Bu garantilerin üstüne beş yerleşim kararı geliyor:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Karar&lt;/th&gt;
&lt;th&gt;Gerekçe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Disk başına bir VG ve bir LV&lt;/td&gt;
&lt;td&gt;Disk büyür, VG'si büyür, LV'si büyür: net ve bire bir bir zincir. Paylaşımlı bir VG tahsiste daha esnek ama hangi fiziksel diskin hangi LV'yi beslediğini bulanıklaştırıyor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LV, VG'nin yüzde yüzü&lt;/td&gt;
&lt;td&gt;LV her zaman diskine eşit; VG büyüyünce &lt;code&gt;lvol&lt;/code&gt; onu otomatik uzatıyor, hiçbir şey değişmediğinde no-op olarak boş dönüyor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XFS, ext4 değil&lt;/td&gt;
&lt;td&gt;Hedef ortamdaki DB-sunucu pratiği; &lt;code&gt;xfs_growfs&lt;/code&gt;'le online büyüyor; küçültülememesi provider'ın sadece-büyüme kuralıyla zaten örtüşüyor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lab, &lt;code&gt;/srv/*&lt;/code&gt; altına bağlanıyor&lt;/td&gt;
&lt;td&gt;Canlı &lt;code&gt;/var&lt;/code&gt;'ın üstüne taze bir dosya sistemi bağlamak önce bir veri taşıma ister; lab, makineyi güvenli bağlama noktalarında kanıtlıyor, production veri taşımasıyla uyguluyor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Boyutlar tfvars parametresi&lt;/td&gt;
&lt;td&gt;Golden template her VM için sade ve aynı kalıyor; VM başına boyutlar iş yükü parametresi; tam olarak Faz 4'ün istek formunun dolduracağı şey&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Bu yerleşimin bir özelliği erkenden içselleştirilmeye değer, çünkü bütün bir endişe sınıfını ortadan kaldırıyor: tasarım sadece büyümeyi destekliyor ve bu bir eksiklik değil, bilinçli bir tasarım tercihi. Provider küçültmeyi reddediyor, XFS bir dosya sistemini küçültemiyor, playbook &lt;code&gt;lvol&lt;/code&gt;'ü &lt;code&gt;shrink: false&lt;/code&gt; ile çalıştırıyor ki hiç denemesin. Bir volüm gerçekten küçülmek zorundaysa doğru ve sağlıklı yöntem doğru boyutta yeni bir disk artı bir veri taşıma; yerinde yapılan bir göz boyama değil, planlı bir göç.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform: dört diski tanımlamak
&lt;/h2&gt;

&lt;p&gt;Faz 2'nin Terraform tarafı tek bir kavramın dört kez uygulanması: serial'li bir disk bloğu. Aşağıdaki ek, vm.tf'e Faz 1'in mevcut scsi0 OS disk bloğunun hemen ardına giriyor. Neyin eksik olduğuna dikkat: provider'a özel geçici çözüm yok, ignore yok, lifecycle bloğu yok. Kimlik şeması, hipervizöre olduğu gibi geçen bir string özniteliğinden fazlasını istemiyor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
  &lt;span class="nx"&gt;interface&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scsi1"&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;var_disk_size_gb&lt;/span&gt;
  &lt;span class="nx"&gt;serial&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"var01"&lt;/span&gt;
  &lt;span class="nx"&gt;ssd&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;discard&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"on"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
  &lt;span class="nx"&gt;interface&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scsi2"&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log_disk_size_gb&lt;/span&gt;
  &lt;span class="nx"&gt;serial&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"log01"&lt;/span&gt;
  &lt;span class="nx"&gt;ssd&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;discard&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"on"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
  &lt;span class="nx"&gt;interface&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scsi3"&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data_disk_size_gb&lt;/span&gt;
  &lt;span class="nx"&gt;serial&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"data01"&lt;/span&gt;
  &lt;span class="nx"&gt;ssd&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;discard&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"on"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
  &lt;span class="nx"&gt;interface&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scsi4"&lt;/span&gt;
  &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backup_disk_size_gb&lt;/span&gt;
  &lt;span class="nx"&gt;serial&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"backup01"&lt;/span&gt;
  &lt;span class="nx"&gt;ssd&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;discard&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"on"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ssd&lt;/code&gt; ve &lt;code&gt;discard&lt;/code&gt; bayrakları OS diskiyle birebir aynı, ki beş disk NFS backend'inde aynı şekilde davransın: SSD emülasyonu guest'in TRIM göndermesine izin veriyor, &lt;code&gt;discard on&lt;/code&gt; paylaşımda thin provisioning'in doğru ve sağlıklı çalışmasını sağlıyor. Arayüzler açıkça sabitlenmiş, scsi1'den scsi4'e; çünkü provider, state ile gerçeği eşleştirirken diskleri tam olarak arayüzden okuyor; sabit bir pin, diff'i temiz tutuyor.&lt;/p&gt;

&lt;p&gt;Boyutlar, hepsi varsayılanlı dört yeni değişkenden geliyor; mevcut bir tfvars dosyasını kırmayan da tam bu: hiçbir satır değişmeden çalışmaya devam ediyor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# terraform.tfvars.example (Faz 2 eki)&lt;/span&gt;
var_disk_size_gb    &lt;span class="o"&gt;=&lt;/span&gt; 10  &lt;span class="c"&gt;# scsi1 serial=var01    -&amp;gt; /srv/var&lt;/span&gt;
log_disk_size_gb    &lt;span class="o"&gt;=&lt;/span&gt; 10  &lt;span class="c"&gt;# scsi2 serial=log01    -&amp;gt; /srv/log&lt;/span&gt;
data_disk_size_gb   &lt;span class="o"&gt;=&lt;/span&gt; 20  &lt;span class="c"&gt;# scsi3 serial=data01   -&amp;gt; /srv/data (büyütme demosu)&lt;/span&gt;
backup_disk_size_gb &lt;span class="o"&gt;=&lt;/span&gt; 15  &lt;span class="c"&gt;# scsi4 serial=backup01 -&amp;gt; /srv/backup&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Değişken&lt;/th&gt;
&lt;th&gt;Varsayılan&lt;/th&gt;
&lt;th&gt;Serial&lt;/th&gt;
&lt;th&gt;Bağlama noktası&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;var_disk_size_gb&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;var01&lt;/td&gt;
&lt;td&gt;/srv/var&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;log_disk_size_gb&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;log01&lt;/td&gt;
&lt;td&gt;/srv/log&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;data_disk_size_gb&lt;/td&gt;
&lt;td&gt;20 (demoda 30'a çıkıyor)&lt;/td&gt;
&lt;td&gt;data01&lt;/td&gt;
&lt;td&gt;/srv/data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;backup_disk_size_gb&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;backup01&lt;/td&gt;
&lt;td&gt;/srv/backup&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Repo güncellenince, mevcut Faz 1 state'ine karşı çekilen plan bir yerinde güncelleme gösteriyor, bir yer değiştirme değil. Bu, üçüncü bölümdeki ForceNew-yok kanıtının gerçek çıktıda görünür olduğu an ve dikkatle okunmaya değer: plan tam olarak bir kaynağın değiştiğini, sıfır kaynağın yok edildiğini göstermeli.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~ resource "proxmox_virtual_environment_vm" "test_vm" {
    ~ agent { enabled = true }
    ~ disk {
        ~ serial = "data01" -&amp;gt; (known after apply)
        # (5 değişmeyen öznitelik gizlendi)
      }
    + disk {
        + datastore_id = "nfs-shared"
        + interface    = "scsi1"
        + serial       = "var01"
        + size         = 10
      }
    + disk { ... scsi2, serial "log01", size 10 ... }
    + disk { ... scsi3, serial "data01", size 20 ... }
    + disk { ... scsi4, serial "backup01", size 15 ... }
  }

Plan: 0 to add, 1 to change, 0 to destroy.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Diff'in tam görünümü provider sürümüne göre değişiyor ama özet satır sözleşmenin ta kendisi: 0 to add, 1 to change, 0 to destroy. Bir plan bir boyut düzenlemesinden sonra VM'in yeniden oluşturulacağını gösterirse dur ve &lt;code&gt;yes&lt;/code&gt; yazmadan önce diff'i oku; bu tasarımda yeniden oluşturmanın tek meşru sebepleri VMID ya da klon kaynağı gibi kimlik özniteliklerinin değişmesi, asla bir disk boyutu değil.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply: disk, VM çalışırken beliriyor
&lt;/h2&gt;

&lt;p&gt;Disk eklemesini apply etmek tasarım gereği sıradan: provider, VM konfigürasyonunu API üzerinden güncelliyor, NFS datastore'da dört disk dosyası oluşturuyor, çalışan VM de hotplug ile dört yeni virtio-scsi aygıtı görüyor. Zamanlanacak bir kesinti penceresi yok, açılacak bir konsol yok; tüm operasyon NFS'te disk başına saniyeler sürüyor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/terraform# terraform apply
proxmox_virtual_environment_vm.test_vm: Modifying... &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;200]
proxmox_virtual_environment_vm.test_vm: Modifications &lt;span class="nb"&gt;complete &lt;/span&gt;after 12s

Apply &lt;span class="nb"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; Resources: 0 added, 1 changed, 0 destroyed.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu akıştaki tek kritik nokta saha testinde ortaya çıktı ve baş ağrıtmadan önce bilinmesinde fayda var. API diskleri takılı olarak raporluyor, &lt;code&gt;qm config&lt;/code&gt; serial'leri gösteriyor; ama serial hotplug edilebilen bir özellik değil: disk'ler VM zaten çalışırken eklendiğinde, saklanan konfigürasyon serial'leri taşıyor ama çalışan QEMU süreci taşımıyor, bu yüzden guest kernel'i boş serial'ler raporluyor. Düzeltme node üzerinden tam bir durdur-başlat: &lt;code&gt;qm shutdown 200 &amp;amp;&amp;amp; qm start 200&lt;/code&gt;. Guest içindeki bir reboot QEMU'yu yeniden başlatmıyor. Sonraki bölümdeki playbook'un assert'i tam bu durumu iki ihtimalli net bir teşhis mesajıyla yakalıyor; hata bu yüzden gizemli değil, gayet anlaşılır.&lt;/p&gt;

&lt;h3&gt;
  
  
  İki taraftan doğrulama
&lt;/h3&gt;

&lt;p&gt;Bu seride her yerde olduğu gibi bir iddia, ancak arkasındaki kanıt ve somut çıktı kadar geçerlidir. Diskler artık hipervizör sınırının iki tarafında da var ve üç komut zincirin tamamını kapsıyor; hepsi de Ansible adımı bir şeye dokunmadan önce aynı dört serial'de hemfikir olmalı. İlk ikisi bir PVE node'unda çalışıp hipervizörün gördüğü durumu, hem saklanan konfigürasyonda hem gerçekten çalışan QEMU sürecinde gösteriyor; sonuncusu guest içinde çalışıp kernel'in gerçekten ne gördüğünü gösteriyor. Bu, saha hatasını dakikalar içinde izole eden komut seti.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fazv18pk1ay942q1npwd5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fazv18pk1ay942q1npwd5.png" alt="WebUI Üzerinden Görünümü" width="800" height="234"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# pve-a'da: saklanan konfigürasyon serial'leri taşıyor...&lt;/span&gt;
root@pve-a:~# qm config 200 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"scsi[1-4]:"&lt;/span&gt;
scsi1: nfs-shared:vm-200-disk-0,size&lt;span class="o"&gt;=&lt;/span&gt;10,serial&lt;span class="o"&gt;=&lt;/span&gt;var01,ssd&lt;span class="o"&gt;=&lt;/span&gt;1,discard&lt;span class="o"&gt;=&lt;/span&gt;on
scsi2: nfs-shared:vm-200-disk-1,size&lt;span class="o"&gt;=&lt;/span&gt;10,serial&lt;span class="o"&gt;=&lt;/span&gt;log01,ssd&lt;span class="o"&gt;=&lt;/span&gt;1,discard&lt;span class="o"&gt;=&lt;/span&gt;on
scsi3: nfs-shared:vm-200-disk-2,size&lt;span class="o"&gt;=&lt;/span&gt;20,serial&lt;span class="o"&gt;=&lt;/span&gt;data01,ssd&lt;span class="o"&gt;=&lt;/span&gt;1,discard&lt;span class="o"&gt;=&lt;/span&gt;on
scsi4: nfs-shared:vm-200-disk-3,size&lt;span class="o"&gt;=&lt;/span&gt;15,serial&lt;span class="o"&gt;=&lt;/span&gt;backup01,ssd&lt;span class="o"&gt;=&lt;/span&gt;1,discard&lt;span class="o"&gt;=&lt;/span&gt;on

&lt;span class="c"&gt;# ...çalışan QEMU süreci de öyle:&lt;/span&gt;
root@pve-a:~# qm showcmd 200 &lt;span class="nt"&gt;--pretty&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"serial=[a-z0-9]*"&lt;/span&gt;
&lt;span class="nv"&gt;serial&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;var01
&lt;span class="nv"&gt;serial&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;log01
&lt;span class="nv"&gt;serial&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;data01
&lt;span class="nv"&gt;serial&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backup01

&lt;span class="c"&gt;# guest içinde: kernel her serial'i kendi görüşünde raporluyor&lt;/span&gt;
ubuntu@vm-test-01:~&lt;span class="nv"&gt;$ &lt;/span&gt;lsblk &lt;span class="nt"&gt;-o&lt;/span&gt; NAME,SIZE,TYPE,SERIAL
NAME SIZE TYPE SERIAL
sda  10G  disk drive-scsi0   &amp;lt;- OS diski: QEMU&lt;span class="s1"&gt;'nun varsayılan kimliği, serial yok
sdb  15G  disk backup01
sdc  20G  disk data01
sdd  10G  disk log01
sde  10G  disk var01

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu çıktıda üç ayrıntı dikkati hak ediyor. OS diski &lt;code&gt;drive-scsi0&lt;/code&gt; gösteriyor, QEMU'nun serial'siz yapılandırılmış bir disk için varsayılan tanımlayıcısı; zararsız çünkü bu tasarımda hiçbir şey OS diskini serial'le adreslemiyor. Disk dosyası numaralandırması kasıtlı biçimde tedirgin edici görünüyor: OS diski &lt;code&gt;vm-200-disk-0.qcow2&lt;/code&gt; iken dört ham veri diski &lt;code&gt;vm-200-disk-0&lt;/code&gt;'dan &lt;code&gt;vm-200-disk-3&lt;/code&gt;'e uzanıyor. Yani depolama tahsis mekanizması (storage allocator), farklı dosya uzantıları arasında indeksleri yeniden kullanmış; bir hata gibi görünüyor, aslında bir uygulama detayı, disk sayısı da boyutlar da serial'ler de doğru. Ve &lt;code&gt;/dev/disk/by-id&lt;/code&gt;'nin &lt;code&gt;lsblk&lt;/code&gt; çıktısını yansıtmasını beklemeyin: bu Ubuntu 26.04 guest'inde o dizin serial-adlı hiçbir girdi hiç oluşturmadı; playbook'un kernel görüşünü okumasının sebebi tam da bu.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rebuild dolambacı: önce başarısız olan apply
&lt;/h3&gt;

&lt;p&gt;Saha oturumu çalışan bir Faz 1 VM'inden başlamadı. Lab'ı sıfıra indirerek başladı: eski repo dizini silindi, eski VM'ler yok edildi, repo ctrl-01'de yeniden açıldı, &lt;code&gt;terraform init&lt;/code&gt; boş bir state'ten başladı. Temizlikten bir nesne kaçtı: Faz 1'in golden template'i, VMID 9000, hâlâ pve-a'da duruyordu ve oturumun ilk apply'ı ona çarpıp başarısız oldu. Hata bir dönüştürme sorunu gibi görünüyor; asıl sorun iki adım önce, oluşturma anında yaşandı ve sıra dikkatle okunmaya değer, çünkü geride kalan her nesne senaryosunda benzer durum yaşanır.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/terraform# terraform apply
proxmox_virtual_environment_vm.ubuntu_template: Creating...
proxmox_virtual_environment_vm.ubuntu_template: Still creating...
╷
│ Error: VM convert to template failed
│ ... can&lt;span class="s1"&gt;'t convert a template to a template ...
╵
# apply #1 burada durdu; template kaynağı state'&lt;/span&gt;te kaldı, tainted işaretlendi

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mekanizma, sonradan provider kaynağından doğrulandı: create çağrısı PVE'nin "VM 9000 already exists" hatasına çarptı; provider'ın retry yardımcısı bu spesifik hatayı zaten-tamamlanmış-başarı olarak ele alıyor (vms.go, &lt;code&gt;ErrorContains("already exists")&lt;/code&gt; etrafındaki &lt;code&gt;WithAlreadyDoneCheck&lt;/code&gt;). Oluşturma bu yüzden "başarılı" oldu, imaj içe aktarma ve disk boyutlandırma geride kalan template'e karşı çalıştı, uyuşmazlık ancak son dönüştürme adımında ortaya çıktı: PVE bir template'i template'e dönüştürmeyi reddetti. Durumu olduğundan daha vahim gösteren beklenmedik bir ayrıntı daha var: provider, VM oluşturulduktan hemen sonra kaynak ID'sini yazıyor, yani başarısız apply template kaynağını state'te mevcut ve tainted bırakıyor; bunu hiç kurtarırken görmemiş birine tamamen kurtarılamaz görünen bir durum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/terraform# terraform apply
Note: Objects have changed outside of Terraform since the last
&lt;span class="s2"&gt;"terraform apply"&lt;/span&gt; ... the following changes ... has been deleted
- ...
proxmox_virtual_environment_vm.ubuntu_template: Creating...
proxmox_virtual_environment_vm.ubuntu_template: Creation &lt;span class="nb"&gt;complete &lt;/span&gt;after 10s
proxmox_virtual_environment_vm.test_vm: Creating...
proxmox_virtual_environment_vm.test_vm: Creation &lt;span class="nb"&gt;complete &lt;/span&gt;after 5s

Apply &lt;span class="nb"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; Resources: 2 added ...
&lt;span class="c"&gt;# template: ~10 sn; test_vm: ~5 sn; ikinci denemede ikisi de temiz kuruldu&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kurtarma hiçbir elle state ameliyatı istemedi ve asıl ders bu: apply'ı yeniden çalıştırmak geçerli bir ilk tepki. Refresh, state ile gerçeğin anlaşmadığını fark etti, Terraform dışında nesnelerin değiştiğine dair tanıdık notu bastı, geride kalan girdiyi temizledi, iki kaynağı da temiz yeniden kurdu: template'i on saniyede, VM'i beş saniyede. Bu hikâyeden iki alışkanlık çıkıyor: bir lab'ı söküyorsan template'i de yok et, bu temizliğin unuttuğu tek nesne o, node üzerinde &lt;code&gt;qm destroy 9000&lt;/code&gt; onu kaldırıyor. Ve bir apply geride kalmış bir şeye çarpıp düşerse, hatayı oku, sonra &lt;code&gt;terraform state&lt;/code&gt; komutlarına uzanmadan önce tekrar apply et; provider'ın okuma yolu tam bu durumu yakınsatmak için inşa edilmiş.&lt;/p&gt;

&lt;p&gt;Rebuild'in bir sonucu daha vardı, tam bir sonraki komutu karşılıyor: yeni VM taze host anahtarları üretti, ctrl-01'deki known_hosts hâlâ eski makineyi hatırlıyor ve SSH bağlantıyı yüksek sesle reddediyor. Bu her klonlanan VM'in her rebuild'inde beklenen bir şey, uyarı özelliğin ta kendisi, düzeltmesi tek komut:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# ssh ubuntu@192.168.122.50
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
...
root@ctrl-01:~# ssh-keygen &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.ssh/known_hosts &lt;span class="nt"&gt;-R&lt;/span&gt; 192.168.122.50
&lt;span class="c"&gt;# Host 192.168.122.50 found: line 2&lt;/span&gt;
192.168.122.50 Host key removed.
root@ctrl-01:~# ssh ubuntu@192.168.122.50  &lt;span class="c"&gt;# yeni anahtarı kabul et&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Faz 1'i yazarken bu sahneye "bunu sonradan öğrendim" diye not düşmüştüm; söz burada tutuldu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ansible storage playbook'u
&lt;/h2&gt;

&lt;p&gt;Faz 1 tamamen builtin modüllerle çalışmıştı; Faz 2, pipeline'ın ilk gerçek bağımlılığını kazandığı yer. LVM ve mount yönetimi community collection'larında yaşıyor, repo artık bunları bir requirements dosyasında sabitliyor ki kontrol düğümü repodan tek başına yeniden üretilebilsin. Kurulum ctrl-01'de tek komut, bu fazın getirdiği tek yeni ön koşul da bu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ansible/requirements.yml&lt;/span&gt;
&lt;span class="na"&gt;collections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;community.general&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://galaxy.ansible.com&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ansible.posix&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://galaxy.ansible.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/ansible# ansible-galaxy collection &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.yml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playbook'un kendisi bir ekran değişken, bir ekran görev ve şekli üçüncü bölümdeki kimlik zincirini izliyor: önce çöz, sonra kur, sonra bağla. Değişkenler dört diskin tüm istenen durumunu tek yerde bildiriyor; lab'a ileride beşinci bir disk eklemek bu yüzden bir tfvars satırı, bir vm.tf bloğu ve bu listeye bir girdi kadar basit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# playbooks/02_storage.yml (data_disks sözleşmesi)&lt;/span&gt;
&lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;data_disks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;serial&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;var01&lt;/span&gt; &lt;span class="c1"&gt;# scsi1, boyut: var_disk_size_gb&lt;/span&gt;
      &lt;span class="na"&gt;vg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vg_var&lt;/span&gt;
      &lt;span class="na"&gt;lv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lv_var&lt;/span&gt;
      &lt;span class="na"&gt;mount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/srv/var&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;serial&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;log01&lt;/span&gt; &lt;span class="c1"&gt;# scsi2, boyut: log_disk_size_gb&lt;/span&gt;
      &lt;span class="na"&gt;vg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vg_log&lt;/span&gt;
      &lt;span class="na"&gt;lv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lv_log&lt;/span&gt;
      &lt;span class="na"&gt;mount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/srv/log&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;serial&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;data01&lt;/span&gt; &lt;span class="c1"&gt;# scsi3, boyut: data_disk_size_gb&lt;/span&gt;
      &lt;span class="na"&gt;vg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vg_data&lt;/span&gt;
      &lt;span class="na"&gt;lv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lv_data&lt;/span&gt;
      &lt;span class="na"&gt;mount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/srv/data&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;serial&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;backup01&lt;/span&gt; &lt;span class="c1"&gt;# scsi4, boyut: backup_disk_size_gb&lt;/span&gt;
      &lt;span class="na"&gt;vg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vg_backup&lt;/span&gt;
      &lt;span class="na"&gt;lv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lv_backup&lt;/span&gt;
      &lt;span class="na"&gt;mount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/srv/backup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Çözümleme önce geliyor, çünkü sonraki her görev bir diski kendi çözülmüş yolundan adresliyor ve saha testi bu çözümlemenin nereden okuyacağına karar verdi. İlk sürüm bir &lt;code&gt;find&lt;/code&gt; görevi ile &lt;code&gt;/dev/disk/by-id&lt;/code&gt;'yi dolaşıyordu; Ubuntu 26.04 guest'i serial symlink'lerini orada hiç oluşturmadı, bu yüzden v2 doğrudan kernel'e soruyor: tek bir &lt;code&gt;lsblk -J&lt;/code&gt; çağrısı her blok aygıt için NAME, TYPE ve SERIAL'i yakalıyor, bir &lt;code&gt;set_fact&lt;/code&gt; bu JSON'dan serial-den-diske haritayı kuruyor, bir debug görevi haritayı yazdırıyor ki çalıştırma log'u her serial'in hangi aygıta dönüştüğünü göstersin, ve bir assert bir serial tam olarak bir diskten başka bir şeye çözülürse açıkça hata fırlatıp işlemi durduruyor. Bu assert hem beşinci bölümdeki taze-QEMU durumuna hem klasik bir yazım hatasına karşı bir bekçi; hata mesajı ise karmaşık bir stack trace yerine iki ihtimalli net bir teşhis taşıyor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read the kernel serial view of all disks&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lsblk -J -o NAME,TYPE,SERIAL&lt;/span&gt;
  &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lsblk_serials&lt;/span&gt;
  &lt;span class="na"&gt;changed_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Map every serial to its disk(s) (kernel view)&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.set_fact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;serial_map&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
      &lt;span class="s"&gt;{{ serial_map | default({}) | combine({&lt;/span&gt;
        &lt;span class="s"&gt;item: (lsblk_serials.stdout | from_json).blockdevices&lt;/span&gt;
          &lt;span class="s"&gt;| selectattr('type', 'equalto', 'disk')&lt;/span&gt;
          &lt;span class="s"&gt;| selectattr('serial', 'equalto', item)&lt;/span&gt;
          &lt;span class="s"&gt;| map(attribute='name') | list&lt;/span&gt;
      &lt;span class="s"&gt;}) }}&lt;/span&gt;
  &lt;span class="na"&gt;loop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;data_disks&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;map(attribute='serial')&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;|&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;list&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Every serial must resolve to exactly one disk&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.assert&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;that&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;serial_map[item.serial] | default([]) | length == &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;fail_msg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
      &lt;span class="s"&gt;Expected exactly one disk with serial {{ item.serial }}, found&lt;/span&gt;
      &lt;span class="s"&gt;{{ serial_map[item.serial] | default([]) | length }}. Diagnose in&lt;/span&gt;
      &lt;span class="s"&gt;the guest with lsblk -o NAME,SIZE,SERIAL. (a) Empty serials there&lt;/span&gt;
      &lt;span class="s"&gt;mean the running QEMU predates the config: check qm config, then&lt;/span&gt;
      &lt;span class="s"&gt;fully stop and start the VM; a guest reboot does NOT restart&lt;/span&gt;
      &lt;span class="s"&gt;QEMU. (b) If lsblk shows the serial, compare against vm.tf.&lt;/span&gt;
  &lt;span class="na"&gt;loop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;data_disks&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu yeniden yazım teorik değildi: ilk sürüm sahada tam olarak by-id'nin boş olduğu yerde başarısız oldu ve o başarısızlığın şekli, onu izole eden komutlarla birlikte saklamaya değer, çünkü "playbook, hipervizörün orada olduğuna yemin ettiği şeyi göremiyor" durumunun genel reçetesi bu: saklanan konfigürasyonu kontrol et, çalışan süreci kontrol et, kernel'i kontrol et, ilk anlaşmayan görüş sorunu adlandırsın.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
TASK &lt;span class="o"&gt;[&lt;/span&gt;Every serial must resolve to exactly one disk] &lt;span class="k"&gt;**************&lt;/span&gt;
fatal: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]: FAILED! &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;var01&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"Expected exactly one disk with serial var01, found 0. ..."&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
... &lt;span class="o"&gt;(&lt;/span&gt;log01, data01, backup01: aynı şekil, found 0&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# izolasyon, dakikalar sonra (VM'in tam durdur/başlat'ından sonra):&lt;/span&gt;
&lt;span class="c"&gt;# pve-a'da: qm config 200 | grep serial -&amp;gt; dört serial de mevcut&lt;/span&gt;
&lt;span class="c"&gt;# pve-a'da: qm showcmd 200 | grep serial -&amp;gt; çalışan QEMU'da da var&lt;/span&gt;
&lt;span class="c"&gt;# guest'te: lsblk -o NAME,SIZE,SERIAL -&amp;gt; dört serial de mevcut&lt;/span&gt;
&lt;span class="c"&gt;# guest'te: ls /dev/disk/by-id -&amp;gt; 10 girdi, hiçbiri serial-adlı değil&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eşleşme kurulduktan sonraki inşa zinciri dört görevden oluşuyor ve modül işleyişi varsayımlarla değil, doğrudan community.general kaynak kodundan incelenerek kurgulandı. &lt;code&gt;fstype: lvm&lt;/code&gt; ile &lt;code&gt;filesystem&lt;/code&gt; modülü oluşturmayı &lt;code&gt;pvcreate&lt;/code&gt;'e, büyütmeyi &lt;code&gt;pvresize&lt;/code&gt;'a eşliyor; &lt;code&gt;lvg&lt;/code&gt; modülü gerekirse &lt;code&gt;pvcreate&lt;/code&gt;'i kendisi çalıştırıp volume group'u kuruyor; &lt;code&gt;size: 100%VG&lt;/code&gt; ile &lt;code&gt;lvol&lt;/code&gt; modülü LV hedefini VG'nin tamamı olarak hesaplıyor, ilk çalıştırmada LV'yi kuruyor, VG her büyüdüğünde &lt;code&gt;lvextend --resizefs&lt;/code&gt; çağırıyor; bu da XFS için online &lt;code&gt;xfs_growfs&lt;/code&gt;'i tetikliyor. &lt;code&gt;shrink&lt;/code&gt; bayrağı sadece-büyüme mantığıyla eşleşsin diye &lt;code&gt;false&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create/resize physical volumes&lt;/span&gt;
  &lt;span class="na"&gt;community.general.filesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fstype&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lvm&lt;/span&gt;
    &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;disk_map[item.serial]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;resizefs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# ilk çalıştırmada pvcreate, her çalıştırmada pvresize&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create volume groups (one per disk)&lt;/span&gt;
  &lt;span class="na"&gt;community.general.lvg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.vg&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;pvs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;disk_map[item.serial]&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create/extend logical volumes at 100 percent of their VG&lt;/span&gt;
  &lt;span class="na"&gt;community.general.lvol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.vg&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;lv&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.lv&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;100%VG&lt;/span&gt; &lt;span class="c1"&gt;# LV her zaman VG'sine eşit&lt;/span&gt;
    &lt;span class="na"&gt;resizefs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# lvextend --resizefs -&amp;gt; xfs_growfs&lt;/span&gt;
    &lt;span class="na"&gt;shrink&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="c1"&gt;# sadece büyüme, tasarım gereği&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create XFS filesystems&lt;/span&gt;
  &lt;span class="na"&gt;community.general.filesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fstype&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xfs&lt;/span&gt;
    &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dev/{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.vg&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.lv&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Mount filesystems and persist in fstab&lt;/span&gt;
  &lt;span class="na"&gt;ansible.posix.mount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.mount&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/dev/{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.vg&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.lv&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;fstype&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xfs&lt;/span&gt;
    &lt;span class="na"&gt;opts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;defaults,noatime&lt;/span&gt;
    &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mounted&lt;/span&gt; &lt;span class="c1"&gt;# hem şimdi bağla HEM fstab'a yaz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu zincirde iki ayrıntı dikkati hak ediyor. Mount görevi &lt;code&gt;state: mounted&lt;/code&gt; kullanıyor, bu hem hemen bağlıyor hem fstab girdisini yazıyor; playbook, düzen bir reboot'u atlatana kadar bitmiş sayılmıyor. Ve disk'in tamamı, partition tablosu olmadan LVM'e bir PV olarak veriliyor; bu modern disk-başına-tek-LV kalıbı ve resize zincirinden &lt;code&gt;growpart&lt;/code&gt; adımını tamamen kaldırıyor. Genişletilecek bir partition yok, çünkü partition yok.&lt;/p&gt;

&lt;p&gt;Son olarak, &lt;code&gt;pre_tasks&lt;/code&gt; bloğu her şeyden önce &lt;code&gt;lvm2&lt;/code&gt; ve &lt;code&gt;xfsprogs&lt;/code&gt;'u kuruyor, çünkü Ubuntu cloud imajları ikisiyle de gelmiyor. Bu, Faz 1'deki eksik guest agent'la aynı sınıftan bir ders: cloud imajları bilinçli olarak minimal, iş yükünün taban sistemin ötesinde ihtiyaç duyduğu her şey pipeline'ın işi oluyor. Bu adımı unutmak, filesystem modülünün &lt;code&gt;pvcreate&lt;/code&gt;'i bulamadığı kafa karıştırıcı bir erken hatayla sonuçlanıyor; pre_task bağımlılığı açık ve idempotent hale getiriyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  İlk çalıştırma ve doğrulama
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sıfırıncı adım: taze VM'de guest agent yok
&lt;/h3&gt;

&lt;p&gt;Sıralama kuralları neyin önce çalışacağını belirliyor ve saha oturumu bunu bir başarısızlıktan değil bir uyarıdan öğrendi. Taze klonlanmış bir VM'de QEMU guest agent yok; Faz 1'in &lt;code&gt;01_first_contact.yml&lt;/code&gt;'i onu kuran adım. Agent bu fazda özellikle önemli, çünkü beşinci bölümdeki teşhis durdur-başlat'ı temiz bir kapanış istiyor ve PVE, agent'ı olan bir VM'i onun üzerinden kapatıyor. Aşağıdaki uyarı, aynı komutun agent yokken neye benzediği; zararsız ama sıralamayı adlandırıyor: önce ilk temas, sonra depolama.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# qm shutdown 200
warning: QEMU Guest Agent is not running
&lt;span class="c"&gt;# kapatma yine de başarılı; agent olmadan guest-farkında değil, düz bir ACPI kapatma&lt;/span&gt;

root@pve-a:~# qm start 200

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rebuild edilmiş VM'de ilk temas playbook'unun tekrar çalıştırılması, Faz 1'in taze bir makine için belgelediği doğrulama çıktısının aynısıyla sonuçlandı, aynı sebeple: agent paketi kuruluyor (changed), postinst'i servisi zaten başlatmış oluyor (bu yüzden service görevi &lt;code&gt;ok&lt;/code&gt; okuyor), yönetilen damga yazılıyor (changed). Aynı sayılar, yeni makine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/01_first_contact.yml
TASK &lt;span class="o"&gt;[&lt;/span&gt;Install QEMU guest agent] &lt;span class="k"&gt;*********************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Enable and start the guest agent] &lt;span class="k"&gt;*************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Mark the VM as managed by this pipeline] &lt;span class="k"&gt;*******************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]

PLAY RECAP &lt;span class="k"&gt;******************************************************&lt;/span&gt;
vm-test-01 : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="c"&gt;# taze klon doğrulandı: Ubuntu 26.04, kernel 7.0.0-30-generic&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  İlk çalıştırma
&lt;/h3&gt;

&lt;p&gt;Agent yerindeyken storage playbook'u ilk kez çalıştırılıyor ve değişiklik yapan tek çalıştırma bu: sonrasında playbook'taki her görev ya no-op, ya kozmetik bir kontrol ya da bir büyütme adımı. Saha testinde recap beş changed görev gösterdi; dört tam dosya sistemi yığınını çıplak disklerden inşa etmenin görünüşü bu. Araç pre_task'ı &lt;code&gt;ok&lt;/code&gt;'a indi çünkü daha önce yarım kalmış bir deneme &lt;code&gt;lvm2&lt;/code&gt; ve &lt;code&gt;xfsprogs&lt;/code&gt;'u zaten kurmuştu; bakir bir VM'de o görev de değişiyor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
PLAY &lt;span class="o"&gt;[&lt;/span&gt;Storage - LVM and XFS on serial-tagged data disks] &lt;span class="k"&gt;**********&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Show the serial to device mapping &lt;span class="o"&gt;(&lt;/span&gt;the guessing game this replaces&lt;span class="o"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;***&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;var01&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"var01 (vg_var/lv_var -&amp;gt; /srv/var) = /dev/sde"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;log01&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"log01 (vg_log/lv_log -&amp;gt; /srv/log) = /dev/sdd"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;data01&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"data01 (vg_data/lv_data -&amp;gt; /srv/data) = /dev/sdc"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backup01&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"backup01 (vg_backup/lv_backup -&amp;gt; /srv/backup) = /dev/sdb"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Every serial must resolve to exactly one disk] &lt;span class="k"&gt;**************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;var01&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"All assertions passed"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
... &lt;span class="o"&gt;(&lt;/span&gt;3 tane daha, hepsi geçti&lt;span class="o"&gt;)&lt;/span&gt; ...

TASK &lt;span class="o"&gt;[&lt;/span&gt;Create/resize physical volumes] &lt;span class="k"&gt;****************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;var01&lt;span class="o"&gt;)&lt;/span&gt; ... &lt;span class="o"&gt;(&lt;/span&gt;3 tane daha&lt;span class="o"&gt;)&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Create volume &lt;span class="nb"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;one per disk&lt;span class="o"&gt;)]&lt;/span&gt; &lt;span class="k"&gt;***********************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vg_var&lt;span class="o"&gt;)&lt;/span&gt; ... &lt;span class="o"&gt;(&lt;/span&gt;3 tane daha&lt;span class="o"&gt;)&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Create/extend logical volumes at 100 percent of their VG] &lt;span class="k"&gt;***&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vg_var/lv_var&lt;span class="o"&gt;)&lt;/span&gt; ... &lt;span class="o"&gt;(&lt;/span&gt;3 tane daha&lt;span class="o"&gt;)&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Create XFS filesystems] &lt;span class="k"&gt;************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/dev/vg_var/lv_var&lt;span class="o"&gt;)&lt;/span&gt; ... &lt;span class="o"&gt;(&lt;/span&gt;3 tane daha&lt;span class="o"&gt;)&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Mount filesystems and persist &lt;span class="k"&gt;in &lt;/span&gt;fstab] &lt;span class="k"&gt;********************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/srv/var&lt;span class="o"&gt;)&lt;/span&gt; ... &lt;span class="o"&gt;(&lt;/span&gt;3 tane daha&lt;span class="o"&gt;)&lt;/span&gt;

PLAY RECAP &lt;span class="k"&gt;******************************************************&lt;/span&gt;
vm-test-01 : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;14 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eşleştirme bloğunu her şeyden önce okuyun: o dört debug satırı, ikinci bölümdeki tahmin oyununun düz metinde çözülmesi. Her serial, kendi VG/LV çifti, bağlama noktası ve çözülmüş aygıtıyla tek satırda duruyor; bütün bu tasarımın bize kazandırdığı asıl değer bu satır. Bir serial çözülemeseydi, assert karmaşık bir stack trace yerine yönlendirici bir hata mesajıyla süreci tam orada durdururdu.&lt;/p&gt;

&lt;p&gt;Playbook, çalıştırma log'unun bir iddia değil kanıtla bitmesi için iki doğrulama çıktısıyla kapanıyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TASK [Show block devices with serials and mounts] *************
NAME                   SIZE TYPE SERIAL      MOUNTPOINT
sda                    10G disk              / &amp;lt;- OS diski (serial gerekmiyor)
sdb                    15G disk backup01
└─vg_backup-lv_backup  15G lvm               /srv/backup
sdc                    20G disk data01
└─vg_data-lv_data      20G lvm               /srv/data
sdd                    10G disk log01
└─vg_log-lv_log        10G lvm               /srv/log
sde                    10G disk var01
└─vg_var-lv_var        10G lvm               /srv/var

TASK [Show filesystem usage] ************************************
Filesystem                        Size  Used Avail Use% Mounted on
/dev/mapper/vg_var-lv_var          10G  104M   10G   2% /srv/var
/dev/mapper/vg_log-lv_log          10G  104M   10G   2% /srv/log
/dev/mapper/vg_data-lv_data        20G  424M   20G   3% /srv/data
/dev/mapper/vg_backup-lv_backup    15G  145M   15G   1% /srv/backup

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  İdempotans: tekrar çalıştırma
&lt;/h3&gt;

&lt;p&gt;Bu playbook'un sözleşmesi, hiçbir şey değişmediğinde ikinci çalıştırmanın olaysız (sıkıcı) geçmesiydi ve saha testi bu taahhüdü kesin sayılarla doğruladı. PV'ler zaten var, VG'ler zaten onları içeriyor, LV'ler zaten VG'lerine eşit, dosya sistemleri zaten var, bağlamalar zaten fstab'la eşleşiyor; bu yüzden her görev bir tanesi dışında &lt;code&gt;ok&lt;/code&gt;'a iniyor: PV görevi saha testinde yine &lt;code&gt;changed&lt;/code&gt; raporladı, çünkü &lt;code&gt;resizefs: true&lt;/code&gt; ile community.general'in filesystem modülü her çağrıda &lt;code&gt;pvresize&lt;/code&gt;'ı çalıştırıyor ve hiçbir boyut kımıldamasa bile görevi changed işaretliyor. Etki yine idempotent, hiçbir şey büyümüyor ya da yeniden yazılmıyor, ancak recap çıktısındaki gerçekçi beklenti sıfır değil, bir changed görev.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
TASK &lt;span class="o"&gt;[&lt;/span&gt;Create/resize physical volumes] &lt;span class="k"&gt;****************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;var01&lt;span class="o"&gt;)&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;log01&lt;span class="o"&gt;)&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;data01&lt;span class="o"&gt;)&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;backup01&lt;span class="o"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;# pvresize geçişi&lt;/span&gt;
&lt;span class="c"&gt;# diğer her görev: ok&lt;/span&gt;

PLAY RECAP &lt;span class="k"&gt;******************************************************&lt;/span&gt;
vm-test-01 : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;14 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tek hayatta kalan değişiklik &lt;code&gt;pvresize&lt;/code&gt; geçişi: &lt;code&gt;resizefs: true&lt;/code&gt; ile modül onu koşulsuz çalıştırıyor ve hiçbir disk büyümese bile changed raporluyor. Gürültü olarak görün; asıl sinyal hiçbir VG, LV, dosya sistemi ya da mount görevinin değişiklik raporlamaması.&lt;/p&gt;

&lt;h2&gt;
  
  
  Büyütme denemesi: tek düzenleme, sıfır kesinti
&lt;/h2&gt;

&lt;p&gt;Senaryo: &lt;code&gt;/srv/data&lt;/code&gt;, aşağıya inmemesi gereken bir sunucuda dolmaya yaklaşıyor. Eski dünyada bu bir bakım penceresi, doğru hipervizör diskini deneme-yanılmayla bulmak ve beş komutluk ritüel demekti. Burada tek bir değişken düzenlemesi, bir apply ve playbook'un bir kez daha çalıştırılması; VM hiçbir şey fark etmiyor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ctrl-01'de: data_disk_size_gb 20 -&amp;gt; 30, sonra apply&lt;/span&gt;
root@ctrl-01:~/proxmox-automation/terraform# terraform apply
~ resource &lt;span class="s2"&gt;"proxmox_virtual_environment_vm"&lt;/span&gt; &lt;span class="s2"&gt;"test_vm"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    ~ disk &lt;span class="o"&gt;{&lt;/span&gt;
        ~ size &lt;span class="o"&gt;=&lt;/span&gt; 20 -&amp;gt; 30   &lt;span class="c"&gt;# yalnızca scsi3 değişiyor&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

Plan: 0 to add, 2 to change, 0 to destroy.   &lt;span class="c"&gt;# 2. değişiklik: template VM&lt;/span&gt;
...
proxmox_virtual_environment_vm.test_vm: Modifications &lt;span class="nb"&gt;complete &lt;/span&gt;after 1s

Apply &lt;span class="nb"&gt;complete&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; Resources: 0 added, 2 changed, 0 destroyed.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply, VM çalışırken diski API üzerinden büyüttü; guest'teki virtio-scsi katmanı yeni aygıt boyutunu anında aldı. Ama guest içinde henüz hiçbir şey değişmedi: PV hâlâ eski boyutu, LV ve dosya sistemi de onunla birlikte kayıtlı. Disk büyüdü; üstündeki yığın bilmiyor. Playbook'un tekrar çalıştırılması tam olarak bu yüzden gerekiyor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Saha oturumunda bir denemede playbook apply'dan önce çalıştırıldı, &lt;code&gt;df&lt;/code&gt; yine 20G raporladı: playbook yalnızca hipervizörün zaten büyüttüğü boyutu içeriye yansıtabiliyor. Sıra: düzenle, &lt;code&gt;terraform apply&lt;/code&gt;, playbook, doğrulama.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
TASK &lt;span class="o"&gt;[&lt;/span&gt;Create/resize physical volumes] &lt;span class="k"&gt;****************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;data01&lt;span class="o"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;# pvresize büyümeyi gördü&lt;/span&gt;
&lt;span class="c"&gt;# (+ diğerlerinde her çalıştırmada olan rutin kontrol)&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Create/extend logical volumes at 100 percent of their VG] &lt;span class="k"&gt;***&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vg_data/lv_data&lt;span class="o"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;# lvextend --resizefs&lt;/span&gt;

PLAY RECAP &lt;span class="k"&gt;******************************************************&lt;/span&gt;
vm-test-01 : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;14 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# ssh ubuntu@192.168.122.50 &lt;span class="s1"&gt;'df -h /srv/data'&lt;/span&gt;
Filesystem                     Size  Used Avail Use% Mounted on
/dev/mapper/vg_data-lv_data    30G  620M   30G   3% /srv/data

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İki görev değişti, yalnızca biri büyüme anlamına geliyor: LV görevi tam olarak büyüyen tek disk için değişti: &lt;code&gt;lvol&lt;/code&gt;, VG'yi LV'den büyük görünce &lt;code&gt;lvextend&lt;/code&gt;'i &lt;code&gt;--resizefs&lt;/code&gt; ile çağırdı, bu da dosya sistemi bağlıyken online &lt;code&gt;xfs_growfs&lt;/code&gt;'i tetikledi. PV görevi dört diskin hepsinde her çalıştırmadaki alışılmış rutin tetiklemeyi işaretledi. Bu hassasiyet, disk-başına-bir-VG yerleşiminin ödülü: büyüme, serial üzerinden tam olarak doğru yığına yönlendiriliyor, komşusuna hiç dokunmadan. Uptime tüm dizi boyunca hiç değişmedi; disk, bağlı ve kullanımdaki bir XFS dosya sistemi altında 20G'den 30G'ye büyüdü.&lt;/p&gt;

&lt;p&gt;Ters yönü denemek de öğretici, çünkü biri er ya da geç bir diski bu yolla küçültmeyi deneyecek. &lt;code&gt;data_disk_size_gb&lt;/code&gt;'yi 20'ye geri çekip apply etmek, planı provider'ın kendi sözleriyle duvara çarptırıyor: &lt;code&gt;Cannot shrink, it is not supported&lt;/code&gt;. Bu hata bir eksiklik değil, tasarımın kendi işini yapması. Daha küçük bir volume'e giden doğru ve sağlıklı yol; doğru boyutta yeni bir disk, bir veri taşıma ve eskisinin kaldırılmasıdır; yerinde yapılan bir göz boyama değil, kendi prosedürü olan planlı bir göç.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hızlı başvuru: belirti, neden, çözüm
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Belirti&lt;/th&gt;
&lt;th&gt;Neden&lt;/th&gt;
&lt;th&gt;Çözüm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plan, VM'in yok edilip yeniden oluşturulacağını gösteriyor&lt;/td&gt;
&lt;td&gt;Bir kimlik özniteliği değişmiş (VMID, klon kaynağı), disk boyutu değil&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;yes&lt;/code&gt; yazmadan dur, diff'i oku; kimlik özniteliğini geri al, bir boyut düzenlemesi için asla replace'i kabul etme&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply &lt;code&gt;VM convert to template failed ... can't convert a template to a template&lt;/code&gt; hatasıyla sonlanıyor&lt;/td&gt;
&lt;td&gt;Geride kalmış bir nesne zaten VMID 9000'i tutuyor; provider "already exists" içeren bir create hatasını zaten-tamamlanmış sayıyor&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;terraform apply&lt;/code&gt;'ı tekrar çalıştır: refresh geride kalanı temizler ve temiz yeniden kurar; ya da önce node'da &lt;code&gt;qm destroy 9000&lt;/code&gt; ile elle kaldır&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH rebuild sonrası &lt;code&gt;REMOTE HOST IDENTIFICATION HAS CHANGED&lt;/code&gt; uyarısı veriyor&lt;/td&gt;
&lt;td&gt;Rebuild edilen VM taze host anahtarları üretti; ctrl-01 eskisini hatırlıyor&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ssh-keygen -f ~/.ssh/known_hosts -R &amp;lt;ip&amp;gt;&lt;/code&gt;, yeniden bağlan, yeni anahtarı kabul et&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assert başarısız: serial 0 diske çözülüyor, lsblk boş serial gösteriyor&lt;/td&gt;
&lt;td&gt;Çalışan QEMU konfigürasyondan eski: serial'ler çalışan bir sürece hotplug edilemiyor&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;qm config&lt;/code&gt; serial'leri gösteriyorsa, VM'i node'da tam durdur-başlat (&lt;code&gt;qm shutdown&lt;/code&gt; sonra &lt;code&gt;qm start&lt;/code&gt;); guest içi reboot QEMU'yu yeniden başlatmaz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serial'ler lsblk'de görünüyor ama &lt;code&gt;/dev/disk/by-id&lt;/code&gt;'de serial girdisi yok&lt;/td&gt;
&lt;td&gt;Bu Ubuntu 26.04 virtio-scsi guest'i by-id symlink'lerini hiç oluşturmuyor&lt;/td&gt;
&lt;td&gt;Düzeltilecek bir şey yok: playbook kernel görüşünü okuyor; by-id ilk sürümün bağımlılığıydı, artık yok&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;qm shutdown&lt;/code&gt;, &lt;code&gt;QEMU Guest Agent is not running&lt;/code&gt; uyarısı veriyor&lt;/td&gt;
&lt;td&gt;Klon taze, &lt;code&gt;01_first_contact.yml&lt;/code&gt; henüz tekrar çalıştırılmadı, agent yok&lt;/td&gt;
&lt;td&gt;Önce &lt;code&gt;01_first_contact.yml&lt;/code&gt;'i çalıştır; kapatma agent olmadan da çalışır, düz bir ACPI kapatmaya düşer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bir boyut parametresini düzenledikten sonra &lt;code&gt;df&lt;/code&gt; hâlâ eski boyutu gösteriyor&lt;/td&gt;
&lt;td&gt;Playbook, &lt;code&gt;terraform apply&lt;/code&gt; diski büyütmeden önce çalıştı&lt;/td&gt;
&lt;td&gt;Sıra önemli: düzenle, &lt;code&gt;terraform apply&lt;/code&gt;, sonra playbook; yalnızca hipervizörün zaten büyüttüğü boyutu yansıtır&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;lvol&lt;/code&gt; ya da &lt;code&gt;lvg&lt;/code&gt; modülü bulunamıyor&lt;/td&gt;
&lt;td&gt;Collection'lar kontrol düğümüne kurulmamış&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ansible-galaxy collection install -r requirements.yml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filesystem modülü &lt;code&gt;pvcreate&lt;/code&gt;'i arayıp bulamıyor&lt;/td&gt;
&lt;td&gt;Cloud imajında lvm2 yok (pre_task atlanmış ya da kaldırılmış)&lt;/td&gt;
&lt;td&gt;Playbook'u değiştirmeden tekrar çalıştır; pre_task önce lvm2 ve xfsprogs'u kuruyor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apply, &lt;code&gt;Cannot shrink ... not supported&lt;/code&gt; hatası veriyor&lt;/td&gt;
&lt;td&gt;Bir boyut parametresi küçültülmüş&lt;/td&gt;
&lt;td&gt;Tasarım gereği yalnızca büyümeye izin var; volume gerçekten küçülmeli ise yeni disk oluştur ve taşı&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Sırada ne var?
&lt;/h2&gt;

&lt;p&gt;Faz 2 kapanınca, taze sağlanmış bir VM işletim sistemiyle, kimliğiyle, ağıyla ve eksiksiz DB sınıfı bir depolama düzeniyle geliyor; hepsi tek bir apply ve tek bir playbook'tan. Hâlâ eksik olan, orijinal manuel sürecin depolama adımından sonra yavaşlatan her şey: ajanlar. Faz 3, eski template'in &lt;code&gt;/install&lt;/code&gt; dizinini gerçek Ansible rollerine çeviriyor, ajan başına bir tane, her biri idempotent ve konfigürasyon güdümlü: sunucu adresi &lt;code&gt;zabbix_agent2.conf&lt;/code&gt;'a template'lenmiş Zabbix Agent 2, kontrollü kaynaklardan kurulan Trend Micro ve ManageEngine, QRadar'a işaret eden rsyslog forward kuralları.&lt;/p&gt;

&lt;p&gt;Faz 4 sonra son elle dokunma noktasını kaldırıyor: istek formu. Bu rehberde tanıtılan boyutlar zaten sade tfvars parametreleri, yani birer form alanı adayı; bir Semaphore UI pipeline'ı bir form gönderiminden bir workspace tfvars yazabilir, &lt;code&gt;terraform apply&lt;/code&gt;'ı ve iki playbook'u çalıştırabilir, dakikalar içinde tamamen kurulmuş bir sunucu teslim edebilir. Faz 5 pipeline'ı ölçek için sertleştiriyor: IP adreslerinin elle atanmayı bırakması için IPAM, paralellik sınırları ve gerçekliğin bildirilen durumdan saptığını fark etmek için drift tespiti.&lt;/p&gt;

&lt;p&gt;Kat edilen mesafe kendi paragrafını hak ediyor, çünkü tüm seriyi haklı çıkaran ölçüt bu. Bu serinin yerini aldığı süreç günde yirmi ila doksan kez işletiliyordu: konsol-güdümlü klonlama, elle IP konfigürasyonu, ajan başına bir SSH oturumu, elle düzenlenmiş konfigürasyonlar ve bitirmek için bir reboot; bir DB profili söz konusu olduğunda üstüne bir de depolama işi. İki fazdan sonra aynı sonuç, bir kontrol konteynerinden iki komut, her adımı loglanmış, her hata modu belgelenmiş ve her disk kernel'in onu nerede bulduğuyla değil ne olduğuyla adreslenmiş. Kalan fazlar kalıbın tekrarı, yeni bir fikir değil: durumu bildir, o duruma yakınsa (durumu eşitle), doğrulama çıktısıyla teyit et.&lt;/p&gt;

&lt;p&gt;Companion repo, seri boyunca her fazda biraz daha büyüyor:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;a href="https://github.com/Hakanbaban53/proxmox-automation" rel="noopener noreferrer"&gt;Link: GitHub repo; fazlarla eşleşen dizin yapısı, playbook'lar ve Terraform dosyaları&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bu fazı kendi lab'ınızda denerseniz, by-id'nin sizin ortamınızda çalışıp çalışmadığını ve rebuild sonrası geride kalan nesneleri kontrol etmeye değer; ikisi de bu yazıdaki komutlarla dakikalar içinde çözülüyor. Deneyimleriniz ve kendi disk desenleriniz için yorumlarda bekliyorum.&lt;/p&gt;

</description>
      <category>proxmox</category>
      <category>terraform</category>
      <category>ansible</category>
      <category>devops</category>
    </item>
    <item>
      <title>Proxmox'da Sıfır Dokunuşla VM Sağlama: Terraform, cloud-init ve Ansible (Bölüm 1)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Tue, 01 Sep 2026 06:00:52 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/proxmoxda-sifir-dokunusla-vm-saglama-terraform-cloud-init-ve-ansible-bolum-1-1aof</link>
      <guid>https://dev.to/hakanbaban53/proxmoxda-sifir-dokunusla-vm-saglama-terraform-cloud-init-ve-ansible-bolum-1-1aof</guid>
      <description>&lt;p&gt;Bir önceki seride Proxmox VE cluster ve Corosync'i kurmuştuk; üç node (pve-a, pve-b, pve-c), bir QDevice, quorum dersleri, split-brain denemesi ve NFS shared storage ile bitirmiştik.&lt;/p&gt;

&lt;p&gt;O lab hâlâ ayakta ve bu yeni seri tam olarak o lab'ın üzerine kuruluyor. Cluster kısmı bitti; şimdi asıl konu, o cluster'dan verimli VM üretmek.&lt;/p&gt;

&lt;p&gt;Başlangıç noktası hepimizin bildiği o manuel rutin: yeni bir sunucu lazım olur, konsolu açarsın, template'den klonlarsın, IP'yi, maskeyi, ağ geçidini elle yazarsın, her agent kurulumu için ayrı ayrı SSH girersin, bir dosyayı elinle düzenlersin, sonunda reboot atarsın. Günde yirmi kurulumda bu sıkıcı; doksan kurulumda yönetilemez. Bu serinin ilk fazı, o işin en can yakıcı katmanını kaldırıyor: işletim sistemi kurulumunun kendisi. Faz 1'in sonunda elimizde tek komutla çalışan bir pipeline olacak; altın kalıbı (golden template) Terraform kuracak, workload VM'i cloud-init ile klonlayacak ve makineyi Ansible'a devredecek.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hedef: tek komut, üç kaynak
&lt;/h2&gt;

&lt;p&gt;Faz 1'in tamamı aslında şu cümleye indirgenebilir: &lt;code&gt;terraform apply&lt;/code&gt; yazdığımda Proxmox üç kaynak oluşturmalı ve Ansible kalanını halletmeli. Üç kaynak, sırayla şunlar:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ubuntu 26.04 LTS cloud imajının NFS storage'a indirilmesi&lt;/li&gt;
&lt;li&gt;Bu imajdan VMID 9000 numaralı, Terraform tarafından yönetilen altın kalıp&lt;/li&gt;
&lt;li&gt;VMID 200 numaralı, statik IP'li, cloud-init'li tam klon (full clone)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Klon ayağa kalkıp ağa girdikten sonra sıra Ansible'a geçiyor; ilk temas (first contact) playbook'u qemu-guest-agent'ı kuruyor ve VM'e "buradan yönetiliyorsun" damgasını basıyor. Sonrası, ileriki fazların konusu: veri diskleri (Faz 2), monitoring ve güvenlik agent'ları (Faz 3), form tabanlı self-servis akış (Faz 4).&lt;/p&gt;

&lt;p&gt;Kullanılan araçların doğrulanmış sürümleri şöyle; hepsi yazım anında (Ağustos 2026) upstream kaynaklardan kontrol edildi. Güncelliğini yitirmiş tutorial'lar, lab'da boşa geçen saatlerin bir numaralı sebebi:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bileşen&lt;/th&gt;
&lt;th&gt;Sürüm&lt;/th&gt;
&lt;th&gt;Not&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Proxmox VE&lt;/td&gt;
&lt;td&gt;9.2&lt;/td&gt;
&lt;td&gt;8.4 dalı 2026-08-31'te EOL; hard minimum 8.4 (Import içerik türü 8.4'le geldi)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terraform&lt;/td&gt;
&lt;td&gt;1.15.9&lt;/td&gt;
&lt;td&gt;1.16 hâlâ release-candidate aşamasında&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bpg/proxmox provider&lt;/td&gt;
&lt;td&gt;0.111.1&lt;/td&gt;
&lt;td&gt;Eski &lt;code&gt;proxmox_virtual_environment_download_file&lt;/code&gt; adı deprecated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ubuntu imajı&lt;/td&gt;
&lt;td&gt;26.04 LTS (Resolute)&lt;/td&gt;
&lt;td&gt;İki varyant: amd64 ve amd64v3 (x86-64-v3 CPU ister)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ansible-core&lt;/td&gt;
&lt;td&gt;2.20.1&lt;/td&gt;
&lt;td&gt;Ubuntu deposundan; Faz 1 için builtin modüller yeterli&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Ön kontrol: dört kapı, on dakika
&lt;/h2&gt;

&lt;p&gt;İlk &lt;code&gt;apply&lt;/code&gt;'dan önce dört kapıyı geçmek gerekiyor: cluster sürümü, CPU komut seti, NFS storage ve ağ planı. Cluster serisindeki disiplin burada da geçerli: her iddia, komut çıktısıyla kanıtlanır.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# pveversion
pve-manager/9.2.2/b9984c6d90a4bd80 &lt;span class="o"&gt;(&lt;/span&gt;running kernel: 7.0.2-6-pve&lt;span class="o"&gt;)&lt;/span&gt;

root@pve-a:~# &lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;
192.168.122.11

root@pve-a:~# pvesm status
Name        Type    Status  Total&lt;span class="o"&gt;(&lt;/span&gt;KiB&lt;span class="o"&gt;)&lt;/span&gt;   Used&lt;span class="o"&gt;(&lt;/span&gt;KiB&lt;span class="o"&gt;)&lt;/span&gt;  Available&lt;span class="o"&gt;(&lt;/span&gt;KiB&lt;span class="o"&gt;)&lt;/span&gt;  %
&lt;span class="nb"&gt;local       dir     &lt;/span&gt;active  17687844     4986852    11777140        28.19%
local-lvm   lvmthin active  10940416     0          10940416        0.00%
nfs-shared  nfs     active  486256640    197097472  286114816       40.53%

root@pve-a:~# ping &lt;span class="nt"&gt;-c2&lt;/span&gt; 192.168.122.1
PING 192.168.122.1 &lt;span class="o"&gt;(&lt;/span&gt;192.168.122.1&lt;span class="o"&gt;)&lt;/span&gt; 56&lt;span class="o"&gt;(&lt;/span&gt;84&lt;span class="o"&gt;)&lt;/span&gt; bytes of data.
64 bytes from 192.168.122.1: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.312 ms
64 bytes from 192.168.122.1: &lt;span class="nv"&gt;icmp_seq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.298 ms

&lt;span class="nt"&gt;---&lt;/span&gt; 192.168.122.1 ping statistics &lt;span class="nt"&gt;---&lt;/span&gt;
2 packets transmitted, 2 received, 0% packet loss, &lt;span class="nb"&gt;time &lt;/span&gt;1001ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;hostname -I&lt;/code&gt; çıktısındaki adres, &lt;code&gt;https://&lt;/code&gt; öneki ve &lt;code&gt;:8006&lt;/code&gt; portuyla birlikte sonradan &lt;code&gt;pve_endpoint&lt;/code&gt; değişkeninin değerini oluşturacak. NFS tarafında 486 GB'lık paylaşımda yer bol; imaj, kalıp ve ilk VM için en az 25 GB gerekiyor. Paket kaybı sıfır olan ping de ağ tarafını kanıtlıyor.&lt;/p&gt;

&lt;p&gt;Çoğu tutorial'ın atladığı bir kapı daha var: CPU komut seti. Ubuntu 26.04'ün iki cloud imajı var; baseline &lt;code&gt;amd64&lt;/code&gt; her x86-64 CPU'da çalışır, &lt;code&gt;amd64v3&lt;/code&gt; ise x86-64-v3 mikro mimari seviyesini (AVX2, BMI2, FMA, MOVBE) ister ve modern donanımda belirgin şekilde daha hızlıdır. v3 imajını bu özelliklerden yoksun bir CPU'da açarsanız boot'ta kernel panic alırsınız; fiziksel CPU yeni olsa bile Proxmox'un VM'e gösterdiği sanal CPU tipi eskiyse aynı sonuç çıkar. Benim lab'ım nested-virt olduğu için bu kontrolü fiziksel makinede, yani laptop üzerinde çalıştırdım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# laptop üzerinde, scripts/check-cpu-v3.sh&lt;/span&gt;
OK: CPU exposes all x86-64-v3 features &lt;span class="o"&gt;(&lt;/span&gt;avx2 bmi2 fma movbe&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
You can use the amd64v3 cloud image.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Storage: content type'ların sessiz tuzağı
&lt;/h2&gt;

&lt;p&gt;PVE node'larının yerel diskleri küçük olduğu için her şey NFS'te duruyor: indirilen cloud imajı, altın kalıp, VM diskleri. Proxmox storage'ları hangi içerik türlerini kabul ettiklerini bildirir; yeni oluşturulmuş bir NFS storage genelde sadece disk imajlarını kabul eder. Faz 1 için kritik olan tür &lt;code&gt;Import&lt;/code&gt;; bu tür kapalıysa Terraform'un indirme kaynağı HTTP 500 ile ölüyor ve hata mesajı storage ayarına hiç değinmiyor. &lt;code&gt;Snippets&lt;/code&gt; de şimdiden açılırsa Faz 4'te custom user-data dosyaları için bu ayara geri dönmek zorunda kalmayız.&lt;/p&gt;

&lt;p&gt;Web arayüzünde &lt;strong&gt;Datacenter &amp;gt; Storage &amp;gt; nfs-shared &amp;gt; Edit&lt;/strong&gt; yolunu izleyip Content listesindeki her kutuyu tiklemek yeterli.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft6yyfks9232pwj59l6h7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft6yyfks9232pwj59l6h7.png" alt="NFS depolama düzenleme" width="608" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CLI'deki karşılığı tek satır; lab günlüğüne yazdığım da bu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# pvesm &lt;span class="nb"&gt;set &lt;/span&gt;nfs-shared &lt;span class="nt"&gt;-content&lt;/span&gt; images,rootdir,vztmpl,snippets,import
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Import&lt;/code&gt; türü çoğu tutorial'dan yeni olduğu için bir cümlelik açıklamayı hak ediyor. Proxmox'un &lt;code&gt;download-url&lt;/code&gt; adında bir API ucu var; bir node bu uç sayesinde dosyayı HTTPS üzerinden doğrudan storage'a çekiyor. bpg provider bu ucu &lt;code&gt;proxmox_download_file&lt;/code&gt; kaynağıyla kullanıyor; bu yüzden kontrol düğümünde &lt;code&gt;wget&lt;/code&gt; de, &lt;code&gt;qm importdisk&lt;/code&gt; da yok. Uç, &lt;code&gt;import&lt;/code&gt; içerik türünü bildirmeyen bir storage'a yazmayı reddediyor ve bu ret Terraform tarafına jenerik bir 500 olarak yansıyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform için API token'ı
&lt;/h2&gt;

&lt;p&gt;Provider'ın cluster'a erişmesi için üç yol var: kullanıcı adı ve şifre, auth ticket ya da API token'ı. Otomasyon için doğru cevap token: tek tek iptal edilebilir, kendi izin sınırını taşır ve bir insanın şifresini CI değişkenine gömmenize gerek kalmaz. Token'ı üç komutla, idempotent şekilde oluşturuyorum; kullanıcı ve izin nesneleri cluster genelindeki yapılandırma veritabanında tutulduğu için komutu tek bir node'da çalıştırmak yeterli, diğer node'lara kendiliğinden replike oluyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# pveum user add terraform@pve &lt;span class="nt"&gt;--comment&lt;/span&gt; &lt;span class="s2"&gt;"Terraform automation"&lt;/span&gt;
root@pve-a:~# pveum acl modify / &lt;span class="nt"&gt;--users&lt;/span&gt; terraform@pve &lt;span class="nt"&gt;--roles&lt;/span&gt; Administrator
root@pve-a:~# pveum user token add terraform@pve provider &lt;span class="nt"&gt;--privsep&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────┬──────────────────────┬────────┬─────────┐
│ token-name │ value                │ expire │ privsep │
├────────────┼──────────────────────┼────────┼─────────┤
│ provider   │ 1a2b3c4d-...         │ never  │       1 │
└────────────┴──────────────────────┴────────┴─────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Web arayüzünde &lt;strong&gt;Datacenter &amp;gt; Users &amp;gt; add&lt;/strong&gt; yolunu izleyip yeni kullanıcı eklenebilir. Önemli olan kısım, Linux PAM standard authentication yerine Proxmox VE authentication server seçilmesi:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqns3iph70tn4qvfzalse.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqns3iph70tn4qvfzalse.png" alt="Yeni Kullanıcı Ekleme" width="630" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ardından Web arayüzünde &lt;strong&gt;Datacenter &amp;gt; API Tokens &amp;gt; add&lt;/strong&gt; yolunu izleyip yeni bir token eklenir:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faoz2cg57j43d5n2pch4j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faoz2cg57j43d5n2pch4j.png" alt="Yeni API Token Ekleme" width="608" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Token değeri, tam token kimliği ile UUID'nin eşittirle birleşimi: &lt;code&gt;terraform@pve!provider=1a2b3c4d-...&lt;/code&gt;. Kopyalarken dizgenin başına ya da sonuna karışan boşluklar, yeni üretilmiş bir token'ın reddedilmesinin en yaygın sebebi; o yüzden tamını tamına alın, ne eksiği ne fazlası. Açık konuşmak gerekirse: Administrator rolü ve &lt;code&gt;privsep 0&lt;/code&gt; bir lab kısayolu. Production'da custom bir role geçilip minimum yetkiyle yetinilmeli (indirme kaynağı için &lt;code&gt;Sys.Audit&lt;/code&gt;, &lt;code&gt;Sys.Modify&lt;/code&gt;, &lt;code&gt;Datastore.AllocateTemplate&lt;/code&gt;; VM kurulumu için &lt;code&gt;VM.Allocate&lt;/code&gt;, &lt;code&gt;VM.Clone&lt;/code&gt; ve benzerleri) ve &lt;code&gt;privsep&lt;/code&gt; 1 yapılmalı. Bu, serinin sonundaki hardening maddelerinden biri.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kontrol düğümü: küçük bir LXC
&lt;/h2&gt;

&lt;p&gt;Terraform ve Ansible'ın çalışacağı kontrol düğümü, NFS üzerinde küçük bir LXC konteyneri: &lt;code&gt;ctrl-01&lt;/code&gt;. Konteyner olması bilinçli bir tercih; saniyeler içinde açılıyor, boştayken kabaca 100 MB RAM yiyor ve root filesystem'i zaten Faz 1'de açtığımız &lt;code&gt;rootdir&lt;/code&gt; içerik türünün kapsamına giriyor. Faz 1'de kernel düzeyinde yetki gerektiren hiçbir şey yok, o yüzden unprivileged konteyner sorunsuz.&lt;/p&gt;

&lt;p&gt;Önce Ubuntu LXC template'ini NFS'e indirip konteyneri oluşturuyorum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# pveam available &lt;span class="nt"&gt;--section&lt;/span&gt; system | &lt;span class="nb"&gt;grep &lt;/span&gt;ubuntu
root@pve-a:~# pveam download nfs-shared ubuntu-26.04-standard_26.04-1_amd64.tar.zst
downloading ubuntu-26.04-standard_26.04-1_amd64.tar.zst from
download finished

root@pve-a:~# pct create 900 nfs-shared:vztmpl/ubuntu-26.04-standard_26.04-1_amd64.tar.zst &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--hostname&lt;/span&gt; ctrl-01 &lt;span class="nt"&gt;--memory&lt;/span&gt; 2048 &lt;span class="nt"&gt;--cores&lt;/span&gt; 2 &lt;span class="nt"&gt;--rootfs&lt;/span&gt; nfs-shared:8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--net0&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eth0,bridge&lt;span class="o"&gt;=&lt;/span&gt;vmbr0,ip&lt;span class="o"&gt;=&lt;/span&gt;192.168.122.10/24,gw&lt;span class="o"&gt;=&lt;/span&gt;192.168.122.1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unprivileged&lt;/span&gt; 1 &lt;span class="nt"&gt;--features&lt;/span&gt; &lt;span class="nv"&gt;nesting&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;--start&lt;/span&gt; 1

root@pve-a:~# pct list
VMID Status    Lock Name
900  running       ctrl-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Template'in tam sürüm dizgesi zamanla değişir; önemli olan üç şey: template'in NFS'e indirilmesi (böylece migration sonrası her node konteyneri başlatabilir), konteynere gelecekteki VM'lerle aynı ağdan statik adres verilmesi ve ağ tarafının aynı vmbr0 köprüsüne takılması. 2 GB RAM, Terraform state işlemlerine rahat rahat yetiyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  İlk giriş: konsolda şifre yok
&lt;/h3&gt;

&lt;p&gt;Konteyner ayağa kalktı, noVNC konsolunu açtım, &lt;code&gt;root&lt;/code&gt; yazdım ve şunu aldım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Login incorrect
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ubuntu LXC template'inde root hesabı kilitli geliyor ve hiçbir varsayılan şifresi yok; template, yapılandırmanın konsoldan değil host'tan yapılacağını varsayıyor. Kapının kendisi &lt;code&gt;pct enter&lt;/code&gt;; kimlik doğrulaması olmadan, kernel namespace'i üzerinden konteynerin içine root shell açıyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# pct enter 900
root@ctrl-01:~#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Konsoldan tty1'e doğrudan girmek isterseniz içeride &lt;code&gt;passwd root&lt;/code&gt; çalıştırmak yeterli. Node tarafından tek satırlık, etkileşimsiz alternatif de var:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# pct &lt;span class="nb"&gt;exec &lt;/span&gt;900 &lt;span class="nt"&gt;--&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo "root:changeme" | chpasswd'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu yazıda "ctrl-01 içinde" etiketli komutların tamamı bu kapıdan girilerek çalıştırıldı.&lt;/p&gt;

&lt;p&gt;Aynı shell'e web arayüzünden de girilebilir:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2c5pf30y7d9n0nile4mj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2c5pf30y7d9n0nile4mj.png" alt="Web arayüzünden konteyner shell'ine giriş" width="800" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Minimal konteynerde gpg yok
&lt;/h3&gt;

&lt;p&gt;Terraform'u HashiCorp deposundan kurmak istedim; çünkü Ubuntu'nun kendi deposundaki sürüm geride kalıyor. Elinizdeki tutorial'ların hepsi şöyle bir blok gösterir: anahtarı indir, &lt;code&gt;gpg --dearmor&lt;/code&gt;'dan geçir, keyring'e yaz. Ben de öyle yaptım ve şunu aldım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo: 'gpg': command not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu sadece ilk halka. Minimal Ubuntu LXC template'inde gnupg yok, o yüzden dearmor adımı keyring'e hiçbir şey yazmıyor ve &lt;code&gt;apt-get update&lt;/code&gt; bir sonraki adımda HashiCorp deposunu imzasız reddediyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NO_PUBKEY AA16FCBCA621E701
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;çünkü &lt;code&gt;signed-by&lt;/code&gt; referansı, hiç var olmamış bir &lt;code&gt;.gpg&lt;/code&gt; dosyasına bakıyor. Çözüm, gpg'yi tamamen atlamak: HashiCorp'ın sunduğu anahtar ASCII-armored ve modern apt (2.4 ve üzeri; Ubuntu 26.04'te apt 3.x var) armored anahtarları &lt;code&gt;.asc&lt;/code&gt; uzantısıyla doğrudan okuyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# wget &lt;span class="nt"&gt;-qO&lt;/span&gt; /usr/share/keyrings/hashicorp.asc &lt;span class="se"&gt;\&lt;/span&gt;
  https://apt.releases.hashicorp.com/gpg
root@ctrl-01:~# &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/hashicorp.asc] &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
  https://apt.releases.hashicorp.com &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;lsb_release &lt;span class="nt"&gt;-cs&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; main"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/apt/sources.list.d/hashicorp.list
root@ctrl-01:~# apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; terraform
root@ctrl-01:~# apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; ansible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ayrıca doğruladım: Ubuntu 26.04'ün kod adı &lt;code&gt;resolute&lt;/code&gt; ve HashiCorp mirror'ında kendi dağıtımı var; &lt;code&gt;lsb_release -cs&lt;/code&gt; hiçbir özel işlem gerektirmiyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Üretilmemiş locale
&lt;/h3&gt;

&lt;p&gt;Terraform kuruldu, sıra Ansible'da. &lt;code&gt;ansible --version&lt;/code&gt; ise version banner'ı yerine bunu bastı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: Ansible could not initialize the preferred locale: unsupported locale setting
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ubuntu template'i &lt;code&gt;LANG=en_US.UTF-8&lt;/code&gt; set ediyor ama o locale'i hiç üretmiyor; aynı eksiklik, paket kurulumları sırasında perl'den gelen uyarıların da sebebiydi. Ansible, perl kadar hoşgörülü değil; başlamayı tamamen reddediyor. Locale'i bir kez üretmek ikisini de tek hamlede çözüyor ve &lt;code&gt;update-locale&lt;/code&gt; bu ayarı &lt;code&gt;/etc/default/locale&lt;/code&gt;'a taşıdığı için reboot sonrası da kalıcı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; locales
root@ctrl-01:~# locale-gen en_US.UTF-8
root@ctrl-01:~# update-locale &lt;span class="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;en_US.UTF-8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Araç kapıları da artık kanıtla kapandı; her iki banner'ı da gerçek çalıştırmadaki haliyle buraya bırakıyorum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# terraform &lt;span class="nt"&gt;-version&lt;/span&gt;
Terraform v1.15.9
on linux_amd64

root@ctrl-01:~# ansible &lt;span class="nt"&gt;--version&lt;/span&gt;
ansible-core 2.20.1
  config file &lt;span class="o"&gt;=&lt;/span&gt; /etc/ansible/ansible.cfg
  executable location &lt;span class="o"&gt;=&lt;/span&gt; /usr/bin/ansible
  python version &lt;span class="o"&gt;=&lt;/span&gt; 3.13.2 &lt;span class="o"&gt;(&lt;/span&gt;/usr/bin/python3&lt;span class="o"&gt;)&lt;/span&gt;
  jinja version &lt;span class="o"&gt;=&lt;/span&gt; 3.1.6
  libyaml &lt;span class="o"&gt;=&lt;/span&gt; True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bir küçük sürüm gerçeğini de buraya not edeyim: araştırmam sırasında "Ansible core 2.21" yazmıştım ama Ubuntu deposu &lt;code&gt;ansible-core 2.20.1&lt;/code&gt; + &lt;code&gt;ansible 13.1.0&lt;/code&gt; meta paketini veriyor. Plan 2.21'di, saha 2.20.1'di; saha kazanır.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSH anahtarı ve repo'nun üç aktarmalı yolculuğu
&lt;/h2&gt;

&lt;p&gt;Kontrol düğümü, kurduğu her VM'e anahtar enjekte edecek; önce o anahtar çifti:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.ssh/id_ed25519 &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
Generating public/private ed25519 key pair.
Your identification has been saved &lt;span class="k"&gt;in&lt;/span&gt; /root/.ssh/id_ed25519
Your public key has been saved &lt;span class="k"&gt;in&lt;/span&gt; /root/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:1Zc5k... root@ctrl-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cat ~/.ssh/id_ed25519.pub&lt;/code&gt; ile okunan satır, Terraform tarafında her klonlanan VM'e cloud-init &lt;code&gt;user_account&lt;/code&gt; bloğuyla enjekte edilecek olan dizgi. Aynı anahtar malzemesini üç yerde görmek (kontrol düğümü, hypervisor'da &lt;code&gt;qm cloudinit&lt;/code&gt; çıktısı, guest içinde &lt;code&gt;authorized_keys&lt;/code&gt;), Faz 1'in en hızlı uçtan uca sağlaması.&lt;/p&gt;

&lt;p&gt;Repo zip'i laptop'ta duruyor. Konteynere taşımak üç aktarmada tamamlanıyor ve her aktarma, o ayağın elinde zaten olan yolu kullanıyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# laptop üzerinde: cluster'a (laptop aynı zamanda lab'ın NAT ağ geçidi, 192.168.122.1)&lt;/span&gt;
laptop&lt;span class="nv"&gt;$ &lt;/span&gt;scp ~/Downloads/proxmox-automation.zip root@192.168.122.11:/root/
proxmox-automation.zip  100%  452KB   9.1MB/s   00:00

&lt;span class="c"&gt;# pve-a üzerinde: dosyayı konteynerin filesystem'ine doğrudan yaz; SSH'a gerek yok&lt;/span&gt;
root@pve-a:~# pct push 900 /root/proxmox-automation.zip /root/proxmox-automation.zip

&lt;span class="c"&gt;# ctrl-01 içinde&lt;/span&gt;
root@ctrl-01:~# apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; unzip
root@ctrl-01:~# unzip ~/proxmox-automation.zip &lt;span class="nt"&gt;-d&lt;/span&gt; ~/
root@ctrl-01:~# &lt;span class="nb"&gt;ls&lt;/span&gt; ~/proxmox-automation
ansible  docs  README.md  scripts  terraform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Laptop'tan konteynere doğrudan &lt;code&gt;scp&lt;/code&gt; neden çalışmaz? Çünkü yeni kurulmuş Ubuntu konteynerinde kilitli bir root var, şifre yok, &lt;code&gt;authorized_keys&lt;/code&gt; yok; SSH'ın doğrulayacağı hiçbir şey yok. &lt;code&gt;pct push&lt;/code&gt; bu engeli tasarım gereği bypass ediyor, dosyayı konteyner filesystem'ine node üzerinden yazıyor. Her aktarmanın başarı işareti farklı: &lt;code&gt;scp&lt;/code&gt; ilerleme satırı basıp sessizce çıkıyor, &lt;code&gt;pct push&lt;/code&gt; hiçbir şey basmıyor (Proxmox'un "başarı sessizdir" geleneği) ve &lt;code&gt;ls&lt;/code&gt; nihai makbuz. Bu zincir, repo bir git remote'a taşındığı anda tek bir &lt;code&gt;git clone&lt;/code&gt;'a indirgeniyor; o zaman bu bölümün tamamı tarih oluyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform tarafı: kritik kararlar
&lt;/h2&gt;

&lt;p&gt;Repo'daki Terraform konfigürasyonunun tamamına girmeyeceğim; sadece beklenmedik bir davranışla karşılaştığınızda açıklaması elinizin altında olsun diye kritik kararları ve iki dosyanın can alıcı kısımlarını buraya bırakıyorum.&lt;/p&gt;

&lt;p&gt;İlki, imaj indirme ve altın kalıp:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_download_file"&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu_image"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;content_type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"import"&lt;/span&gt;     &lt;span class="c1"&gt;# PVE 8.4+ ve storage'da Import açık olmalı&lt;/span&gt;
  &lt;span class="nx"&gt;datastore_id&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template_node&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloud_image_url&lt;/span&gt;
  &lt;span class="nx"&gt;file_name&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu-2604-cloudimg.qcow2"&lt;/span&gt;
  &lt;span class="nx"&gt;upload_timeout&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;         &lt;span class="c1"&gt;# provider varsayılanı 600 s, dar geliyor&lt;/span&gt;
  &lt;span class="nx"&gt;overwrite_unmanaged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_virtual_environment_vm"&lt;/span&gt; &lt;span class="s2"&gt;"ubuntu_template"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template_name&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template_node&lt;/span&gt;
  &lt;span class="nx"&gt;vm_id&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template_vmid&lt;/span&gt;  &lt;span class="c1"&gt;# sabit 9000&lt;/span&gt;
  &lt;span class="nx"&gt;template&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;cpu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cores&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cpu_type&lt;/span&gt;  &lt;span class="c1"&gt;# x86-64-v3, aşağıda hikayesi var&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;scsi_hardware&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"virtio-scsi-pci"&lt;/span&gt;
  &lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
    &lt;span class="nx"&gt;import_from&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxmox_download_file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ubuntu_image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="nx"&gt;interface&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scsi0"&lt;/span&gt;
    &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template_disk_size_gb&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;serial_device&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="nx"&gt;vga&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"serial0"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;boot_order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"scsi0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Buradaki en önemli satır &lt;code&gt;import_from&lt;/code&gt;. &lt;code&gt;file_id&lt;/code&gt; kullanırsanız provider sessizce PVE node'una SSH açıp &lt;code&gt;qm disk import&lt;/code&gt; çalıştırıyor; API token'ıyla giden yolda ise SSH yok ve apply template adımında düşüyor. &lt;code&gt;import_from&lt;/code&gt; ise PVE'nin yerel &lt;code&gt;import-from=&lt;/code&gt; disk seçeneğini API üzerinden kullanıyor; kimse hiçbir node'a SSH yapmıyor. İkinci kritik karar: template'te &lt;code&gt;initialization&lt;/code&gt; bloğu olmamalı; cloud-init ayarları klonun işidir, öyle ki tek kalıp, birbirinden tamamen farklı ağ kimlikleriyle workload'lara hizmet verebilsin. Kalıp bir kalıp, makine değil.&lt;/p&gt;

&lt;p&gt;İkinci dosya, workload klonu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"proxmox_virtual_environment_vm"&lt;/span&gt; &lt;span class="s2"&gt;"test_vm"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm_name&lt;/span&gt;
  &lt;span class="nx"&gt;node_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm_node&lt;/span&gt;
  &lt;span class="nx"&gt;vm_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workload_vmid&lt;/span&gt;  &lt;span class="c1"&gt;# sabit 200&lt;/span&gt;

  &lt;span class="nx"&gt;clone&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;vm_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;proxmox_virtual_environment_vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ubuntu_template&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm_id&lt;/span&gt;
    &lt;span class="nx"&gt;full&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;wait_for_ip&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# bu satırın 15 dakikalık hikayesi aşağıda&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;disk&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  &lt;span class="c1"&gt;# klonun root diskini büyütür&lt;/span&gt;
    &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
    &lt;span class="nx"&gt;interface&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"scsi0"&lt;/span&gt;
    &lt;span class="nx"&gt;size&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm_disk_size_gb&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;initialization&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;datastore_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage_id&lt;/span&gt;
    &lt;span class="nx"&gt;dns&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;domain&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;search_domain&lt;/span&gt;
      &lt;span class="nx"&gt;servers&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dns_servers&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;ip_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ipv4&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.vm_ip_address}/${var.vm_ip_cidr}"&lt;/span&gt;
        &lt;span class="nx"&gt;gateway&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm_ip_gateway&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;user_account&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;keys&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;trimspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathexpand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ssh_public_key_path&lt;/span&gt;&lt;span class="p"&gt;)))]&lt;/span&gt;
      &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vm_username&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kararların gerekçeleri, kısaca:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Karar&lt;/th&gt;
&lt;th&gt;Gerekçe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;proxmox_download_file&lt;/code&gt; (yeni ad)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;proxmox_virtual_environment_download_file&lt;/code&gt; deprecated; v1.0'da kalkacak&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scsi_hardware = virtio-scsi-pci&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ubuntu cloud imajlarının istediği kontrolcü; online disk resize'ı yalnızca bu destekliyor, Faz 2 bunun üzerine kurulu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU tipi &lt;code&gt;x86-64-v3&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;PVE varsayılanı &lt;code&gt;x86-64-v2-Auto&lt;/code&gt; AVX2 taşımıyor; amd64v3 guest boot'ta kernel panic yiyor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Seri konsol (&lt;code&gt;serial_device&lt;/code&gt; + &lt;code&gt;vga serial0&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Cloud imaj konvansiyonu; standart VGA'da noVNC'de görülen boş ekran belirtisini önler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full clone&lt;/td&gt;
&lt;td&gt;NFS üzerinde bağımsız diskler; production DB sunucusu pratiğinin aynısı&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Guest agent cloud-init yerine Ansible'dan&lt;/td&gt;
&lt;td&gt;user-data sade kalıyor, paket yapılandırması yönetim altına giriyor; Faz 3'te drift tespiti de yanında geliyor&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  init, validate ve plan: iki schema hatası üst üste
&lt;/h2&gt;

&lt;p&gt;Değişkenleri doldurup (&lt;code&gt;pve_endpoint&lt;/code&gt;, token, &lt;code&gt;storage_id = nfs-shared&lt;/code&gt;, VM adı ve IP'si) provider'ı çekiyorum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# terraform init
Initializing the backend...
Initializing provider plugins...
- Finding bpg/proxmox versions matching &lt;span class="s2"&gt;"~&amp;gt; 0.111.1"&lt;/span&gt;...
- Installing bpg/proxmox v0.111.1...
- Installed bpg/proxmox v0.111.1 &lt;span class="o"&gt;(&lt;/span&gt;signed, key ID F0582AD6AE97C188&lt;span class="o"&gt;)&lt;/span&gt;

Terraform has been successfully initialized!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  vlan_tag artık yok
&lt;/h3&gt;

&lt;p&gt;İlk &lt;code&gt;terraform plan&lt;/code&gt; tam da burada, schema hatasıyla düştü:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;╷
│ Error: Unsupported argument
│
│   on template.tf line 65, in resource "proxmox_virtual_environment_vm" "ubuntu_template":
│   65:     vlan_tag = var.vlan_tag
│
│ An argument named "vlan_tag" is not expected here.
╵
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Provider 0.111 hattında &lt;code&gt;network_device.vlan_tag&lt;/code&gt; özniteliğini &lt;code&gt;vlan_id&lt;/code&gt; olarak yeniden adlandırmış. Eski tutorial'lar &lt;code&gt;vlan_tag&lt;/code&gt; kullanıyor. Düzeltme tek satır; değişken adını koruyup değeri &lt;code&gt;vlan_id&lt;/code&gt;'ye bağlıyorum, böylece tfvars dosyası değişmiyor&lt;/p&gt;

&lt;p&gt;Bu arada, VLAN-aware köprülerdeki trunk özelliği ayrı bir öznitelik (&lt;code&gt;trunks = "10;20;30"&lt;/code&gt;); &lt;code&gt;vlan_id&lt;/code&gt; ile karıştırmamak gerek.&lt;/p&gt;

&lt;h3&gt;
  
  
  hostname kalkmış, CPU tipinde -Auto yok
&lt;/h3&gt;

&lt;p&gt;Plan bu kez başka iki hatayla düştü. İlki &lt;code&gt;initialization.hostname&lt;/code&gt; özniteliği; provider 0.111'de kaldırılmış. cloud-init hostname'i artık VM'in adından geliyor, o yüzden VM adı geçerli bir DNS ismi olmalı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;│ Error: Unsupported argument
│
│   on vm.tf line 90, in resource "proxmox_virtual_environment_vm" "test_vm":
│   90:     hostname = var.vm_name
│
│ An argument named "hostname" is not expected here.
╵
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İkincisi daha gizliydi: &lt;code&gt;x86-64-v3-Auto&lt;/code&gt; diye bir CPU tipi provider validator'ının listesinde yok. PVE arayüzünde gördüğünüz &lt;code&gt;-Auto&lt;/code&gt; varyantları, provider tarafında geçersiz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;│ Error: expected cpu.0.type to be one of [x86-64-v2 x86-64-v3 ... host ...],
│ got x86-64-v3-Auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Çözüm: &lt;code&gt;hostname&lt;/code&gt; satırını silmek ve &lt;code&gt;cpu_type&lt;/code&gt;'ı düz &lt;code&gt;x86-64-v3&lt;/code&gt; yapmak. Buradan çıkan ders, &lt;code&gt;terraform validate&lt;/code&gt;'ı alışkanlık haline getirmek oldu; init ile plan arasına sıkışan bu tek komut, tüm öznitelik ve blokları gerçek provider şemasına karşı, cluster'a tek istek atmadan kontrol ediyor. İki schema hatasının ikisini de, kimlik bilgilerine hiç dokunmadan, birer saniyenin altında yakalayabilirdi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# terraform validate
Success! The configuration is valid.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ve nihayet sağlıklı bir plan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plan: 3 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + ssh_command    = "ssh ubuntu@192.168.122.50"
  + template_vm_id = 9000
  + test_vm_id     = 200
  + test_vm_ip     = "192.168.122.50"
  + test_vm_name   = "vm-test-01"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İlk çalıştırmada üç ekleme, sıfır değişiklik, sıfır silme; olması gereken tablo bu. Outputs bloğu da anahtarların devrini gösteriyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  İlk apply: 4 dakika 25 saniye, 11 saniye, 15 dakika 5 saniye
&lt;/h2&gt;

&lt;p&gt;Konfigürasyon düzeltmeleri sonrası apply. Süreler ölçüldü; işte gerçek değerler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;proxmox_download_file.ubuntu_image: Creating...
proxmox_download_file.ubuntu_image: Still creating... [4m25s elapsed]
proxmox_download_file.ubuntu_image: Creation complete after 4m25s
proxmox_virtual_environment_vm.ubuntu_template: Creating...
proxmox_virtual_environment_vm.ubuntu_template: Creation complete after 11s
proxmox_virtual_environment_vm.test_vm: Creating...
proxmox_virtual_environment_vm.test_vm: Still creating... [15m00s elapsed]
proxmox_virtual_environment_vm.test_vm: Creation complete after 15m5s

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Outputs:

ssh_command = "ssh ubuntu@192.168.122.50"
template_vm_id = 9000
test_vm_id = 200
test_vm_ip = "192.168.122.50"
test_vm_name = "vm-test-01"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmjtajto784seenqznsvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmjtajto784seenqznsvq.png" alt="Terraform Apply Sonucunda Yeni Template ve Yeni VM" width="307" height="687"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Süreyi belirleyen indirme (4,5 dakika) ve saniyeler içinde ayaklanan kalıp (11 saniye) normal; VM'e bağlanan 15 dakikalık kısım ise asıl sorun işareti.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hata olmayan on beş dakikalık uyarı
&lt;/h3&gt;

&lt;p&gt;Apply'ın kuyruğunda şu uyarı vardı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;╷
│ Warning: error waiting for network interfaces from QEMU agent
│
│ with proxmox_virtual_environment_vm.test_vm,
│ on vm.tf line 7, in resource "proxmox_virtual_environment_vm" "test_vm":
│ 7: resource "proxmox_virtual_environment_vm" "test_vm" {
│
│ timeout while waiting for the QEMU agent on VM "200" to publish the
│ network interfaces
╵
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;15 dakika 5 saniyelik sürenin kendisi ipucu. Klon saniyeler içinde bitti, VM neredeyse anında açıldı; beklemin tamamı, provider'ın guest agent'ı yoklamasından ibaretti. Mekanizmayı sonradan provider'ın kaynak kodundan doğruladım: VM konfigürasyonunda agent açık olduğu sürece provider, VM'i başlattıktan sonra ve sonraki her plan/apply yenilemesinde agent'a ağ arayüzlerini soruyor ve "henüz IP yok" cevabını &lt;code&gt;agent.timeout&lt;/code&gt; (varsayılan 15 dakika) bitene kadar tekrarlıyor. Ubuntu cloud imajları qemu-guest-agent ile gelmiyor; o yüzden her yoklama boşa çıkıyor, 15 dakika dolunca provider bir &lt;code&gt;Warning&lt;/code&gt; ile pes ediyor. Warning, Error değil: VM çalışıyor, state temiz, tek kayıp state'te &lt;code&gt;ipv4_addresses&lt;/code&gt;'ın boş kalması; statik IP tasarımında zaten ihtiyacım yok.&lt;/p&gt;

&lt;p&gt;Üç makul tepki var; repoya işlenen, birincisi:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;agent { wait_for_ip { disabled = true } }&lt;/code&gt; ile sorguyu tamamen atlamak; statik IP'li bu pipeline için doğru varsayılan.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agent.timeout&lt;/code&gt;'ı kısaltmak (örneğin 2m); bekleme küçülür ama kalkmaz. Agent tabanlı IP keşfini ileride isterseniz makul orta yol.&lt;/li&gt;
&lt;li&gt;Hiçbir şey yapmamak; guest agent kurulunca yoklamalar saniyeler içinde başarıya döner ve uyarı kendiliğinden kaybolur.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Asla doğru olmayan dördüncü yol ise apply'ı Ctrl-C ile kesmek; oluşturulması yarıda kesilen kaynak tainted olur ve arkasında yarım kalmış bir temizlik bırakır. Ben kesmedim, bekledim; 15 dakikanın bedeli bu yazı oldu.&lt;/p&gt;

&lt;p&gt;Düzeltmeyi uygulayıp tekrar plan çektiğimde fark tek bir bloğa iniyordu (agent), apply "0 to add, 2 changed" ile bir saniyede tamamlandı ve sonraki tüm yenilemeler saniye sürdü. Yani &lt;code&gt;wait_for_ip&lt;/code&gt; satırı, bu yazıyı okuyan herkesin konfigürasyonuna eklemesi gereken tek satırlık sigorta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doğrulama: üç bağımsız katman hemfikir olana kadar
&lt;/h2&gt;

&lt;p&gt;Terraform "tamam" dedikten sonra güven meselesi başlıyor. Hipervizör, guest ve ağ katmanlarının üçü de aynı şeyi söyleyene kadar hiçbir şeye inanmıyorum.&lt;/p&gt;

&lt;p&gt;Hipervizör tarafı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# qm list
VMID  Name             Status   MEM&lt;span class="o"&gt;(&lt;/span&gt;MB&lt;span class="o"&gt;)&lt;/span&gt;  BOOTDISK&lt;span class="o"&gt;(&lt;/span&gt;GB&lt;span class="o"&gt;)&lt;/span&gt;  PID
9000  ubuntu-2604-tpl  stopped  2048     10.00         0
200   vm-test-01       running  2048     10.00         318234

root@pve-a:~# qm config 200 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"scsi0|net0|agent|serial"&lt;/span&gt;
agent: &lt;span class="nv"&gt;enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
net0: &lt;span class="nv"&gt;virtio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;BC:24:11:2E:AA:F7,bridge&lt;span class="o"&gt;=&lt;/span&gt;vmbr0
scsi0: nfs-shared:vm-200-disk-0,size&lt;span class="o"&gt;=&lt;/span&gt;10G
serial0: socket
vga: serial0

root@ctrl-01:~# terraform state list
proxmox_download_file.ubuntu_image
proxmox_virtual_environment_vm.ubuntu_template
proxmox_virtual_environment_vm.test_vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kalıbın &lt;code&gt;stopped&lt;/code&gt; ve PID 0 görünmesi tam olması gerektiği gibi; bir kalıbın çalışıyor görünmesi, birilerinin yanlışlıkla kalıbı başlattığı anlamına gelir ve asla olmamalıdır. &lt;code&gt;qm config&lt;/code&gt; çıktısı ise altıncı bölümdeki dört donanım kararını tek bakışta doğruluyor: agent açık, virtio ağ, NFS'te root diski, seri konsol çifti.&lt;/p&gt;

&lt;p&gt;Guest ve ağ tarafı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# ssh ubuntu@192.168.122.50
The authenticity of host &lt;span class="s1"&gt;'192.168.122.50'&lt;/span&gt; can&lt;span class="s1"&gt;'t be established.
ED25519 key fingerprint is SHA256:dG9w...DzKw.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Welcome to Ubuntu 26.04 LTS (Resolute) (GNU/Linux 6.17.0-25-generic...)

ubuntu@vm-test-01:~$ cloud-init status --wait
status: done

ubuntu@vm-test-01:~$ grep Datasource /var/log/cloud-init-output.log
Cloud-init v. 25.1 finished at ... Datasource DataSourceNoCloud
seeddev=/dev/sr0. Up 14.32 seconds
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prompt'taki &lt;code&gt;vm-test-01&lt;/code&gt;, kaldırılan &lt;code&gt;initialization.hostname&lt;/code&gt; özniteliğine rağmen hostname'in cloud-init tarafından VM adından alındığının kanıtı. &lt;code&gt;status: done&lt;/code&gt; ve &lt;code&gt;DataSourceNoCloud seeddev=/dev/sr0&lt;/code&gt; ise tohum (seed) diskının bulunduğunun ve ilk boot'ta tamamen tüketildiğinin makbuzu. Bu ikisi olmadan, VM göründüğü gibi çalışsa bile cloud-init payload'ı hiç almamış olabilir; belirtisi de şu olur: statik adres yerine imajın DHCP kimliğiyle ağa çıkar. Bir not: VM'i destroy/apply döngüsüne sokarsanız yeni makine yeni host anahtarıyla gelir; yeniden bağlanmadan önce &lt;code&gt;ssh-keygen -R 192.168.122.50&lt;/code&gt; şart. Bunu sonradan, Faz 2 rebuild'i sırasında öğrendim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ansible ilk temas: pipeline'ın kapanışı
&lt;/h2&gt;

&lt;p&gt;Terraform, açılmış ve ağa bağlanmış bir VM'e kadar götürüyor. İşletim sisteminin içindeki her şey artık Ansible'ın sahası ve Faz 3'te bu ilk playbook'un üzerine tüm agent yığını (Zabbix Agent 2, Trend Micro, ManageEngine, QRadar'a rsyslog forward'u) gelecek. Faz 1 playbook'u bilinçli olarak minik; görevi yönetim kanalını kanıtlamak ve hypervisor'ın tek umursadığı paketi, qemu-guest-agent'ı kurmak.&lt;/p&gt;

&lt;p&gt;Envanter tek VM'lik:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;provisioned&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;vm-test-01&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ansible_host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.122.50&lt;/span&gt;
          &lt;span class="na"&gt;ansible_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~/proxmox-automation/ansible# ansible provisioned &lt;span class="nt"&gt;-m&lt;/span&gt; ping
vm-test-01 | SUCCESS &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"ansible_facts"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"discovered_interpreter_python"&lt;/span&gt;: &lt;span class="s2"&gt;"/usr/bin/python3"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
    &lt;span class="s2"&gt;"changed"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"ping"&lt;/span&gt;: &lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playbook dört görevden ibaret: kimlik göster, agent'ı kur, servisi başlat, &lt;code&gt;/etc/provisioned-by&lt;/code&gt; damgasını yaz. (Playbook'un tamamı repoda; burada çalıştırmanın çıktısı daha değerli.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@ctrl-01:~# ansible-playbook playbooks/01_first_contact.yml

PLAY &lt;span class="o"&gt;[&lt;/span&gt;First contact - verify a freshly provisioned VM] &lt;span class="k"&gt;***********&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;******************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Show system identity] &lt;span class="k"&gt;*************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01] &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"vm-test-01 is up, Ubuntu 26.04"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Install QEMU guest agent] &lt;span class="k"&gt;*********************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Enable and start the guest agent] &lt;span class="k"&gt;*************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Mark the VM as managed by this pipeline] &lt;span class="k"&gt;******************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;vm-test-01]

PLAY RECAP &lt;span class="k"&gt;*******************************************************&lt;/span&gt;
vm-test-01 : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2 &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;skipped&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;rescued&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ok=5 changed=2&lt;/code&gt; ilk bakışta yanlış görünür; aritmetiği şöyle: &lt;code&gt;ok&lt;/code&gt; sayacı changed olan görevleri de içerir. Beş görevin beş sonucu var; üçü normalde changed raporlardı ama service görevi fresh VM'de &lt;code&gt;ok&lt;/code&gt; rapor etti, çünkü paketin postinst'i, apt görevinin hemen ardından agent'ı zaten başlatıp enable etmişti. İki changed; paket kurulumu ve damga dosyası. Bir dakika sonra ikinci çalıştırma, idempotans makbuzu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vm-test-01 : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;changed&lt;/code&gt;'in sıfıra düşmesi bu playbook'u tek seferlik kurulumdan güvenli, tekrar çalıştırılabilir bir operasyona çevirir; Faz 3'te aynı örüntü her provision edilmiş VM'e karşı çalışacak ve sıfırın üstündeki changed, rutin bir yan etki değil, incelenmeye değer bir drift sinyali olacak.&lt;/p&gt;

&lt;h3&gt;
  
  
  Facts enjeksiyonu 2.24'te kalkıyor
&lt;/h3&gt;

&lt;p&gt;İlk çalıştırmada iki görevden şu uyarı düştü:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[DEPRECATION WARNING]: The INJECT_FACTS_AS_VARS setting is scheduled to be
removed in version 2.24. ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Playbook, &lt;code&gt;ansible_distribution&lt;/code&gt; tarzı çıplak fact değişkenleri kullanıyordu. ansible-core 2.20 otomatik fact enjeksiyonunu deprecate etmiş; 2.24'te tamamen kalkıyor. Düzeltme, parantez sözdizimine geçmek:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# eski:&lt;/span&gt;
&lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inventory_hostname&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;up,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ansible_distribution&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ansible_distribution_version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;span class="c1"&gt;# yeni:&lt;/span&gt;
&lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inventory_hostname&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;up,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ansible_facts['distribution']&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ansible_facts['distribution_version']&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2.24 çıktığında bu uyarı, kırılan playbook'ların başındaki hata mesajına dönüşecek; düzeltmesi de gösterildiği kadar küçük.&lt;/p&gt;

&lt;p&gt;Agent kurulduktan sonra hypervisor tarafındaki son kapı da sessizce açılıyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;root@pve-a:~# qm guest cmd 200 ping
root@pve-a:~# &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt;
0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;qm guest cmd ping&lt;/code&gt; başarılı olunca hiçbir şey basmaz; sessizlik ve sıfır çıkış kodu, testin geçtiğinin işareti. Bu tek satır, 15 dakikalık uyarıyla başlayan döngüyü kapatıyor: agent artık var, yoklamalar saniyeler içinde cevap buluyor ve Proxmox arayüzü VM'in IP adresini kendisi gösteriyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lab aniden dondu
&lt;/h2&gt;

&lt;p&gt;Faz 1'i kapatırken bir de gizemli olay yaşadım; kaydetmemek olmaz. Oturum ortasında pve-a'ya açık SSH bağlantım aniden &lt;code&gt;Connection reset by peer&lt;/code&gt; ile gitti. Yeniden girdiğimde CT 900 önce &lt;code&gt;not running&lt;/code&gt; gösterdi, saniyeler sonra yeniden running oldu; VM 200 ise durmuştu ve sonraki plan &lt;code&gt;started: false -&amp;gt; true&lt;/code&gt; değişikliği gösterdi. Ansible, guest'in uptime'ını 2.2 dakika raporladı; yani makine kısa süre önce yeniden başlamıştı. Üç belirti de aynı anda bir pve-a reboot'una işaret ediyordu ama hiçbir crash kanıtı yoktu.&lt;/p&gt;

&lt;p&gt;Cevap, utanılacak kadar basitti: laptop öğle yemeğinde uykuya girmiş. Bu lab nested-virt; pve-a ve arkadaşları o laptop'un libvirt guest'leri. Host uykuya girince tüm lab bir anda askıya alınıyor; SSH kopuyor, konteyner duruyor, VM kapanıyor. Hiçbir şey çökmedi; &lt;code&gt;onboot=1&lt;/code&gt; ayarları her şeyi kendisi toparladı. Son ders donanımda değil, lab tasarımında: nested-virt lab'ın tek bir fiziksel host'u var ve onun güç yönetimi, cluster'ın beşinci düğümüdür. Lab saatlerinde host'un otomatik uykuya dalmasını kapatmak ve bunu &lt;code&gt;uptime&lt;/code&gt; ile &lt;code&gt;journalctl --list-boots&lt;/code&gt; üzerinden doğrulamak yeterli.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hızlı başvuru: belirti, neden, çözüm
&lt;/h2&gt;

&lt;p&gt;Yazı boyunca geçen belirti ve çözümler, hepsini baştan okumak istemeyenler için tek tabloda:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Belirti&lt;/th&gt;
&lt;th&gt;Neden&lt;/th&gt;
&lt;th&gt;Çözüm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Konsolda &lt;code&gt;Login incorrect&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Ubuntu LXC template'i şifresiz ve root kilitli&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pct enter 900&lt;/code&gt;, gerekiyorsa &lt;code&gt;passwd&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gpg: command not found&lt;/code&gt; + &lt;code&gt;NO_PUBKEY&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Minimal template'te gnupg yok; keyring hiç yazılmadı&lt;/td&gt;
&lt;td&gt;Anahtarı &lt;code&gt;.asc&lt;/code&gt; olarak sakla; gpg'ye hiç ihtiyaç yok&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ansible could not initialize the preferred locale&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;LANG&lt;/code&gt; set edilmiş ama locale üretilmemiş&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;locale-gen en_US.UTF-8&lt;/code&gt; + &lt;code&gt;update-locale&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan: &lt;code&gt;vlan_tag is not expected here&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Provider 0.111 özniteliği &lt;code&gt;vlan_id&lt;/code&gt; yaptı&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;network_device&lt;/code&gt; içinde &lt;code&gt;vlan_id = N&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan: &lt;code&gt;hostname&lt;/code&gt; yok + &lt;code&gt;x86-64-v3-Auto&lt;/code&gt; geçersiz&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;initialization.hostname&lt;/code&gt; kaldırıldı; &lt;code&gt;-Auto&lt;/code&gt; CPU tipleri validatörde yok&lt;/td&gt;
&lt;td&gt;hostname satırını sil (VM adı DNS ismi), &lt;code&gt;cpu_type = x86-64-v3&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VM 15 dk &lt;code&gt;Still creating&lt;/code&gt; + Warning&lt;/td&gt;
&lt;td&gt;Agent açık ama imajda qemu-guest-agent yok; &lt;code&gt;agent.timeout&lt;/code&gt; 15m&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;wait_for_ip { disabled = true }&lt;/code&gt;; asla Ctrl-C değil&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;INJECT_FACTS_AS_VARS&lt;/code&gt; deprecation uyarısı&lt;/td&gt;
&lt;td&gt;ansible-core 2.24'te çıplak fact değişkenleri kalkıyor&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ansible_facts['...']&lt;/code&gt; parantez sözdizimi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH reset, CT durdu, VM kapandı; kanıt yok&lt;/td&gt;
&lt;td&gt;Laptop uykusu; nested-virt lab'ın tamamı host'a bağlı&lt;/td&gt;
&lt;td&gt;Lab saatlerinde host uykusunu kapat; &lt;code&gt;journalctl --list-boots&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Sırada ne var?
&lt;/h2&gt;

&lt;p&gt;Faz 1 tek diskli bir VM üretiyor; web sunucusu ve jump host için yeterli, veritabanı sunucusu için değil. Faz 2'nin konusu çoklu disk örüntüsü: &lt;code&gt;/var&lt;/code&gt;, &lt;code&gt;/log&lt;/code&gt;, &lt;code&gt;/data&lt;/code&gt; ve &lt;code&gt;/backup&lt;/code&gt; için ayrı SCSI cihazlar, her diske Terraform &lt;code&gt;serial&lt;/code&gt; özniteliğiyle kalıcı kimlik ve konuk içinde LVM + XFS zinciri. Buraya çekilen temeller tam olarak Faz 2'nin ihtiyacı olanlar; &lt;code&gt;virtio-scsi-pci&lt;/code&gt; kontrolcüsü online disk resize'ı destekleyen tek kontrolcü ve serial etiketi, &lt;code&gt;/dev/sdb&lt;/code&gt; harflerinin konuk içinde kayması problemine kökten çözüm. Müşteri bir terabayt ek data isterse cevap bir satırlık değişken düzenlemesi ve bir re-apply olacak.&lt;/p&gt;

&lt;p&gt;Companion repo, seri boyunca her fazda biraz daha büyüyor:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;a href="https://github.com/Hakanbaban53/proxmox-automation" rel="noopener noreferrer"&gt;Link: GitHub repo; fazlarla eşleşen dizin yapısı, playbook'lar ve Terraform dosyaları&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bu fazı siz de kendi lab'ınızda denerseniz, 15 dakikalık uyarı sizin de karşınıza çıkacaktır; çözümü, yazının yukarısındaki o tek satırlık sigorta. Sorularınız, düzeltmeleriniz ve kendi karşılaştığınız tuzaklar için yorumlarda bekliyorum.&lt;/p&gt;

</description>
      <category>proxmox</category>
      <category>terraform</category>
      <category>ansible</category>
      <category>devops</category>
    </item>
    <item>
      <title># Redundant Links, İzleme Araçları ve Bir Affinity Kilitlenmesi (Modül 5)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Wed, 26 Aug 2026 06:32:30 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/-redundant-links-izleme-araclari-ve-bir-affinity-kilitlenmesi-modul-5-479j</link>
      <guid>https://dev.to/hakanbaban53/-redundant-links-izleme-araclari-ve-bir-affinity-kilitlenmesi-modul-5-479j</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seri:&lt;/strong&gt; Proxmox VE Cluster ve Corosync | Hafta 5&lt;/p&gt;




&lt;p&gt;Serinin adı "Cluster ve Corosync"; ama dört modüldür ağırlık HA Manager, resource affinity ve CRS'teydi, Corosync'in kendisine (redundant link'ler, izleme araçları) hiç dönmemiştim. Bu modülde iki konuyu birleştirip derinlemesine işledim: birden fazla corosync link'i tanımlayıp gerçekten birini kesip diğerinin devralmasını kanıtlamak, ve günlük operasyonda kullanılacak izleme araçlarını tek tek denemek. İkisi de planladığımdan çok daha fazla soru açtı; biri yanlış bir config anahtarı yüzünden saatler süren bir araştırmaya dönüştü, diğeri ise hiç beklemediğim bir kilitlenme keşfiyle bitti.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bölüm 1: Redundant Corosync Links
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Kurulum: İkinci Link'i Eklemek
&lt;/h3&gt;

&lt;p&gt;Şu ana kadar cluster'ımızda tek bir corosync link'i vardı (&lt;code&gt;link1&lt;/code&gt;, izole &lt;code&gt;corosync-net&lt;/code&gt; ağı). Management ağını (&lt;code&gt;192.168.122.x&lt;/code&gt;) &lt;code&gt;link0&lt;/code&gt; olarak ekleyip gerçek bir yedeklilik kurdum; &lt;code&gt;/etc/pve/corosync.conf&lt;/code&gt;'u kopyalayıp düzenleyip atomik olarak yerine taşıdım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; /etc/pve/corosync.conf /etc/pve/corosync.conf.new
&lt;span class="c"&gt;# nodelist'teki her node'a ring0_addr ekledim, totem'e ikinci bir interface bloğu ekledim&lt;/span&gt;
&lt;span class="nb"&gt;mv&lt;/span&gt; /etc/pve/corosync.conf.new /etc/pve/corosync.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Doğrulama:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;corosync-cfgtool &lt;span class="nt"&gt;-s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LINK ID 0 udp
    addr    = 192.168.122.11
    status: ... connected ... connected
LINK ID 1 udp
    addr    = 10.10.10.11
    status: ... connected ... connected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Teknik olarak başarılı; iki link de bağlı. Ama log'a dikkatlice bakınca, mimarimizin niyetini tersine çeviren bir şey oldu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[KNET  ] rx: host: 3 link: 0 is up
[KNET  ] host: host: 3 (passive) best link: 0 (pri: 1)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;link_mode: passive&lt;/code&gt; modunda, öncelik eşitken &lt;strong&gt;düşük numaralı link kazanıyor&lt;/strong&gt;. &lt;code&gt;link0&lt;/code&gt;'ı sonradan eklediğim için, o Corosync'in asıl trafiğini üstlenmiş; Modül 0'da özellikle izole ettiğimiz &lt;code&gt;corosync-net&lt;/code&gt; (&lt;code&gt;link1&lt;/code&gt;) sessizce yedek konuma düşmüştü.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yanlış Anahtar, Saatler Süren Bir Araştırma
&lt;/h3&gt;

&lt;p&gt;Bunu düzeltmek için &lt;code&gt;link1&lt;/code&gt;'e daha yüksek öncelik vermeye çalıştım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;linknumber&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;linknumber&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İşe yaramadı. &lt;code&gt;corosync-cmapctl | grep priority&lt;/code&gt; sadece &lt;strong&gt;tek, indekslenmemiş&lt;/strong&gt; bir satır gösterdi: &lt;code&gt;totem.interface.priority (str) = 10&lt;/code&gt;. Diğer parametreler (&lt;code&gt;knet_ping_interval&lt;/code&gt;, &lt;code&gt;knet_ping_timeout&lt;/code&gt;) düzgün şekilde &lt;code&gt;interface.0.*&lt;/code&gt; / &lt;code&gt;interface.1.*&lt;/code&gt; diye ayrılmışken, &lt;code&gt;priority&lt;/code&gt; öyle değildi. Log'da "best link" seçimi hâlâ &lt;code&gt;(pri: 1)&lt;/code&gt; gösteriyordu; bizim verdiğimiz değer hiç okunmamıştı.&lt;/p&gt;

&lt;p&gt;Tam bir servis restart'ının (&lt;code&gt;systemctl restart corosync&lt;/code&gt;) sorunu çözebileceğini düşündüm; denedim, çözmedi. Restart, &lt;code&gt;pve-a&lt;/code&gt;'yı ~13 saniyeliğine cluster'dan düşürdü (&lt;code&gt;Nodes: 1, Quorate: No&lt;/code&gt;), ama &lt;code&gt;priority&lt;/code&gt; yine tek, indekslenmemiş kaldı.&lt;/p&gt;

&lt;p&gt;Sebep, resmi man sayfasında (&lt;code&gt;corosync.conf(5)&lt;/code&gt;) çıktı: doğru anahtar &lt;code&gt;priority&lt;/code&gt; değil, &lt;strong&gt;&lt;code&gt;knet_link_priority&lt;/code&gt;&lt;/strong&gt;. Bizim yazdığımız &lt;code&gt;priority&lt;/code&gt;, geçerli bir knet parametresi olmadığı için corosync tarafından sessizce, gevşek bir yere yazılmış; hiçbir zaman gerçek link seçim mantığına girmemiş.&lt;/p&gt;

&lt;h3&gt;
  
  
  Doğru Syntax, Kesin Kanıt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;linknumber&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="nx"&gt;knet_link_priority&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;linknumber&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="nx"&gt;knet_link_priority&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;corosync-cmapctl | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"interface.*priority"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;totem.interface.0.knet_link_priority&lt;/span&gt; &lt;span class="err"&gt;(u8)&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;5&lt;/span&gt;
&lt;span class="err"&gt;totem.interface.1.knet_link_priority&lt;/span&gt; &lt;span class="err"&gt;(u8)&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu sefer düzgün indekslenmiş. Log de anında değişti:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[KNET  ] host: host: 3 (passive) best link: 0 (pri: 5)
[KNET  ] host: host: 3 (passive) best link: 1 (pri: 10)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Corosync her iki linki de değerlendirip yüksek öncelikli olanı (&lt;code&gt;link1&lt;/code&gt;, corosync-net) seçmiş.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kesme ve Geri Getirme Testi
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;link1&lt;/code&gt;'i fiziksel host'tan kestim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh domif-setlink pve-a vnet0 down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[KNET  ] link: host: 3 link: 1 is down
[KNET  ] host: host: 3 (passive) best link: 0 (pri: 5)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anında &lt;code&gt;link0&lt;/code&gt;'a geçiş; &lt;code&gt;pvecm status&lt;/code&gt; kesintisiz &lt;code&gt;Quorate: Yes&lt;/code&gt; kaldı, hâlâ tam oy sayısıyla. Sonra geri açtım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh domif-setlink pve-a vnet0 up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[KNET  ] rx: host: 3 link: 1 is up
[KNET  ] host: host: 3 (passive) best link: 1 (pri: 10)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Saniyeler içinde&lt;/strong&gt; &lt;code&gt;link1&lt;/code&gt;'e geri dönüş. Bu, hem failover'ı hem failback'i (yüksek öncelikli link geri gelince otomatik ona dönme) doğru anahtarla kesin olarak kanıtladı. İlk yanlış denemede ("sticky" davranış sandığım şey) aslında sadece önceliğin hiç uygulanmamış olmasıydı; gerçek mekanizma tam beklendiği gibi çalışıyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bölüm 2: İzleme Araçları
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;corosync-quorumtool&lt;/code&gt;: Daha Okunabilir Bir Alternatif
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;corosync-quorumtool &lt;span class="nt"&gt;-s&lt;/span&gt;
corosync-quorumtool &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İçerik &lt;code&gt;pvecm status&lt;/code&gt; ile aynı, ama membership tablosu hex ID (&lt;code&gt;0x00000001&lt;/code&gt;) yerine düz ondalık ID + doğrudan hostname gösteriyor. Günlük kullanımda daha okunabilir.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token/Consensus Formülünü Canlı Doğrulamak
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;corosync-cmapctl | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'totem.token|totem.consensus'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;runtime.config.totem.token&lt;/span&gt; &lt;span class="err"&gt;(u32)&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;3125&lt;/span&gt;
&lt;span class="err"&gt;runtime.config.totem.consensus&lt;/span&gt; &lt;span class="err"&gt;(u32)&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;3750&lt;/span&gt;
&lt;span class="err"&gt;totem.token_coefficient&lt;/span&gt; &lt;span class="err"&gt;(u32)&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="err"&gt;125&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modül 0'da bulduğumuz formül: &lt;code&gt;token = 3000 + (node_sayısı - 2) × token_coefficient&lt;/code&gt;. 3 node ile: &lt;code&gt;3000 + 1×125 = 3125&lt;/code&gt;. Tam uyuyor. &lt;code&gt;consensus = 1.2 × token = 3750&lt;/code&gt;. O da uyuyor. Aylar önce bir dokümandan öğrendiğimiz bir formülü, kendi cluster'ımızın gerçek sayılarıyla doğrulamış olduk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beklenmedik Bulgu: İki Ayrı &lt;code&gt;corosync.conf&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-cluster&lt;/code&gt; (pmxcfs) loglarına bakınca, hiç bilmediğimiz bir mekanizma ortaya çıktı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; pve-cluster &lt;span class="nt"&gt;-n&lt;/span&gt; 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[dcdb] notice: wrote new corosync config '/etc/corosync/corosync.conf' (version = 7)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bir saniye sonra, corosync log'unda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;[CFG] Config reload requested by node 1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Şimdiye kadar hep &lt;code&gt;/etc/pve/corosync.conf&lt;/code&gt;'u düzenledik; bu, pmxcfs üzerinden cluster geneline otomatik yayılan sanal bir dosya. Ama corosync daemon'ının kendisi aslında &lt;strong&gt;&lt;code&gt;/etc/corosync/corosync.conf&lt;/code&gt;&lt;/strong&gt;'u okuyor, farklı bir yol. pmxcfs bizim düzenlememizi algılayıp gerçek dosyayı arkada kendisi yazıyor, corosync de bunu saniyeler içinde fark edip reload istiyor. İki ayrı dosya, tek görünen arayüz.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yan Etki: Corosync Restart'ı HA'ya da Yayılıyor
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;systemctl restart corosync&lt;/code&gt; denememizin ardından, &lt;code&gt;pve-ha-crm&lt;/code&gt;/&lt;code&gt;pve-ha-lrm&lt;/code&gt; logları da bir "Boot" işareti ve yeniden başlatma döngüsü gösterdi; VM'ler yeniden başlatılmış, lock'lar yeniden alınmış. "Sadece corosync'i restart ettim" sanısı, HA katmanına da dalga dalga yayılabiliyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bölüm 3: Bir Node'u Gerçekten Çıkarmak
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prosedür
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt;'yi resmi prosedürle çıkardım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# pve-c'de&lt;/span&gt;
systemctl stop pve-cluster corosync

&lt;span class="c"&gt;# pve-a'da&lt;/span&gt;
pvecm delnode pve-c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes: 2
Expected votes: 3
Total votes: 3
Quorum: 2
    0x00000000    1    Qdevice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beklenmedik detay: &lt;strong&gt;QDevice oyu 2'den 1'e düşmüş.&lt;/strong&gt; &lt;code&gt;lms&lt;/code&gt; algoritmasının formülü &lt;code&gt;N-1&lt;/code&gt; (node sayısı eksi bir); önceden 3-1=2'ydi, şimdi 2-1=1. &lt;code&gt;pvecm delnode&lt;/code&gt;, node sayısını düşürse de QDevice algoritmasına (&lt;code&gt;lms&lt;/code&gt; olarak kalmaya devam ediyor) hiç dokunmuyor; bunu elle yönetmek bize düşüyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ortamın Kararsızlığı: Beklenmedik Bir HA Kilitlenmesi
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt; çıkarma işleminden sonra, &lt;code&gt;ha-manager status&lt;/code&gt; saatlerce şunu gösterdi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fencing standby (CRM watchdog standby)
lrm pve-a (wait_for_agent_lock, ...)
lrm pve-b (wait_for_agent_lock, ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Corosync/quorum seviyesi tamamen sağlıklıyken (&lt;code&gt;Quorate: Yes&lt;/code&gt;), HA CRM/LRM katmanı ayrı bir kilitte takılı kalmıştı. Loglardaki &lt;code&gt;Boot&lt;/code&gt; işaretleri, host laptop'un bu süre zarfında birkaç kez uyku/uyanma döngüsünden geçtiğini gösteriyordu; nested VM'ler bu geçişlerde bazen kendini resetliyor. Bu, kontrollü bir test değildi, dürüstçe belirtmem gerekiyor. Ama şunu net gösterdi: &lt;strong&gt;corosync seviyesinde quorum sağlıklı olması, HA katmanının da sağlıklı olduğu anlamına gelmiyor&lt;/strong&gt;; ikisi ayrı ayrı bozulabiliyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bölüm 4: &lt;code&gt;lms&lt;/code&gt;'ten &lt;code&gt;ffsplit&lt;/code&gt;'e Geçiş
&lt;/h2&gt;

&lt;p&gt;Artık gerçekten 2 node'dayız; Modül 2'de "resmi olarak desteklenmiyor" dediğimiz &lt;code&gt;lms&lt;/code&gt; yerine, resmi olarak önerilen &lt;code&gt;ffsplit&lt;/code&gt;'i test edebileceğimiz ilk an bu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/algorithm: lms/algorithm: ffsplit/'&lt;/span&gt; corosync.conf.new
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Total votes: 3
    0x00000000    1    Qdevice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;QDevice oyu &lt;strong&gt;1&lt;/strong&gt;'de kaldı; &lt;code&gt;ffsplit&lt;/code&gt; her zaman sabit 1 oy veriyor, &lt;code&gt;lms&lt;/code&gt;'in değişken &lt;code&gt;N-1&lt;/code&gt; formülü değil. 2-node özelinde rakamsal sonuç aynı görünüyor (zaten &lt;code&gt;N-1=1&lt;/code&gt; burada), ama mekanizma temelden farklı; asıl fark bir node düştüğünde ortaya çıkacak.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gerçek Bir 2-Node + QDevice Testi
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-b&lt;/code&gt;'yi çökerttim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh destroy pve-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes: 1
Total votes: 2
Quorum: 2
Quorate: Yes
    0x00000001    1    pve-a
    0x00000000    1    Qdevice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt; (1 oy) + QDevice (&lt;code&gt;ffsplit&lt;/code&gt;'in sabit 1 oyu) = 2, eşik de 2. &lt;strong&gt;Quorate: Yes.&lt;/strong&gt; Bu, Modül 2'de simüle ettiğimiz senaryonun, artık gerçekten resmi olarak desteklenen 2-node yapılandırmasında, doğru algoritmayla çalıştığının kanıtı.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bölüm 5: Beklenmedik Kapanış, Affinity Kilitlenmesi
&lt;/h2&gt;

&lt;p&gt;Asıl beklemediğim şey burada oldu. VM 102 (o an &lt;code&gt;pve-b&lt;/code&gt;'deydi) için &lt;code&gt;ha-manager status&lt;/code&gt;, &lt;code&gt;fence&lt;/code&gt; durumundan sonra sonsuza kadar &lt;strong&gt;&lt;code&gt;recovery&lt;/code&gt;&lt;/strong&gt;'de takılı kaldı. Loglara baktım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; pve-ha-crm &lt;span class="nt"&gt;-n&lt;/span&gt; 40 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"102"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;08:16:50  recovering service 'vm:102' from fenced node 'pve-b' failed, no recovery node found
08:17:00  recovering service 'vm:102' from fenced node 'pve-b' failed, no recovery node found
08:17:10  recovering service 'vm:102' from fenced node 'pve-b' failed, no recovery node found
... (her 10 saniyede bir, kesintisiz tekrarlanıyor)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sebep: Modül 4'te tanımladığımız negatif resource affinity kuralı (VM 100 ve 102 asla aynı node'da olamaz) hâlâ aktifti. Tek ayakta kalan node (&lt;code&gt;pve-a&lt;/code&gt;) zaten VM 100'ü barındırıyordu; VM 102 için &lt;strong&gt;yasal hiçbir hedef yoktu&lt;/strong&gt;. Sistem bu imkansız durumu, Modül 4'teki gerçek migration hatasından (&lt;code&gt;exit code 255&lt;/code&gt;, birkaç denemeden sonra &lt;code&gt;error&lt;/code&gt; state'ine düşme) tamamen farklı bir şekilde ele aldı: &lt;strong&gt;hiç &lt;code&gt;error&lt;/code&gt;'a düşmedi&lt;/strong&gt;, sadece sessizce, sabırla, her 10 saniyede bir yeniden denemeye devam etti.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pve-b&lt;/code&gt;'yi geri getirdim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh start pve-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Birkaç dakika sonra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lrm pve-b (active, ...)
service vm:102 (pve-b, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-b&lt;/code&gt; geri gelir gelmez, VM 102 için nihayet yasal bir hedef oluştu (VM 100'den uzak), ve kilitlenme kendiliğinden çözüldü.&lt;/p&gt;

&lt;p&gt;Bu, Modül 3'teki "yanlış çalışmaya devam etmektense hiç çalışmamak" fail-safe felsefesinin bir üst seviyesi: burada sistem "hiç çalışmamayı" bile seçmedi, "kuralı çiğnemektense sonsuza kadar beklemeyi" seçti. HA'nın kendi kurtarma mantığı, kendi affinity kurallarıyla çelişkiye düşebiliyor, ve sistem bunu görmezden gelmiyor; askıda bırakıyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Bu modül, planladığımdan çok daha derin bir yere gitti, ve muhtemelen serinin en yoğun modülü oldu.&lt;/p&gt;

&lt;p&gt;Birincisi, &lt;code&gt;priority&lt;/code&gt; yerine &lt;code&gt;knet_link_priority&lt;/code&gt; gerektiği yanlış anahtar hatası. Saatler süren bir araştırmaya (config reload mı restart mı, cmapctl'in tuhaf tek satırı, "sticky" yanlış hipotezi) yol açtı, ama sonunda man sayfasını okumanın (tahmin etmek yerine) değerini bir kez daha kanıtladı.&lt;/p&gt;

&lt;p&gt;İkincisi, pmxcfs'in arkada iki ayrı corosync.conf dosyası yönetmesi. Beş modüldür &lt;code&gt;/etc/pve/corosync.conf&lt;/code&gt;'u düzenliyorduk, corosync'in gerçekte &lt;code&gt;/etc/corosync/corosync.conf&lt;/code&gt;'u okuduğunu hiç fark etmemiştik.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, ve en değerlisi: affinity kilitlenmesi. Bunu planlamamıştık; gerçek bir node çıkarma operasyonunun, gerçek bir node çökmesinin, ve Modül 4'te tanımladığımız bir kuralın kesişiminde kendiliğinden ortaya çıktı. HA'nın "kuralı çiğnemektense sonsuza kadar bekle" tercihi, sistemin ne kadar temkinli tasarlandığını gösteren en net kanıt oldu.&lt;/p&gt;

&lt;p&gt;Bu seride Corosync'in temellerinden (Modül 1) quorum'a (Modül 2), HA Manager'a (Modül 3), resource affinity ve CRS'e (Modül 4), ve şimdi redundant link'lere ve izleme araçlarına kadar geniş bir yüzeyi gezdim. Her modülde en az bir varsayımım yanlış çıktı, ve neredeyse her seferinde yanlış çıkan varsayım, doğru olandan daha çok şey öğretti. Bu, sanırım bu serinin özeti: hazır bir HOL yokken, doğru cevabı bilmiyor olmak bir eksiklik değil, öğrenmenin kendisiydi.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri, resmi Proxmox VE dokümantasyonundan (pve.proxmox.com), corosync man sayfalarından, ve topluluk kaynaklarından 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.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>infrastructure</category>
      <category>linux</category>
      <category>monitoring</category>
      <category>networking</category>
    </item>
    <item>
      <title># Resource Affinity, CRS ve Bir Gece Boyu Salınım (Modül 4)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Fri, 21 Aug 2026 05:50:06 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/-resource-affinity-crs-ve-bir-gece-boyu-salinim-modul-4-ji9</link>
      <guid>https://dev.to/hakanbaban53/-resource-affinity-crs-ve-bir-gece-boyu-salinim-modul-4-ji9</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seri:&lt;/strong&gt; Proxmox VE Cluster ve Corosync&lt;/p&gt;




&lt;p&gt;Modül 3'ün sonunda söz vermiştim: birden fazla VM ile resource affinity kurallarını (aynı node'da tutma/ayrı tutma) ve CRS'in (Cluster Resource Scheduler) yük dengeleme davranışını test edecektim. Planım basitti: birkaç kural ekle, birkaç migration dene, sonuçları yaz. Gerçekte olan şu oldu: bir gece boyu süren beklenmedik bir salınım, gerçek bir HA arızası, ve kendi verdiğim yanlış bir talimatın beni yanlış bir teşhise sürüklemesi. Hepsini olduğu gibi anlatıyorum.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kavramlar: Resource Affinity ve CRS
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk65rrq1zr0o2edy2gyjz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk65rrq1zr0o2edy2gyjz.png" alt="Resource Affinity &amp;amp; CRS" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource affinity&lt;/strong&gt;, node-affinity'den farklı bir şey; node-affinity bir VM'i belirli node'lara bağlarken, resource affinity iki veya daha fazla VM'i &lt;strong&gt;birbirine göre&lt;/strong&gt; konumlandırıyor. İki tipi var: &lt;strong&gt;pozitif&lt;/strong&gt; (belirtilen kaynaklar hep aynı node'da olmalı) ve &lt;strong&gt;negatif&lt;/strong&gt; (hep farklı node'larda olmalı). Resmi dokümantasyona göre negatif bir kuralda cluster'daki node sayısından fazla kaynak olamıyor (bizim 3 node'umuzda en fazla 3 kaynak), ve aynı VM çifti aynı anda hem pozitif hem negatif bir kuralda olamıyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CRS (Cluster Resource Scheduler)&lt;/strong&gt;, HA kaynaklarının hangi node'a yerleştirileceğine karar veren mekanizma. Üç mod var: &lt;code&gt;basic&lt;/code&gt; (sadece guest sayısına bakar), &lt;code&gt;static&lt;/code&gt; (yapılandırılmış CPU/RAM kotalarını da hesaba katar), &lt;code&gt;dynamic&lt;/code&gt; (gerçek zamanlı kullanımı da hesaba katar). Dynamic mod, isteğe bağlı bir &lt;strong&gt;otomatik yeniden dengeleme&lt;/strong&gt; (auto-rebalance) özelliği de sunuyor; cluster dengesizliği belirli bir eşiği aşarsa, otomatik migration'lar tetikliyor. Config, &lt;code&gt;/etc/pve/datacenter.cfg&lt;/code&gt; içinde &lt;code&gt;crs: ha=dynamic,ha-auto-rebalance=1,ha-auto-rebalance-threshold=&amp;lt;yüzde&amp;gt;,ha-auto-rebalance-hold-duration=&amp;lt;tur&amp;gt;&lt;/code&gt; şeklinde tutuluyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 1: Test VM'lerini Hazırlamak
&lt;/h2&gt;

&lt;p&gt;VM 100'ü iki kez klonladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm clone 100 101 &lt;span class="nt"&gt;--name&lt;/span&gt; alpine-b &lt;span class="nt"&gt;--full&lt;/span&gt;
qm clone 100 102 &lt;span class="nt"&gt;--name&lt;/span&gt; alpine-c &lt;span class="nt"&gt;--full&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İkisini de HA'ya ekledim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager add vm:101 &lt;span class="nt"&gt;--state&lt;/span&gt; started
ha-manager add vm:102 &lt;span class="nt"&gt;--state&lt;/span&gt; started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İlk &lt;code&gt;ha-manager status&lt;/code&gt; çıktısında üçü de &lt;code&gt;pve-a&lt;/code&gt;'da görünüyordu. İlk bakışta "pozitif affinity zaten çalışıyor" diye düşünebilirdim, ama bu yanlış bir sonuç olurdu: &lt;code&gt;qm clone&lt;/code&gt;'u &lt;code&gt;pve-a&lt;/code&gt;'dan çalıştırdığım için, yeni VM'lerin config dosyaları zaten oraya oluşmuştu; hiçbir kural henüz devrede değildi. Tesadüfi yerleşimi kanıt sanmak, bu modülün ilk dersi oldu.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 2: Pozitif Resource Affinity, Gerçek Bir Test
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager rules add resource-affinity keep-together &lt;span class="nt"&gt;--affinity&lt;/span&gt; positive &lt;span class="nt"&gt;--resources&lt;/span&gt; vm:100,vm:101
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gerçek kanıt için, kuralı ihlal etmeye çalıştım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm migrate 101 pve-c &lt;span class="nt"&gt;--online&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cannot migrate resource 'vm:101' to node 'pve-c':
- resource 'vm:101' not allowed on target node 'pve-c'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reddedildi. Kural gerçekten çalışıyor; VM 100 &lt;code&gt;pve-a&lt;/code&gt;'ya bağlı olduğu (Modül 3'ten kalma node-affinity kuralı) için, 101'in oradan ayrılmasına izin verilmiyor. Manuel bir taşımayı bile engellemesi, bunun tesadüfi değil aktif bir kısıtlama olduğunu kanıtlıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beklenmedik Bir İsimlendirme Gizemi
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ha-manager rules list&lt;/code&gt; çalıştırdığımda, Modül 3'te &lt;code&gt;prefer-pve-a&lt;/code&gt; adıyla oluşturduğum node-affinity kuralının artık &lt;code&gt;ha-rule-ae59af1e-b08f&lt;/code&gt; gibi bir hash olarak göründüğünü fark ettim. Kendiliğinden değişmemişti; ben bir ara bu kuralı web arayüzünden silip yine web arayüzünden yeniden eklemiştim. Yeni eklediğim &lt;code&gt;keep-together&lt;/code&gt; (CLI'dan) ise ismini koruyordu. &lt;code&gt;/etc/pve/ha/rules.cfg&lt;/code&gt;'ye bakınca ikisi de doğrulandı. Sebebi araştırınca netleşti: GUI'nin "Add" formunda isim alanı yok; boş bırakılınca backend otomatik bir hash üretiyor. Bunu doğrulamak için CLI'dan ayrı bir isim testi yaptım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager rules add node-affinity test-isim-korunuyor-mu &lt;span class="nt"&gt;--resources&lt;/span&gt; vm:102 &lt;span class="nt"&gt;--nodes&lt;/span&gt; pve-c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu isim korundu. Sonuç: &lt;strong&gt;CLI'dan eklenen kurallar verdiğin ismi koruyor, GUI'den eklenenler otomatik hash alıyor.&lt;/strong&gt; Küçük ama gerçek bir GUI/CLI farkı; benim başıma gelme sebebi kuralı GUI üzerinden silip tekrar eklemem oldu, sistemin kendi kendine isim değiştirmesi değil.&lt;/p&gt;

&lt;p&gt;Aynı ekleme işlemi web arayüzünden Datacenter → HA → Affinity Rules → HA Node Affinity Rules altında "Add" butonuyla da yapılabiliyor; iddiamı bu ekranı görünce doğruladım, gerçekten bir isim alanı yok:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsw9udgiys2m6djplyb94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsw9udgiys2m6djplyb94.png" alt="Web UI dan Affinity Rule Ekleme" width="600" height="494"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 3: Negatif Resource Affinity, Proaktiflik ve Geçişli Çıkarım
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager rules add resource-affinity keep-separate &lt;span class="nt"&gt;--affinity&lt;/span&gt; negative &lt;span class="nt"&gt;--resources&lt;/span&gt; vm:100,vm:102
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hiçbir manuel migration yapmadan, &lt;code&gt;ha-manager status&lt;/code&gt;'a tekrar baktığımda VM 102'nin &lt;strong&gt;kendiliğinden&lt;/strong&gt; &lt;code&gt;pve-c&lt;/code&gt;'ye taşınmış olduğunu gördüm; Modül 3'teki proaktif node-affinity bulgusunun resource-affinity için de geçerli olduğu kanıtlandı.&lt;/p&gt;

&lt;p&gt;Sonra kuralı ihlal etmeye çalıştım: VM 102'yi (&lt;code&gt;pve-c&lt;/code&gt;'de), VM 100'ün olduğu &lt;code&gt;pve-a&lt;/code&gt;'ya geri çekmeye:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm migrate 102 pve-a &lt;span class="nt"&gt;--online&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cannot migrate resource 'vm:102' to node 'pve-a':
- resource 'vm:100' on target node 'pve-a' in negative affinity with resource 'vm:102'
- resource 'vm:101' on target node 'pve-a' in negative affinity with resource 'vm:102'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İkinci satır beni şaşırttı: &lt;code&gt;vm:101&lt;/code&gt; için hiç negatif kural tanımlamamıştım. Sistem bunu kendisi türetmiş: &lt;code&gt;vm:101&lt;/code&gt;, &lt;code&gt;vm:100&lt;/code&gt;'le pozitif kuralda (birlikte kalmalı); &lt;code&gt;vm:100&lt;/code&gt; da &lt;code&gt;vm:102&lt;/code&gt;'yle negatif kuralda (asla birlikte olmamalı). Motor bu iki kuralı birleştirip, açıkça yazılmamış üçüncü bir kısıtlamayı &lt;strong&gt;geçişli olarak&lt;/strong&gt; çıkarmış: &lt;code&gt;vm:101&lt;/code&gt; de &lt;code&gt;vm:102&lt;/code&gt;'den uzak durmalı. Kural motoru sadece her kuralı tek tek kontrol etmiyor, aralarında mantıksal çıkarım yapıyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 4: CRS'i Etkinleştirmek, Yanlış Bir İzin Peşinde
&lt;/h2&gt;

&lt;p&gt;Dynamic CRS'i, testi hızlandırmak için agresif ayarlarla açtım: threshold %10, hold-duration 1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0xdx8ywvgtbkig5sz47z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0xdx8ywvgtbkig5sz47z.png" alt="Datacenter → Options → Cluster Resource Scheduling: Dynamic Load, Automatic Rebalance, Threshold %10, Hold Duration 1" width="447" height="329"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;master pve-b (active, ...) - dynamic load CRS (load imbalance: 8.1%)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;%8.1 &amp;lt; %10&lt;/code&gt; olduğu için hiçbir şey taşınmadı; beklenen davranış. Eşiği &lt;code&gt;%1&lt;/code&gt;'e düşürdüm, ama yine hiçbir taşıma olmadı, dengesizlik &lt;code&gt;%9.3&lt;/code&gt; göstermesine rağmen. Bunun sebebini GUI'den migration denemesiyle araştırdım:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6kfcy0le1bpnfs0dbx6x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6kfcy0le1bpnfs0dbx6x.png" alt="Migrate VM 102, pve-a hedefi, " width="599" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbdolir7bml9mavg8wo7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbdolir7bml9mavg8wo7x.png" alt="Migrate VM 102, pve-b hedefi, " width="599" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pve-b&lt;/code&gt; hedefindeki hata daha az detaylıydı, ve gerçek sebep CRS ile hiç ilgili değildi: Uygulama 2'de test amaçlı eklediğim &lt;code&gt;test-isim-korunuyor-mu&lt;/code&gt; kuralı (VM 102'yi &lt;code&gt;pve-c&lt;/code&gt;'ye sabitleyen) hâlâ duruyordu, hiç silmemiştim. Kalıntıyı temizleyince:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager rules remove test-isim-korunuyor-mu
ha-manager migrate vm:102 pve-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu sefer kabul edildi. Ders: kendi test kalıntılarını temizlemeden bir sonraki testi yorumlamaya çalışmak, yanlış sonuçlara götürebiliyor. "Kesin CRS'in suçu" diye düşünüp geçebilirdim; gerçek sebep çok daha sıradandı.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 5: 12 Dakikalık Salınım
&lt;/h2&gt;

&lt;p&gt;Temiz zeminde CRS'i test etmeye devam ettim. Saatler sonra loglara dönünce, &lt;code&gt;journalctl -u pve-ha-crm&lt;/code&gt; çıktısında beklemediğim bir şey buldum: 21:38 ile 21:50 arası, &lt;strong&gt;tam 12 dakika boyunca&lt;/strong&gt;, VM 102 her ~20 saniyede bir &lt;code&gt;pve-b&lt;/code&gt; ile &lt;code&gt;pve-c&lt;/code&gt; arasında ileri geri taşınmış:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;21:38:27  auto rebalance - migrate vm:102 to pve-c (imbalance from 6.0% to 5.0%)
21:38:47  auto rebalance - migrate vm:102 to pve-b (imbalance from 12.0% to 9.8%)
21:39:07  auto rebalance - migrate vm:102 to pve-c (imbalance from 10.9% to 8.8%)
21:39:27  auto rebalance - migrate vm:102 to pve-b (imbalance from 9.4% to 7.2%)
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Bu desen, yaklaşık 20 saniyede bir tekrarlanarak devam ediyor.)&lt;/p&gt;

&lt;p&gt;Her taşıma "dengesizliği azaltıyor" gibi görünüyor, ama taşıdıktan hemen sonra tekrar dengesiz hale geliyor, sistem tekrar taşıyor; klasik bir salınım. Sebebi büyük ihtimalle bizim test için verdiğimiz aşırı agresif ayarlar (&lt;code&gt;threshold=1%&lt;/code&gt;, &lt;code&gt;hold-duration=1&lt;/code&gt;). Gerçek bir ortamda bu ayarlarla çalışmak, sürekli gereksiz migration'a ve VM'ler için mikro kesintilere yol açardı. Bu, dynamic CRS'in varsayılan ayarlarının (yaklaşık %30 eşik, daha uzun hold-duration) neden öyle seçildiğini somut olarak gösterdi.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 6: Gerçek Bir Arıza
&lt;/h2&gt;

&lt;p&gt;Salınım 21:50'de durmuş, ama ondan 9 saat sonra, sabaha karşı, gerçek bir arıza oluşmuş:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;07:46:58  service 'vm:102' - migration failed (exit code 255)
07:47:18  starting service vm:102 on node 'pve-b' failed, relocating service.
07:47:28  service 'vm:102' - migration failed (exit code 255)
07:47:48  recovery policy for service vm:102 failed, entering error state. Failed nodes: pve-b, pve-b
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VM &lt;code&gt;error&lt;/code&gt; state'ine düşmüştü. &lt;code&gt;qm status 102&lt;/code&gt;, &lt;code&gt;pve-b&lt;/code&gt;'de "stopped", &lt;code&gt;pve-c&lt;/code&gt;'de "config dosyası yok" diyordu; disk ve NFS bağlantısı sağlıklıydı. Asıl ipucu &lt;code&gt;/var/lock/qemu-server/lock-102.conf&lt;/code&gt; dosyasıydı; başarısız migration'ın arkasında bıraktığı bir kilit.&lt;/p&gt;

&lt;p&gt;Proxmox'un resmi hata kurtarma prosedürünü uyguladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager &lt;span class="nb"&gt;set &lt;/span&gt;vm:102 &lt;span class="nt"&gt;--state&lt;/span&gt; disabled
qm unlock 102
qm start 102
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu üçüncü komut başarılı oldu; VM gerçekten çalışmaya başladı (&lt;code&gt;VM 102 started with PID 3490&lt;/code&gt;). Kilit, sorunun gerçek sebebiydi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kendi Verdiğim Yanlış Bir Talimat
&lt;/h3&gt;

&lt;p&gt;Buradan sonra "temiz bir devir" için VM'i durdurup HA'ya tekrar devretmeyi önermiştim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm stop 102
ha-manager &lt;span class="nb"&gt;set &lt;/span&gt;vm:102 &lt;span class="nt"&gt;--state&lt;/span&gt; started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VM birkaç saniye sonra durmuş görününce bir an paniğe kapıldım: "neden durdu?" Log'a bakınca gerçek sebep ortaya çıktı: VM 07:57:42'de başarıyla başlamıştı, ama benim önerdiğim &lt;code&gt;qm stop&lt;/code&gt; komutu tam 9 saniye sonra (07:57:51) onu durdurmuştu. Gizemli bir sistem davranışı değildi; benim gereksiz bir talimatımdı. Asıl düzeltme (&lt;code&gt;qm unlock&lt;/code&gt;) tek başına yeterliydi.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 7: İkinci Bir Salınım, Ve Kalıcı Çözüm
&lt;/h2&gt;

&lt;p&gt;VM'i tekrar &lt;code&gt;--state started&lt;/code&gt; yapınca, HA onu &lt;code&gt;pve-b&lt;/code&gt;'de başlattı, ama 20 saniye sonra CRS onu tekrar &lt;code&gt;pve-c&lt;/code&gt;'ye taşıdı, 30 saniye sonra &lt;code&gt;pve-b&lt;/code&gt;'ye geri getirdi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;08:02:59  service 'vm:102': state changed to 'started' (node = pve-b)
08:03:19  auto rebalance - migrate vm:102 to pve-c (imbalance from 18.4% to 15.4%)
08:03:49  auto rebalance - migrate vm:102 to pve-b (imbalance from 7.0% to 6.3%)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uygulama 5'teki salınım hâlâ aktifti; recovery'nin üstüne binmişti. &lt;code&gt;ha-auto-rebalance&lt;/code&gt;'ı hiç kapatmamıştık. Kapattım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/ha-auto-rebalance=1/ha-auto-rebalance=0/'&lt;/span&gt; /etc/pve/datacenter.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sed&lt;/code&gt; ile metin üzerinde arama-değiştirme yapmak, teknik olarak çalışsa da bir risk taşıyor: yanlış bir eşleşme ya da beklenmedik bir format farkı, dosyayı sessizce bozabilir. Aynı değişikliği web arayüzünden yapmak daha güvenli; &lt;code&gt;Datacenter → Options → Cluster Resource Scheduling&lt;/code&gt; ekranına dönüp "Automatic Rebalance" kutusunu kaldırmak yeterli:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9dww18hdmhm05d5ptt79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9dww18hdmhm05d5ptt79.png" alt="Cluster Resource Scheduling - Automatic Rebalance kapatma" width="451" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Birkaç dakika sonra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;master pve-c (active, ...) - dynamic load CRS
service vm:102 (pve-c, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VM artık sabit. Küçük bir bonus gözlem: &lt;code&gt;master&lt;/code&gt; satırındaki &lt;code&gt;(load imbalance: X%)&lt;/code&gt; yüzdesi de kaybolmuş; muhtemelen bu hesaplama sadece auto-rebalance aktifken yapılıp gösteriliyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Bu modül, planladığımdan tamamen farklı bir yere gitti, ve sanırım bu yüzden serinin en zengin modüllerinden biri oldu.&lt;/p&gt;

&lt;p&gt;Birincisi, resource affinity kurallarının geçişli çıkarım yapması. İki kuralı ayrı ayrı yazdım (100-101 pozitif, 100-102 negatif), ama sistem bunları birleştirip yazmadığım üçüncü bir kısıtlamayı (101-102 negatif) kendisi türetti. Bu, kural motorunun basit bir liste kontrolünden çok daha fazlası olduğunu gösterdi.&lt;/p&gt;

&lt;p&gt;İkincisi, agresif CRS ayarlarının gerçek bir tehlikeyi somutlaştırması. 12 dakikalık salınımı görmeden önce "düşük eşik = daha duyarlı sistem" gibi soyut bir fikrim vardı. Gördükten sonra bunun "sürekli gereksiz migration" anlamına geldiğini anladım; varsayılan ayarların neden temkinli seçildiğini artık deneyimledim.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, ve belki en önemlisi: kendi verdiğim bir talimatın (gereksiz &lt;code&gt;qm stop&lt;/code&gt;) beni yanlış bir teşhise sürüklemesi. Bir rehber, bir dokümantasyon, hatta bir AI asistanı bile, doğrulanmamış bir öneri verdiğinde yanlış ize sürükleyebiliyor. Log'a dönüp gerçek zaman damgalarını karşılaştırmak, "sistem tuhaf davranıyor" sanısını "ben tuhaf bir şey yaptım" gerçeğine çevirdi. Bu ders, teknik bir bulgudan çok, bir çalışma disiplini: iddia etmeden önce logu aç.&lt;/p&gt;

&lt;p&gt;Bir sonraki modülde seriyi toparlayacağım: bu dört modülde öğrendiklerimi (Corosync temelleri, quorum, QDevice, HA Manager, resource affinity, CRS) bir araya getiren bir kapanış, ve muhtemelen bir sonraki öğrenme hedefine (Ceph ya da başka bir konu) işaret eden bir bakış.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri, resmi Proxmox VE dokümantasyonundan (pve.proxmox.com) 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.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title># HA Manager: Watchdog, Fencing ve Node Affinity (Modül 3)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Mon, 17 Aug 2026 05:59:07 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/-ha-manager-watchdog-fencing-ve-node-affinity-modul-3-3fng</link>
      <guid>https://dev.to/hakanbaban53/-ha-manager-watchdog-fencing-ve-node-affinity-modul-3-3fng</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seri:&lt;/strong&gt; Proxmox VE Cluster ve Corosync&lt;/p&gt;




&lt;p&gt;Modül 1'de bir node çökünce VM'in kendiliğinden hiçbir yerde açılmadığını göstermiştim; cluster kurmak otomatik yüksek erişilebilirlik demek değildi. Bu modülde o boşluğu dolduran parçaya geçiyorum: HA Manager. Watchdog tabanlı fencing'i, gerçek bir node çökmesinde recovery'nin saniye saniye nasıl işlediğini, ve bir node affinity kuralının beklediğimden çok daha proaktif davrandığını, hepsini gerçekten test ederek öğrendim.&lt;/p&gt;

&lt;p&gt;Bu modülde her adımı hem terminalden hem web arayüzünden gösteriyorum; ikisi aynı API'yi kullanıyor, ama bazen birini görmek diğerini daha iyi anlamana yardımcı oluyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  HA Manager Nedir?
&lt;/h2&gt;

&lt;p&gt;Proxmox VE'nin HA stack'i, Pacemaker gibi harici bir araç gerektirmiyor; kendi başına çalışan bir çözüm. İki daemon var: &lt;strong&gt;pve-ha-lrm&lt;/strong&gt; (Local Resource Manager), her node'da çalışıp o node'daki servisleri kontrol ediyor; &lt;strong&gt;pve-ha-crm&lt;/strong&gt; (Cluster Resource Manager), cluster genelinde kararlar alıyor, sadece bir node'da aktif "master" olabiliyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fencing&lt;/strong&gt;, bir node arızalandığında onun gerçekten "offline" olduğundan emin olma süreci. Bu kritik, çünkü fence edilmemiş bir node hâlâ shared storage'a erişebiliyor olabilir; aynı VM'i başka bir node'da başlatmak, iki node'un aynı diske aynı anda yazmasına yol açabilir. Proxmox, harici fencing donanımı gerektirmeyen bir yöntem kullanıyor: &lt;strong&gt;watchdog timer tabanlı self-fencing&lt;/strong&gt;. &lt;code&gt;ha-manager&lt;/code&gt;, watchdog timer'ı düzenli olarak resetliyor; bir arıza nedeniyle bu reset gerçekleşmezse, timer node'u otomatik olarak reboot ediyor.&lt;/p&gt;

&lt;p&gt;Burada altta yatan tasarım felsefesi ilginç: node'un "belki çalışıyordur, belki bozuktur" gibi belirsiz bir durumda kalmasına izin verilmiyor, doğrudan tam bir reboot'a zorlanıyor. Mantığı şu: bir node yarım yamalak, tutarsız bir durumda çalışmaya devam ederse (örneğin ağı kopmuş ama diski hâlâ yazabiliyorsa), bu durum veri bozulmasına yol açabilir; oysa node tamamen durursa, en azından zarar vermeye devam etmiyor. Yanlış çalışmaya devam etmektense hiç çalışmamak, burada bilinçli bir güvenlik tercihi.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 1: Watchdog'u Doğrulamak
&lt;/h2&gt;

&lt;p&gt;Nested lab'ımda donanım watchdog yok, Proxmox varsayılan olarak &lt;code&gt;softdog&lt;/code&gt; kernel modülüne düşüyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/default/pve-ha-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# select watchdog module (default is softdog)
#WATCHDOG_MODULE=ipmi_watchdog
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Satır yorumlu, yani varsayılan (&lt;code&gt;softdog&lt;/code&gt;) kullanılıyor. Doğrulamak için ilk denediğim komut boş döndü:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsmod | &lt;span class="nb"&gt;grep &lt;/span&gt;watchdog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(boş çıktı)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bir an modülün yüklü olmadığını düşündüm. Ama hata bendeydi: "softdog" kelimesi harfi harfine "watchdog" içermiyor. Doğrusu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lsmod | &lt;span class="nb"&gt;grep &lt;/span&gt;dog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;softdog                12288  2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modül yüklü. &lt;code&gt;/dev/watchdog&lt;/code&gt; ve &lt;code&gt;/dev/watchdog0&lt;/code&gt; cihazları da mevcuttu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /dev/watchdog&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;crw------- 1 root root  10, 130 Aug 15 07:41 /dev/watchdog
crw------- 1 root root 243,   0 Aug 15 07:41 /dev/watchdog0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Uygulama 2: VM'i HA'ya Eklemek
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager add vm:100 &lt;span class="nt"&gt;--state&lt;/span&gt; started
ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;quorum OK
master pve-a (active, ...)
fencing armed (CRM watchdog active)
lrm pve-a (active, watchdog active, ...)
lrm pve-b (idle, watchdog standby, ...)
lrm pve-c (idle, watchdog standby, ...)
service vm:100 (pve-a, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aynı işlem web arayüzünden de yapılabiliyor: &lt;code&gt;Datacenter → HA → Resources&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhczpptwnowhb95w27sn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwhczpptwnowhb95w27sn.png" alt="Datacenter → HA → Resources ekranı, boş kaynak listesi" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Add" butonuna basıp VM'i ve başlangıç durumunu (&lt;code&gt;started&lt;/code&gt;) seçiyorsun:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdghrlgru3ielpprdl0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdghrlgru3ielpprdl0m.png" alt="Add HA Resource diyaloğu - VM 100 ve state seçimi" width="599" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dikkat çeken bir detay: &lt;code&gt;pve-a&lt;/code&gt; hem VM'i barındırıyor hem de CRM master'ı. Bu, sıradaki testi daha ilginç kılıyor; &lt;code&gt;pve-a&lt;/code&gt;'yı çökertince sadece VM'in taşınıp taşınmayacağını değil, cluster'ın yeni bir master seçip seçemeyeceğini de gözlemleyeceğim.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 3: Gerçek Bir Çökme, Saniye Saniye
&lt;/h2&gt;

&lt;p&gt;Host'tan ping'i başlattım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping 192.168.122.251
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5nvdcyorvxynjaxshda2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5nvdcyorvxynjaxshda2.png" alt="Ping başlatma - terminal görüntüsü" width="641" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sonra &lt;code&gt;pve-a&lt;/code&gt;'yı fiziksel host'tan çökerttim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh destroy pve-a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ping çıktısı Modül 1/2'deki tanıdık deseni tekrarladı: önce sessiz paket kaybı, sonra gateway'in aktif "Destination Host Unreachable" demesi.&lt;/p&gt;

&lt;p&gt;İlk kontrolüm (çökmeden ~10 saniye sonra), &lt;code&gt;pve-b&lt;/code&gt;'den:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;quorum OK
master pve-c (active, ...)
fencing armed (CRM watchdog active)
lrm pve-a (active, watchdog active, ...)
lrm pve-b (idle, watchdog standby, ...)
lrm pve-c (idle, watchdog standby, ...)
service vm:100 (pve-a, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yeni master seçimi hızlı gerçekleşmişti (&lt;code&gt;master pve-c&lt;/code&gt; olmuştu), ama VM henüz taşınmamıştı; bu, sürecin ortasında bir "anlık fotoğraf". Birkaç dakika sonra aynı komutu tekrar çalıştırdım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;quorum OK
master pve-c (active, ...)
fencing armed (CRM watchdog active)
lrm pve-a (old timestamp - dead?, watchdog standby, ...)
lrm pve-b (active, watchdog active, ...)
lrm pve-c (idle, watchdog standby, ...)
service vm:100 (pve-b, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9fe627x7bmb9r5usln5a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9fe627x7bmb9r5usln5a.png" alt="HA Status ekranı - vm:100 pve-b'de started, lrm pve-a " width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VM gerçekten &lt;code&gt;pve-b&lt;/code&gt;'ye taşınmış. &lt;code&gt;lrm pve-a&lt;/code&gt;'nın durumu da ilginçti: sistem bile kesin konuşmuyor, "old timestamp - dead?" diye soru işaretiyle yazıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tam Zaman Çizelgesi
&lt;/h3&gt;

&lt;p&gt;Tahmin etmek yerine &lt;code&gt;pve-c&lt;/code&gt;'nin (master) CRM loglarına baktım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;-u&lt;/span&gt; pve-ha-crm &lt;span class="nt"&gt;--since&lt;/span&gt; &lt;span class="s2"&gt;"19:46:00"&lt;/span&gt; &lt;span class="nt"&gt;--until&lt;/span&gt; &lt;span class="s2"&gt;"19:50:00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;19:46:53  node 'pve-a': state changed from 'online' =&amp;gt; 'unknown'
19:47:43  service 'vm:100': state changed from 'started' to 'fence'
19:47:43  node 'pve-a': state changed from 'unknown' =&amp;gt; 'fence'
19:48:43  successfully acquired lock 'ha_agent_pve-a_lock'
19:48:43  fencing: acknowledged - got agent lock for node 'pve-a'
19:48:43  service 'vm:100': state changed from 'fence' to 'recovery'
19:48:43  recover service 'vm:100' from fenced node 'pve-a' to node 'pve-b'
19:48:43  service 'vm:100': state changed from 'recovery' to 'started'  (node = pve-b)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt;'yı çökerttiğim an ~19:46:33'tü. Üç net faz ortaya çıktı:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Algılama (~20 saniye):&lt;/strong&gt; çökme → &lt;code&gt;online =&amp;gt; unknown&lt;/code&gt; (19:46:53). Corosync'in kaybı fark edip CRM'e bildirmesi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fence kararı (tam 50 saniye):&lt;/strong&gt; &lt;code&gt;unknown&lt;/code&gt; → &lt;code&gt;fence&lt;/code&gt; (19:47:43). Muhtemelen ani bir yanlış pozitiften kaçınmak için bekletilen bir politika süresi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watchdog güvenlik beklemesi (tam 60 saniye):&lt;/strong&gt; &lt;code&gt;fence&lt;/code&gt; → lock alındı, VM &lt;code&gt;pve-b&lt;/code&gt;'de başladı (19:48:43). Bu rakam tesadüf değil; watchdog'un kendi kendini resetleyeceği tam süreyi (tipik 60 saniye) bekliyor, "belki node hâlâ hayatta ve VM'i çalıştırıyordur" ihtimalini sıfırlıyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Toplam: ~130 saniye&lt;/strong&gt; (&lt;code&gt;virsh destroy&lt;/code&gt;'dan VM'in yeni node'da çalışmasına kadar).&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 4: Double-Start'ın Yapısal Olarak İmkansız Olduğunu Kanıtlamak
&lt;/h2&gt;

&lt;p&gt;En kritik soru: &lt;code&gt;pve-a&lt;/code&gt; geri gelince VM'i ikinci kez başlatmaya çalışacak mı? İki node'un aynı diske aynı anda yazması gerçek bir felaket senaryosu olurdu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh start pve-a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boot tamamlandıktan sonra, &lt;code&gt;pve-a&lt;/code&gt;'da:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm status 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Configuration file 'nodes/pve-a/qemu-server/100.conf' does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu, Modül 1'de gördüğüm birebir aynı hata mesajı, ama tamamen farklı bir anlamda. Modül 1'de bu, "kimse bu VM'i başlatmayacak" demekti. Burada ise: fencing + recovery süreci, VM'in config dosyasını pmxcfs üzerinden &lt;strong&gt;gerçekten &lt;code&gt;pve-b&lt;/code&gt;'nin dizinine taşımış&lt;/strong&gt;. &lt;code&gt;pve-a&lt;/code&gt;'da böyle bir dosya artık hiç yok. Bu, double-start'ı sadece "önlenmiş" değil, yapısal olarak &lt;strong&gt;imkansız&lt;/strong&gt; kılıyor: &lt;code&gt;pve-a&lt;/code&gt; geri gelse bile, elinde VM'i başlatacak bir config bile bulamıyor.&lt;/p&gt;

&lt;p&gt;Bunu iki node'dan bağımsız olarak doğruladım. &lt;code&gt;pve-b&lt;/code&gt;'de:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            3
Quorate:          Yes
Total votes:      5
Quorum:           3
Flags:            Quorate Qdevice
...
quorum OK
master pve-c (active, ...)
fencing armed (CRM watchdog active)
lrm pve-a (idle, watchdog standby, ...)
lrm pve-b (active, watchdog active, ...)
lrm pve-c (idle, watchdog standby, ...)
service vm:100 (pve-b, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt;'da, aynı anda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            3
Quorate:          Yes
Total votes:      5
Quorum:           3
Flags:            Quorate Qdevice
...
quorum OK
master pve-c (active, ...)
fencing armed (CRM watchdog active)
lrm pve-a (idle, watchdog standby, ...)
lrm pve-b (active, watchdog active, ...)
lrm pve-c (idle, watchdog standby, ...)
service vm:100 (pve-b, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Birebir tutarlı: 5 oy, 3 node, &lt;code&gt;vm:100 (pve-b, started)&lt;/code&gt;, fencing armed. &lt;code&gt;lrm pve-a&lt;/code&gt;, hiçbir manuel müdahale gerekmeden, kendiliğinden "old timestamp - dead?" durumundan "idle"a döndü.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 5: Node Affinity, Beklediğimden Daha Proaktif
&lt;/h2&gt;

&lt;p&gt;Her şey sağlıklıyken, VM'in tercihen &lt;code&gt;pve-a&lt;/code&gt;'da kalmasını söyleyen bir kural tanımladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager rules add node-affinity prefer-pve-a &lt;span class="nt"&gt;--resources&lt;/span&gt; vm:100 &lt;span class="nt"&gt;--nodes&lt;/span&gt; pve-a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aynı işlem web arayüzünden: &lt;code&gt;Datacenter → HA → Rules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fulv3bjhimy5k6u23opl9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fulv3bjhimy5k6u23opl9.png" alt="Datacenter → HA → Rules ekranı" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Add" → "Node Affinity Rule" diyip kaynağı ve tercih edilen node'u seçiyorsun:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjabul0g2kl0o7wup8ht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhjabul0g2kl0o7wup8ht.png" alt="Add Node Affinity Rule diyaloğu - vm:100, pve-a" width="598" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Beklentim şuydu: bu kural sadece bir sonraki arıza/recovery anında devreye girer, halihazırda sağlıklı çalışan bir servisi kendiliğinden taşımaz. Yanılmışım.&lt;/p&gt;

&lt;p&gt;Kuralı ekledikten saniyeler sonra, tekrar baktığımda:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service vm:100 (pve-b, migrate)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0xpf0zurvfdo19crnj7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0xpf0zurvfdo19crnj7j.png" alt="HA Status - vm:100 migrate durumunda" width="796" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VM zaten taşınmaya başlamıştı; hem de &lt;code&gt;fence&lt;/code&gt; ya da &lt;code&gt;relocate&lt;/code&gt; değil, &lt;strong&gt;&lt;code&gt;migrate&lt;/code&gt;&lt;/strong&gt; durumunda; yani VM durdurulup yeniden başlatılmadı, gerçek bir canlı migration tetiklendi. ~25-30 saniye sonra, tekrar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ha-manager status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service vm:100 (pve-a, started)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fagkajtw8ogryf1cp2qm6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fagkajtw8ogryf1cp2qm6.png" alt="HA Status - vm:100 pve-a'da started" width="796" height="52"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tamamlanmıştı. Hiçbir arıza olmadan, ben sadece bir tercih tanımladığım için, HA Manager kendiliğinden mevcut durumu istenen duruma yakınsatmış. Bu, HA Manager'ın sadece &lt;strong&gt;reaktif&lt;/strong&gt; (arızaya tepki veren) değil, aynı zamanda &lt;strong&gt;proaktif&lt;/strong&gt; (deklare edilen tercihe kendiliğinden yaklaşan) bir sistem olduğunu gösterdi; bunu önceden bilmiyordum, test etmeden öğrenemezdim.&lt;/p&gt;

&lt;p&gt;Son doğrulama:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm status 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;running&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
ha-manager status
ha-manager rules list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            3
Quorate:          Yes
Total votes:      5
Quorum:           3
...
service vm:100 (pve-a, started)
...
┌──────────────┐
│ rule         │
╞══════════════╡
│ prefer-pve-a │
└──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tamamen tutarlı: VM çalışıyor, cluster quorate, kural hâlâ kayıtlı.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Bu modülde üç şey beni özellikle şaşırttı.&lt;/p&gt;

&lt;p&gt;Birincisi, fencing'in üç net fazlı, toplamda ~130 saniyelik bir süreç olması. "HA var, arıza olunca hemen düzelir" gibi belirsiz bir beklentim vardı; gerçekte sistem, her biri ayrı bir amaca hizmet eden (algılama, yanlış pozitiften kaçınma, watchdog güvenlik payı) üç ayrı bekleme süresinden geçiyor. Bu, hız değil, güvenlik önceliğiyle tasarlanmış bir sistem.&lt;/p&gt;

&lt;p&gt;İkincisi, &lt;code&gt;pve-a&lt;/code&gt;'nın config dosyasının gerçekten &lt;code&gt;pve-b&lt;/code&gt;'ye taşınmış olması. Double-start korumasını "kilitli bir mekanizma" gibi hayal etmiştim; gerçekte çok daha basit ve zarif: VM'i başlatacak bilgi artık orada yok, o yüzden başlatılamıyor.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, node affinity kuralının proaktif davranışı. Bu, testin planımı tersine çevirdiği bir andı; "muhtemelen böyle çalışır" diye düşünüp geçebilirdim, ama gerçekten test edince tam tersini gördüm. Modül 2'de de benzer bir şey olmuştu (split-brain'i tetiklemeye çalışıp başaramamak); bu serinin tekrar eden bir teması gibi görünüyor: varsayımlarım, gerçek testlerden daha az güvenilir çıkıyor.&lt;/p&gt;

&lt;p&gt;Bir sonraki modülde, HA Manager'ı biraz daha zorlayacağım: birden fazla VM ile resource affinity kurallarını (aynı node'da tutma/ayrı tutma), ve CRS'in (Cluster Resource Scheduler) yük dengeleme davranışını test edeceğim.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri, resmi Proxmox VE dokümantasyonundan (pve.proxmox.com) 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.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Quorum Kaybını Tetiklemek, QDevice Kurmak ve Shared Storage'a Geçmek (Modül 2)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Fri, 14 Aug 2026 07:03:26 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/quorum-kaybini-tetiklemek-qdevice-kurmak-ve-shared-storagea-gecmek-modul-2-pma</link>
      <guid>https://dev.to/hakanbaban53/quorum-kaybini-tetiklemek-qdevice-kurmak-ve-shared-storagea-gecmek-modul-2-pma</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seri:&lt;/strong&gt; Proxmox VE Cluster ve Corosync&lt;/p&gt;




&lt;p&gt;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 (&lt;code&gt;pvecm expected&lt;/code&gt;) 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 &lt;code&gt;--with-local-disks&lt;/code&gt; olmadan nasıl çalıştığını gösterdim.&lt;/p&gt;

&lt;p&gt;Bu modülde bir hipotezimin yanlış çıktığını da saklamayacağım; yanlış çıkması, doğru sonuçtan daha fazla şey öğretti.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quorum Nedir, Neden Var?
&lt;/h2&gt;

&lt;p&gt;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: &lt;code&gt;quorum = floor(toplam_oy / 2) + 1&lt;/code&gt;. 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 1: Quorum Kaybını Gerçekten Tetiklemek
&lt;/h2&gt;

&lt;p&gt;Bunu Modül 1'deki node çökertme testinden farklı yapmak istedim: orada tüm node'u (&lt;code&gt;virsh destroy&lt;/code&gt;) öldürmüştüm, burada sadece Corosync ağını kesip node'u canlı tutuyorum; management ağı hâlâ açık, SSH ile erişebiliyorum.&lt;/p&gt;

&lt;p&gt;Fiziksel host'tan &lt;code&gt;pve-c&lt;/code&gt;'nin corosync-net arayüzünü düşürdüm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh domif-setlink pve-c vnet15 down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt;'de:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            1
Quorate:          No
Total votes:      1
Quorum:           3 Activity blocked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beklendiği gibi: tek başına kalan &lt;code&gt;pve-c&lt;/code&gt;, quorum eşiğini (3, bu noktada QDevice henüz yoktu) karşılayamıyor.&lt;/p&gt;

&lt;p&gt;pmxcfs'e yazmayı denedim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; /etc/pve/test-readonly.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;touch: cannot touch '/etc/pve/test-readonly.txt': Permission denied
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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ı (&lt;code&gt;Permission denied&lt;/code&gt; vs &lt;code&gt;Read-only file system&lt;/code&gt;) ama sonuç aynı: quorum'suz bir node, konfigürasyona yazamıyor.&lt;/p&gt;

&lt;p&gt;Çoğunluk tarafında (&lt;code&gt;pve-a&lt;/code&gt;, iki node) durum farklıydı: &lt;code&gt;Quorate: Yes&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;Ağı geri açtım (&lt;code&gt;up&lt;/code&gt;), birkaç saniye içinde cluster kendiliğinden 3/3 quorate'e döndü.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 2: QDevice'i Devreye Almak
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;qdevice-1&lt;/code&gt; VM'ine Modül 0'da zaten &lt;code&gt;corosync-qnetd&lt;/code&gt; paketini kurmuştum, ama hiç yapılandırmamıştım. Şimdi gerçekten devreye alma zamanı.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beklenmedik Uyarı: Odd Node Count
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm qdevice setup 192.168.122.20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Clusters with an odd node count are not officially supported!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu beni şaşırttı. Araştırınca öğrendim: &lt;code&gt;pvecm&lt;/code&gt;, 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 &lt;code&gt;ffsplit&lt;/code&gt; (her node'a eşit davranıp QDevice'e her zaman tam 1 oy veren), tek node sayısı için ise &lt;code&gt;--force&lt;/code&gt; ile devreye giren &lt;code&gt;lms&lt;/code&gt; (Last Man Standing). 3 node'lu cluster'ım tek sayı olduğu için bu uyarıyı tetikledi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm qdevice setup 192.168.122.20 &lt;span class="nt"&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu sefer kurulum tamamlandı: sertifikalar üç node'a da dağıtıldı, &lt;code&gt;corosync-qdevice.service&lt;/code&gt; her node'da otomatik enable + start edildi.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;lms&lt;/code&gt; Algoritmasının Etkisini Doğrulamak
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Burada dikkatimi çeken şey: Qdevice satırında &lt;strong&gt;2 oy&lt;/strong&gt; var, 1 değil. &lt;code&gt;ffsplit&lt;/code&gt;'te QDevice her zaman 1 oy verirken, &lt;code&gt;lms&lt;/code&gt;'de &lt;strong&gt;N-1 oy&lt;/strong&gt; veriyor (N = node sayısı). Bizim durumumuzda 3-1=2. &lt;code&gt;corosync.conf&lt;/code&gt;'a bakınca bunu doğruladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="nl"&gt;quorum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;net&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;net&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;lms&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;192.168.122.20&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;tls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Toplam matematik: 3 node × 1 + QDevice × 2 = &lt;strong&gt;5 oy&lt;/strong&gt;, quorum eşiği &lt;strong&gt;3&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 3: QDevice'in Değerini Kanıtlamak
&lt;/h2&gt;

&lt;p&gt;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 &lt;strong&gt;aynı anda&lt;/strong&gt; çökerttim.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh destroy pve-b
&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh destroy pve-c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tek kalan &lt;code&gt;pve-a&lt;/code&gt;'da:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            1
Total votes:      3
Quorum:           3
Quorate:          Yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Matematik: &lt;code&gt;pve-a&lt;/code&gt; (1 oy) + QDevice (2 oy) = 3, eşik de 3. &lt;strong&gt;Quorate: Yes.&lt;/strong&gt; QDevice olmadan bu imkansız olurdu; tek bir node kendi başına asla çoğunluk oluşturamaz.&lt;/p&gt;

&lt;p&gt;Kanıtı tamamlamak için:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;touch&lt;/span&gt; /etc/pve/qdevice-test.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Başarılı oldu; dosya &lt;code&gt;/etc/pve&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;İki node'u da geri getirdim, birkaç dakika içinde cluster tam olarak (5 oy, 3 node) toparlandı.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 4: Split-Brain'i Tetiklemeye Çalışmak
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pvecm expected&lt;/code&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  İlk Deneme: Yanlış Anlaşılan Bir Hata
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt;'yi izole ettim, ama &lt;code&gt;down&lt;/code&gt; komutundan hemen sonra yanlışlıkla &lt;code&gt;up&lt;/code&gt;'ı da çalıştırdım; izolasyon çok kısa sürdü. &lt;code&gt;pve-c&lt;/code&gt;'de:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm expected 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hiçbir hata almadım, ama sonraki denemede (hem &lt;code&gt;pve-c&lt;/code&gt;'de hem &lt;code&gt;pve-a&lt;/code&gt;'da):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unable to set expected votes: CS_ERR_INVALID_PARAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İlk başta bunun QDevice'e özgü bir kısıtlama olduğunu düşündüm. Yanılmışım. Gerçek sebep daha basit: &lt;code&gt;votequorum_setexpected&lt;/code&gt; API'si, &lt;strong&gt;sadece zaten quorum'suz olan bir partition'ı kurtarmak için&lt;/strong&gt; ç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ı.&lt;/p&gt;

&lt;h3&gt;
  
  
  İkinci Deneme: Doğru İzolasyon
&lt;/h3&gt;

&lt;p&gt;Bu sefer &lt;code&gt;pve-c&lt;/code&gt;'yi gerçekten izole tuttum, geri açmadım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh domif-setlink pve-c vnet15 down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt;'de doğruladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            1
Quorate:          No
Total votes:      1
Quorum:           3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gerçekten quorum'suz. Şimdi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm expected 1
pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beklenmedik bir şey oldu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected votes:   3
Quorum:           2
Quorate:          No
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1 istedim, sistem 3 verdi.&lt;/strong&gt; Ve &lt;code&gt;pve-c&lt;/code&gt; (1 oy) bu yeni eşiği (2) bile karşılayamadığı için &lt;code&gt;Quorate: No&lt;/code&gt; kaldı, &lt;code&gt;touch&lt;/code&gt; yine &lt;code&gt;Permission denied&lt;/code&gt; verdi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bu Neden Oldu?
&lt;/h3&gt;

&lt;p&gt;Bunu araştırdım. Proxmox'un kurucu geliştiricilerinden Thomas Lamprecht, 2018 tarihli bir mailing list yazışmasında Corosync'in &lt;code&gt;expected_votes&lt;/code&gt; davranışını şöyle açıklıyor:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Highest expected can not be smaller then the actual online quorate nodes."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yani Corosync, &lt;code&gt;expected_votes&lt;/code&gt; değerini &lt;strong&gt;online ve quorate node sayısının altında tutmuyor&lt;/strong&gt;. Thomas'ın verdiği örneğe göre, manuel olarak &lt;code&gt;expected_votes: 16&lt;/code&gt; ayarlanmışsa ve 28 node online/quorate durumdaysa, Corosync 16 yerine 28'i kullanıyor. Bunu kabaca şu şekilde ifade ediyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;expected = max(user_set_expected, #nodes_quorate_online)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;last_man_standing&lt;/code&gt; etkinleştirildiğinde, yeterli node kaldığı sürece belirli bir süre sonunda &lt;code&gt;highest expected&lt;/code&gt; değerinin aşağı doğru yeniden hesaplanabileceğini belirtiyor. &lt;a href="https://lists.proxmox.com/pipermail/pve-user/2018-October/013641.html?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Proxmox Lists&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bunun QDevice'in &lt;code&gt;lms&lt;/code&gt; algoritmasından kaynaklandığını düşünüyorum; muhtemelen QDevice'in oy hesaplaması sağlıklı kalabilsin diye &lt;code&gt;expected_votes&lt;/code&gt;'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.&lt;/p&gt;

&lt;p&gt;Sonuç ne olursa olsun, pratik etkisi net: &lt;strong&gt;split-brain'i kasıtlı olarak tetiklemeye çalıştım, QDevice'li ortamda başaramadım.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Toparlamak
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm expected 5
&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh domif-setlink pve-c vnet15 up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Birkaç saniye sonra cluster tam olarak (5 oy, 3 node, Quorate: Yes) geri döndü.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 5: Shared Storage ile Migration'ı Yeniden Denemek
&lt;/h2&gt;

&lt;p&gt;Modül 1'de canlı migration'ı test ederken &lt;code&gt;--with-local-disks&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;Baştan söylemek isterim: bu, gerçek bir shared storage değil, homelab için taklit edilmiş bir tanesi. Kullandığım &lt;code&gt;no_root_squash&lt;/code&gt; ve &lt;code&gt;insecure&lt;/code&gt; 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.&lt;/p&gt;

&lt;h3&gt;
  
  
  NFS Sunucusunu Host'ta Kurmak
&lt;/h3&gt;

&lt;p&gt;CachyOS (Arch tabanlı) olduğu için paket ismi Debian'dan farklı; tek paket hem sunucu hem client araçlarını içeriyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;pacman &lt;span class="nt"&gt;-S&lt;/span&gt; nfs-utils
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /srv/nfs/proxmox-shared
&lt;span class="nb"&gt;sudo chown &lt;/span&gt;nobody:nobody /srv/nfs/proxmox-shared
&lt;span class="nb"&gt;sudo chmod &lt;/span&gt;777 /srv/nfs/proxmox-shared
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/etc/exports&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;/&lt;span class="n"&gt;srv&lt;/span&gt;/&lt;span class="n"&gt;nfs&lt;/span&gt;/&lt;span class="n"&gt;proxmox&lt;/span&gt;-&lt;span class="n"&gt;shared&lt;/span&gt; &lt;span class="m"&gt;192&lt;/span&gt;.&lt;span class="m"&gt;168&lt;/span&gt;.&lt;span class="m"&gt;122&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;/&lt;span class="m"&gt;24&lt;/span&gt;(&lt;span class="n"&gt;rw&lt;/span&gt;,&lt;span class="n"&gt;sync&lt;/span&gt;,&lt;span class="n"&gt;no_subtree_check&lt;/span&gt;,&lt;span class="n"&gt;no_root_squash&lt;/span&gt;,&lt;span class="n"&gt;insecure&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; rpcbind nfs-server
&lt;span class="nb"&gt;sudo &lt;/span&gt;exportfs &lt;span class="nt"&gt;-arv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Beklenmedik Engel: Firewall
&lt;/h3&gt;

&lt;p&gt;İlk mount denemesi &lt;code&gt;pve-a&lt;/code&gt;'dan başarısız oldu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;mount.nfs: Connection refused for 192.168.122.1:/srv/nfs/proxmox-shared on /mnt/test-nfs
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Servisler çalışıyordu, export tanımlıydı, portlar (&lt;code&gt;2049&lt;/code&gt;, &lt;code&gt;111&lt;/code&gt;) dinliyordu; sorun &lt;code&gt;firewalld&lt;/code&gt;'ın aktif olmasıydı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--get-active-zones&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;libvirt
  interfaces: virbr-coro virbr0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;virbr0&lt;/code&gt; (management) ve &lt;code&gt;virbr-coro&lt;/code&gt; (corosync-net) ikisi de &lt;code&gt;libvirt&lt;/code&gt; zone'undaydı, ama bu zone'a NFS servisleri hiç eklenmemişti:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;libvirt &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nfs
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;libvirt &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rpc-bind
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--permanent&lt;/span&gt; &lt;span class="nt"&gt;--zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;libvirt &lt;span class="nt"&gt;--add-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mountd
&lt;span class="nb"&gt;sudo &lt;/span&gt;firewall-cmd &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu düzeltmeden sonra manuel mount çalıştı, &lt;code&gt;touch&lt;/code&gt; ve &lt;code&gt;ls&lt;/code&gt; başarılı oldu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8bfgm5kntz3xmi0k7e8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8bfgm5kntz3xmi0k7e8z.png" alt="nfs-shared Depolamasının Web UI da Görünümü" width="301" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Proxmox'a Eklemek ve Disk Taşımak
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvesm add nfs nfs-shared &lt;span class="nt"&gt;--server&lt;/span&gt; 192.168.122.1 &lt;span class="nt"&gt;--export&lt;/span&gt; /srv/nfs/proxmox-shared &lt;span class="nt"&gt;--content&lt;/span&gt; images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name              Type     Status     Total (KiB)      Used (KiB) Available (KiB)        %
nfs-shared         nfs     active       486256640        72509440       412091392   14.91%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VM 100'ün diskini taşıdım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm move-disk 100 scsi0 nfs-shared
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr15peaiom5fqhuam3yk4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr15peaiom5fqhuam3yk4.png" alt="nfs-shared Depolamasına Taşıdığımız Diskin Görünümü" width="800" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Beklenmedik Bir Detay: Hayalet Disk Referansı
&lt;/h3&gt;

&lt;p&gt;İlk migration denemesinde (&lt;code&gt;pve-b&lt;/code&gt;'den &lt;code&gt;pve-c&lt;/code&gt;'ye) log'da hâlâ "copying local disk images" adımı çıktı, 8GB'lık bir kopyalama yaptı; disk zaten NFS'te olması gerekirken. &lt;code&gt;qm config 100&lt;/code&gt;'e baktığımda sebebi gördüm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scsi0: nfs-shared:100/vm-100-disk-0.raw,...
unused0: local-lvm:vm-100-disk-0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;move-disk&lt;/code&gt; diski gerçekten NFS'e taşımıştı, ama eski local-lvm referansını &lt;code&gt;unused0&lt;/code&gt; 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ı. &lt;code&gt;lvremove&lt;/code&gt; ile temizlemeye çalışınca üç node'da da "Failed to find logical volume" hatası aldım; migration'ın kendisi log'un sonunda zaten &lt;code&gt;Logical volume "vm-100-disk-0" successfully removed&lt;/code&gt; demişti, yani gerçek disk çoktan silinmişti, sadece config'te unutulmuş bir referans kalmıştı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm &lt;span class="nb"&gt;unlink &lt;/span&gt;100 &lt;span class="nt"&gt;--idlist&lt;/span&gt; unused0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Temiz Migration: Öncesi/Sonrası
&lt;/h3&gt;

&lt;p&gt;Hayalet referans temizlendikten sonra tekrar denedim (&lt;code&gt;pve-c&lt;/code&gt;'den &lt;code&gt;pve-a&lt;/code&gt;'ya):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Copying local disk images" adımı &lt;strong&gt;tamamen yok&lt;/strong&gt;; disk hiç dokunulmadı, sadece VM'in bellek durumu (158.5 MiB) taşındı.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Modül 1 (local disk, &lt;code&gt;--with-local-disks&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Bu test (NFS shared storage)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Disk kopyalama&lt;/td&gt;
&lt;td&gt;Var, ~8 GB, ~13 saniye&lt;/td&gt;
&lt;td&gt;Yok&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toplam süre&lt;/td&gt;
&lt;td&gt;~20 saniye&lt;/td&gt;
&lt;td&gt;~5 saniye&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Downtime&lt;/td&gt;
&lt;td&gt;43 ms&lt;/td&gt;
&lt;td&gt;15 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Taşınan veri&lt;/td&gt;
&lt;td&gt;Disk + VM state&lt;/td&gt;
&lt;td&gt;Sadece VM state (158.5 MiB)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Ping testi bu sırada da kesintisizdi; 40'tan fazla paket, hiç kayıp yok, gecikme 0.3-1.3ms aralığında sabit kaldı.&lt;/p&gt;

&lt;p&gt;Bu karşılaştırma, &lt;code&gt;--with-local-disks&lt;/code&gt;'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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;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ç.&lt;/p&gt;

&lt;p&gt;En çok üzerinde durduğum üç nokta:&lt;/p&gt;

&lt;p&gt;Birincisi, &lt;code&gt;ffsplit&lt;/code&gt; ve &lt;code&gt;lms&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;İkincisi, &lt;code&gt;pvecm expected&lt;/code&gt;'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.&lt;/p&gt;

&lt;p&gt;Üçü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.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;--with-local-disks&lt;/code&gt; 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ı.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;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.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title># Proxmox Cluster Kurmak: Kavramlar, GUI/CLI ve Gerçek Hatalar (Modül 1)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Tue, 11 Aug 2026 06:06:19 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/-proxmox-cluster-kurmak-kavramlar-guicli-ve-gercek-hatalar-modul-1-1f6k</link>
      <guid>https://dev.to/hakanbaban53/-proxmox-cluster-kurmak-kavramlar-guicli-ve-gercek-hatalar-modul-1-1f6k</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seri:&lt;/strong&gt; Proxmox VE Cluster ve Corosync&lt;/p&gt;




&lt;p&gt;Modül 0'da dört sanal makineyi (&lt;code&gt;pve-a&lt;/code&gt;, &lt;code&gt;pve-b&lt;/code&gt;, &lt;code&gt;pve-c&lt;/code&gt;, &lt;code&gt;qdevice-1&lt;/code&gt;) kurdum, ağlarını yapılandırdım ve birbirlerine ulaşabildiklerini doğruladım. Lab artık hazır. Bu modüld asıl kavramlara ve gerçek cluster kurulumuna geçiyorum: &lt;code&gt;pvecm&lt;/code&gt;, Corosync ve pmxcfs nedir, ne işe yarar, ve cluster'ı hem GUI'den hem CLI'dan kurunca neler yaşadım.&lt;/p&gt;

&lt;p&gt;Bu modülde işleri bilerek iki farklı yoldan yaptım: cluster'ı web arayüzünden oluşturdum, bir node'u terminalden, bir node'u web arayüzünden kattım. Amaç sadece "iki yöntem de mümkün" demek değildi; iki yöntemi karıştırınca ortaya çıkan gerçek bir hatayı da görmek istedim, ve gördüm.&lt;/p&gt;




&lt;h2&gt;
  
  
  Neden Cluster?
&lt;/h2&gt;

&lt;p&gt;Tek bir Proxmox node'u zaten kendi başına çalışan bir hipervizör; web arayüzü var, VM/container yönetimi var. Cluster, birden fazla node'u bir araya getirip merkezi bir yönetim deneyimi sunuyor: tek bir web arayüzünden tüm node'ları yönetmek, VM'leri node'lar arası taşımak, ortak firewall ve HA politikaları tanımlamak.&lt;/p&gt;

&lt;p&gt;Mimari olarak dikkat çeken bir nokta var: Proxmox cluster'ı &lt;strong&gt;multi-master&lt;/strong&gt;. Yani tek bir "merkezi yönetim sunucusu" yok; her node, cluster'ın tamamını yönetebilecek yetkiye sahip. Bu, VMware'in vCenter'ı gibi ayrı bir yönetim katmanına ihtiyaç duymuyor; yönetim mantığı doğrudan node'ların kendisine gömülü.&lt;/p&gt;




&lt;h2&gt;
  
  
  Üç Parça: pvecm, Corosync, pmxcfs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;pvecm&lt;/code&gt;&lt;/strong&gt;, cluster'ı yönetmek için kullandığım komut satırı aracı. Node oluşturma, ekleme, çıkarma, durum sorgulama gibi işlemler buradan geçiyor. Web arayüzünün "Cluster" sekmesi de aslında aynı işlemleri, aynı API üzerinden yapıyor; ikisi farklı arayüz, aynı motor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Corosync Cluster Engine&lt;/strong&gt;, node'lar arası güvenilir grup iletişimini sağlayan alt katman. Hem &lt;code&gt;pvecm&lt;/code&gt; hem web arayüzü bunun üzerine kurulu. Node sayısında sert bir teknik sınır yok; pratikte ağ ve donanım performansı sınırlıyor, üst düzey donanımla 50'den fazla node'lu production cluster'lar bile rapor edilmiş.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pmxcfs (Proxmox Cluster File System)&lt;/strong&gt;, &lt;code&gt;/etc/pve&lt;/code&gt; altında mount edilen, FUSE tabanlı bir dosya sistemi. Cluster'daki tüm konfigürasyon dosyaları burada tutuluyor ve Corosync üzerinden tüm node'lara gerçek zamanlı olarak replike ediliyor. En kritik davranışı şu: node quorum'u kaybettiğinde bu dosya sistemi read-only'e geçiyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 1: pmxcfs'i Kümelenmeden Önce Gözlemlemek
&lt;/h2&gt;

&lt;p&gt;Cluster'ı kurmadan önce, &lt;code&gt;pve-a&lt;/code&gt; üzerinde henüz tek başınayken pmxcfs'e baktım.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status pve-cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Servis &lt;code&gt;active (running)&lt;/code&gt;, &lt;code&gt;pmxcfs&lt;/code&gt; process'i çalışıyor. Log satırlarında ilginç bir detay vardı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pmxcfs[806]: [main] notice: resolved node name 'pve-a' to '192.168.122.11' for default node IP address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9eyzb5icckbyx015t38t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9eyzb5icckbyx015t38t.png" alt="pmxcfs log satırı - node adının management IP'sine çözümlenmesi" width="786" height="18"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;pmxcfs, node adını çözümlerken &lt;strong&gt;management ağının IP'sini&lt;/strong&gt; (&lt;code&gt;192.168.122.11&lt;/code&gt;) varsayılan olarak almış. Bu gözlem, ileride başıma geleceklerin habercisi oldu; birazdan neden önemli olduğunu göreceğiz.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /etc/pve/nodes/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/etc/pve/nodes/&lt;/code&gt; dizininde sadece &lt;code&gt;pve-a&lt;/code&gt;'yı gördüm; bu, "öncesi" fotoğrafıydı.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0ig0mow8gxf0n4wm6nn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff0ig0mow8gxf0n4wm6nn.png" alt="/etc/pve/nodes/ dizini - cluster öncesi, sadece pve-a" width="636" height="63"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Uygulama 2: Cluster'ı Kurmak
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cluster'ı GUI'den Oluşturmak
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdizd2e4aqvhxfjl2ldi6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdizd2e4aqvhxfjl2ldi6.png" alt="Create Cluster ekranı - cluster ismi ve Link seçimi" width="607" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0s2z6d8cxw19mkllay4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0s2z6d8cxw19mkllay4m.png" alt="Create Cluster - Link 1 için corosync-net arayüzü (10.10.10.11) seçili" width="602" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt;'nın web arayüzünden &lt;code&gt;Datacenter → Cluster → Create Cluster&lt;/code&gt; dedim, isim olarak &lt;code&gt;lab-cluster&lt;/code&gt; verdim, Link 1 için &lt;code&gt;corosync-net&lt;/code&gt; arayüzünü (&lt;code&gt;10.10.10.11&lt;/code&gt;) seçtim. İşlem birkaç saniyede tamamlandı.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fno2gooane4zf0x548hhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fno2gooane4zf0x548hhm.png" alt="Datacenter → Cluster - lab-cluster oluşturuldu, tek node (pve-a)" width="799" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Hata: TLS Sertifika Doğrulaması
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-b&lt;/code&gt;'yi katılırken ilk aklıma gelen, doğrudan &lt;code&gt;corosync-net&lt;/code&gt; IP'sini (&lt;code&gt;10.10.10.11&lt;/code&gt;) hedef göstermekti. Mantığım şuydu: bu ağı zaten Corosync trafiği için ayırmıştım, cluster'a katılma işlemi de bir "cluster" işlemiydi, o yüzden bu IP'yi kullanmak bana doğru geldi.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm add 10.10.10.11 &lt;span class="nt"&gt;--link1&lt;/span&gt; 10.10.10.12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Establishing API connection with host '10.10.10.11'
The authenticity of host '10.10.10.11' can't be established.
X509 SHA256 key fingerprint is FF:59:FA:...
Are you sure you want to continue connecting (yes/no)? yes
500 Can't connect to 10.10.10.11:8006 (hostname verification failed)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Meğerse yanılmışım. &lt;code&gt;pvecm add&lt;/code&gt;'in ilk parametresi, Corosync trafiği değil; &lt;code&gt;pve-a&lt;/code&gt;'nın API'sine (&lt;code&gt;:8006&lt;/code&gt; portu, yani web arayüzünün kendisi) HTTPS üzerinden bağlanıp "beni bu cluster'a ekle" demek. Bu, Uygulama 1'de gördüğüm pmxcfs gözlemiyle doğrudan bağlantılıydı: &lt;code&gt;pve-a&lt;/code&gt;'nın self-signed sertifikası, management IP/hostname için üretilmiş. &lt;code&gt;pve-b&lt;/code&gt;, &lt;code&gt;10.10.10.11&lt;/code&gt; üzerinden bu API'ye bağlanmaya çalışınca sertifika o adresi tanımıyor, hostname doğrulaması çöküyor.&lt;/p&gt;

&lt;p&gt;Yani karıştırdığım şey şuydu: &lt;code&gt;corosync-net&lt;/code&gt;'in var olma amacı (Corosync'in kendi trafiği) ile join işleminin gerçekte ne olduğu (bir API çağrısı) aynı şey değil. &lt;code&gt;--link1&lt;/code&gt; parametresi zaten Corosync trafiğinin hangi arayüzden gideceğini ayrıca belirtiyor; ilk parametrenin de aynı ağdan olması gerekmiyor, çünkü o bambaşka bir iletişim katmanı.&lt;/p&gt;

&lt;p&gt;Doğrusu, join/API bağlantısı için management IP'yi, Corosync trafiği için &lt;code&gt;--link1&lt;/code&gt;'i ayrı ayrı kullanmaktı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm add 192.168.122.11 &lt;span class="nt"&gt;--link1&lt;/span&gt; 10.10.10.12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Join request OK, finishing setup locally
stopping pve-cluster service
backup old database to '/var/lib/pve-cluster/backup/config-1786335821.sql.gz'
waiting for quorum...OK
(re)generate node files
generate new node certificate
merge authorized SSH keys
generated new node certificate, restart pveproxy and pvedaemon services
successfully added node 'pve-b' to cluster.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Çalıştı. &lt;code&gt;pve-b&lt;/code&gt; cluster'a katıldı.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;pve-c&lt;/code&gt;'yi GUI'den Katılmak
&lt;/h3&gt;

&lt;p&gt;Bu sefer terminale hiç dokunmadan, tamamen web arayüzünden gitmek istedim. &lt;code&gt;pve-a&lt;/code&gt;'nın arayüzünde &lt;code&gt;Datacenter → Cluster → Join Information&lt;/code&gt;, kopyala butonuna bastım; encode edilmiş bir bilgi bloğu (peer address, fingerprint, cluster network bilgisi hepsi içinde) verdi.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8a6kgnfhw3ry2h50b56k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8a6kgnfhw3ry2h50b56k.png" alt="Join Information ekranı - pve-a, encode edilmiş bilgi bloğu" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8frb6eqdtl3khbi940jg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8frb6eqdtl3khbi940jg.png" alt="Join Information - kopyala butonu" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt;'nin kendi arayüzüne geçip &lt;code&gt;Join Cluster&lt;/code&gt; dedim, kopyaladığım bilgiyi yapıştırdım, root parolasını girdim. Ekran otomatik olarak Peer Address, Fingerprint alanlarını doldurdu, ve &lt;strong&gt;Cluster Network&lt;/strong&gt; kısmında "Link: 1" yazıp &lt;code&gt;10.10.10.13&lt;/code&gt;'ü önerdi.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqxpz2qucqfg4xg323ilb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqxpz2qucqfg4xg323ilb.png" alt="Cluster Join ekranı - pve-c, Link 1 otomatik önerisi (10.10.10.13)" width="799" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3n3kp7ttm6hpr6j5apf7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3n3kp7ttm6hpr6j5apf7.png" alt="Cluster Join ekranı - Peer Address ve Fingerprint otomatik dolu" width="799" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Join 'lab-cluster'" dedim.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fazvpu0hw09x2egcc0nzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fazvpu0hw09x2egcc0nzt.png" alt="Task viewer - Join Cluster, " width="799" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not:&lt;/strong&gt; Join Information bloğu cluster ismini, node adreslerini (management ve corosync IP'leri) ve sertifika fingerprint'ini kodluyor; root parolası bunun dışında, ayrıca giriliyor. Yani bu string'i tek başına ele geçirmek cluster'a katılmaya yetmiyor. Yine de gerçek bir ortamda bu blok ağ topolojisini açığa çıkarıyor, bu yüzden production sistemlerde bu tür ekran görüntülerini herkese açık paylaşmadan önce IP'leri kırpmak/bulanıklaştırmak makul bir alışkanlık. Burada gösterdiğim IP'ler (&lt;code&gt;192.168.122.x&lt;/code&gt;, &lt;code&gt;10.10.10.x&lt;/code&gt;) private adresler ve sadece kendi laptopumdaki izole lab ağında anlamlı olduğu için olduğu gibi bıraktım.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Task viewer ekranı "stopping pve-cluster service" satırında donmuş gibi görünüyordu, "Download" butonu bile aktif olmamıştı. İlk anda başarısız olduğunu düşündüm. Ama bu, bilinen bir kozmetik davranış: &lt;code&gt;pve-cluster.service&lt;/code&gt; yeniden başlarken &lt;code&gt;pveproxy&lt;/code&gt;/&lt;code&gt;pvedaemon&lt;/code&gt; de kendini yeniden başlatıyor, bu da tarayıcının o anki task log bağlantısını kesiyor. Arka planda işlem gerçekte tamamlanmış oluyor; sadece tarayıcı bunu görmüyor.&lt;/p&gt;

&lt;p&gt;Bunu terminalden doğruladım.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sonucu Doğrulamak
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt;'da, &lt;code&gt;pve-b&lt;/code&gt; katıldıktan sonra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            2
Quorate:          Yes
Expected votes:   2
Total votes:      2
Quorum:           2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt; katıldıktan sonra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            3
Quorate:          Yes
Expected votes:   3
Total votes:      3
Quorum:           2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pvecm nodes&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Nodeid      Votes Name
         1          1 pve-a (local)
         2          1 pve-b
         3          1 pve-c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Web arayüzünde de &lt;code&gt;Datacenter → Cluster&lt;/code&gt; altında aynı bilgi: üç node, her biri 1 oy, &lt;code&gt;Link 1&lt;/code&gt; sütununda üçünün de doğru corosync-net IP'sini gösterdiğini gördüm. GUI ve CLI, aynı gerçekliği iki farklı pencereden gösteriyordu; bu benim için iyi bir doğrulama oldu, tek bir kaynağa güvenmek yerine ikisini çapraz kontrol etmiş oldum.&lt;/p&gt;

&lt;h3&gt;
  
  
  pmxcfs'in Canlı Senkronizasyonu
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt;'da bir dosya oluşturdum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"cluster calisiyor"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/pve/test-sync.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-b&lt;/code&gt; ve &lt;code&gt;pve-c&lt;/code&gt;'de, saniyeler içinde:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /etc/pve/test-sync.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cluster calisiyor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt;'nin &lt;code&gt;pve-cluster.service&lt;/code&gt; loglarına baktığımda senkronizasyonun nasıl gerçekleştiğini de gördüm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[status] notice: received sync request (epoch 1/1632/00000003)
[dcdb] notice: received all states
[dcdb] notice: leader is 1/1632
[dcdb] notice: synced members: 1/1632, 2/2612
[dcdb] notice: waiting for updates from leader
[status] notice: all data is up to date
[dcdb] notice: update complete - trying to commit (got 47 inode updates)
[dcdb] notice: all data is up to date
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-c&lt;/code&gt;'nin katıldığı anda, &lt;code&gt;pve-a&lt;/code&gt;'nın (leader'ın) tarafında ne olduğunu da görmek istedim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[status] notice: received sync request (epoch 1/1632/00000003)
[dcdb] notice: received all states
[dcdb] notice: leader is 1/1632
[dcdb] notice: synced members: 1/1632, 2/2612
[dcdb] notice: start sending inode updates
[dcdb] notice: sent all (47) updates
[dcdb] notice: all data is up to date
[status] notice: received all states
[status] notice: all data is up to date
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;leader is 1/1632&lt;/code&gt; satırı özellikle dikkatimi çekti: pmxcfs'in kendi içinde bir "leader" kavramı var, senkronizasyon bu leader üzerinden koordine ediliyor. İki log da aynı sayıyı, 47 update'i, konuşuyor; biri "gönderdim" diyor, diğeri "aldım" diyor. Dağıtık bir sistemde iki bağımsız node'un aynı olayı aynı sayılarla anlatması, bana pmxcfs'in gerçekten tutarlı çalıştığına dair küçük ama tatmin edici bir kanıt oldu.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;/etc/pve/nodes/&lt;/code&gt; Dizininin Son Hali
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /etc/pve/nodes/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modül 1'in başında &lt;code&gt;pve-a&lt;/code&gt;'da sadece kendi node'unu görmüştüm. Şimdi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;drwxr-xr-x 2 root www-data 0 Aug  5 17:57 pve-a
drwxr-xr-x 2 root www-data 0 Aug 10 07:23 pve-b
drwxr-xr-x 2 root www-data 0 Aug 10 07:26 pve-c
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu dizin listesi, hem &lt;code&gt;pve-a&lt;/code&gt;'da hem &lt;code&gt;pve-b&lt;/code&gt;'de hem &lt;code&gt;pve-c&lt;/code&gt;'de birebir aynı; üçü de aynı gerçekliği paylaşıyor. Bu, "öncesi/sonrası" karşılaştırmasının en net hali: bir dizin, tek bir node'a özgü değil, artık cluster'ın ortak hafızasının bir parçası.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test: Migration ve Node Arızası Simülasyonu
&lt;/h2&gt;

&lt;p&gt;Buraya kadar cluster'ı kurdum, quorate olduğunu doğruladım, pmxcfs'in senkronize çalıştığını gördüm. Ama bir arkadaşım haklı bir eksiği fark etti: cluster'a özgü hiçbir şey (bir VM'i node'lar arası taşımak) hiç denenmemişti. "Cluster kurdum" demek, "kurdum ve gerçekten işe yarıyor" demenin garantisi değil.&lt;/p&gt;

&lt;h3&gt;
  
  
  Küçük Bir VM ile Migration Testi
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt; üzerinde minimal bir Alpine Linux VM'i (VMID 100) oluşturdum, &lt;code&gt;vmbr0&lt;/code&gt; (management ağı) üzerine bağladım; &lt;code&gt;corosync-net&lt;/code&gt;'e değil, çünkü o ağ sadece Corosync trafiği için izole tutulmuş durumda, guest trafiğini oraya karıştırmak istemedim.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2For0rac4s4u8v6bxlrxve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2For0rac4s4u8v6bxlrxve.png" alt="Alpine Linux Sanal Makine Detayları" width="759" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;İlk migration denemem başarısız oldu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm migrate 100 pve-b &lt;span class="nt"&gt;--online&lt;/span&gt; &lt;span class="nt"&gt;--with-local-disks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;found local disk 'local:iso/alpine-standard-3.24.1-x86_64.iso' (attached)
can't migrate local disk 'local:iso/alpine-standard-3.24.1-x86_64.iso': local cdrom image
ERROR: migration aborted (duration 00:00:01): Problem found while scanning volumes - can't migrate VM - check log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kurulumdan kalan ISO hâlâ sanal CD-ROM olarak bağlıydı; bu, ne shared storage'da ne de replike ediliyor, sadece &lt;code&gt;pve-a&lt;/code&gt;'nın diskinde duruyor, migration bunu taşıyamıyor. CD-ROM'u çıkarıp tekrar denedim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm &lt;span class="nb"&gt;set &lt;/span&gt;100 &lt;span class="nt"&gt;--ide2&lt;/span&gt; none
qm migrate 100 pve-b &lt;span class="nt"&gt;--online&lt;/span&gt; &lt;span class="nt"&gt;--with-local-disks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu sefer çalıştı. &lt;code&gt;pve-b&lt;/code&gt;'de doğruladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm status 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;running&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cluster genelinde de aynı bilgiyi &lt;code&gt;pve-a&lt;/code&gt;'dan görebiliyordum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvesh get /cluster/resources &lt;span class="nt"&gt;--type&lt;/span&gt; vm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;│ id       │ type │ ... │ name   │
│ qemu/100 │ qemu │ ... │ alpine │
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VM &lt;code&gt;pve-b&lt;/code&gt; üzerinde, çalışır durumda görünüyordu.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node'u Çökertmek
&lt;/h3&gt;

&lt;p&gt;Asıl test buradaydı. Önce ping'i başlattım (host laptop'umdan):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ping 192.168.122.251
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;64 bytes from 192.168.122.251: icmp_seq=1 ttl=64 time=0.842 ms
64 bytes from 192.168.122.251: icmp_seq=2 ttl=64 time=0.969 ms
&lt;/span&gt;&lt;span class="c"&gt;...
&lt;/span&gt;&lt;span class="go"&gt;64 bytes from 192.168.122.251: icmp_seq=19 ttl=64 time=1.08 ms
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sonra &lt;code&gt;pve-b&lt;/code&gt;'yi, temiz bir kapanış değil, gerçek bir çökme gibi simüle ettim; fiziksel host'tan (nested VM olduğu için mümkün):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh destroy pve-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Domain 'pve-b' destroyed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt;'dan cluster durumuna baktım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            2
Quorate:          Yes
Expected votes:   3
Total votes:      2
Quorum:           2
Membership information
----------------------
    Nodeid      Votes Name
0x00000001          1 10.10.10.11 (local)
0x00000003          1 10.10.10.13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tam beklendiği gibi: &lt;code&gt;pve-b&lt;/code&gt; (nodeid 2) membership listesinden düştü, ama kalan iki node (&lt;code&gt;pve-a&lt;/code&gt;, &lt;code&gt;pve-c&lt;/code&gt;) hâlâ çoğunluğu oluşturduğu için &lt;code&gt;Quorate: Yes&lt;/code&gt; kaldı.&lt;/p&gt;

&lt;p&gt;Ping çıktısında ilginç bir detay vardı: &lt;code&gt;pve-b&lt;/code&gt; öldükten hemen sonra paketler önce sessizce kayboldu (ne cevap ne hata, muhtemelen ARP kaydı hâlâ geçerliydi), birkaç düzine paket sonra gateway (&lt;code&gt;192.168.122.1&lt;/code&gt;, libvirt'ün NAT'ı) aktif olarak "Destination Host Unreachable" demeye başladı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;64 bytes from 192.168.122.251: icmp_seq=19 ttl=64 time=1.08 ms
From 192.168.122.1 icmp_seq=52 Destination Host Unreachable
From 192.168.122.1 icmp_seq=53 Destination Host Unreachable
ping: sendmsg: No route to host
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yani arıza algılama anlık değil, kademeli: önce sessizlik, sonra açık ret.&lt;/p&gt;

&lt;h3&gt;
  
  
  VM'i Başka Bir Yerde Başlatmayı Denemek
&lt;/h3&gt;

&lt;p&gt;Şimdi asıl soru: VM 100, &lt;code&gt;pve-b&lt;/code&gt; çökmüşken başka bir node'da kendiliğinden açılır mı?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;qm start 100
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Configuration file 'nodes/pve-a/qemu-server/100.conf' does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hayır, açılmadı; ama hatanın kendisi beklediğimden daha ince bir şey söylüyor. Hata "pve-b'ye ulaşamıyorum" demiyor; "&lt;code&gt;pve-a&lt;/code&gt;'nın kendi node dizininde böyle bir config dosyası yok" diyor. Sebep şu: pmxcfs, &lt;code&gt;nodes/pve-b/qemu-server/100.conf&lt;/code&gt; dosyasını cluster genelinde senkronize ediyor, &lt;code&gt;pve-a&lt;/code&gt; bile bu dosyayı görebiliyor (&lt;code&gt;pvesh get /cluster/resources&lt;/code&gt; bunu az önce gösterdi). Ama &lt;code&gt;qm start&lt;/code&gt;, sadece komutu çalıştırdığın node'un &lt;strong&gt;kendi&lt;/strong&gt; dizinindeki config'lere bakıyor. VM 100'ün config'i &lt;code&gt;pve-b&lt;/code&gt;'nin dizininde olduğu için, &lt;code&gt;pve-a&lt;/code&gt; üzerinde &lt;code&gt;qm start 100&lt;/code&gt; demek, "burada böyle bir VM yok" demekle aynı şey.&lt;/p&gt;

&lt;p&gt;Bu ayrım önemli: pmxcfs veriyi her yere kopyalıyor, ama "bu VM'i sahiplenip başka bir node'da başlat" kararını kimse otomatik almıyor. Veri paylaşılıyor, karar paylaşılmıyor. Bunu yapacak mekanizma (HA Manager, fencing, watchdog) henüz devrede değil.&lt;/p&gt;

&lt;h3&gt;
  
  
  Toparlamak ve Doğrulamak
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pve-b&lt;/code&gt;'yi geri başlattım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;virsh start pve-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Birkaç dakika sonra &lt;code&gt;pve-a&lt;/code&gt;'dan tekrar baktım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pvecm status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Nodes:            3
Quorate:          Yes
Expected votes:   3
Total votes:      3
Quorum:           2
Membership information
----------------------
    Nodeid      Votes Name
0x00000001          1 10.10.10.11 (local)
0x00000002          1 10.10.10.12
0x00000003          1 10.10.10.13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Üç node da geri döndü, cluster kendiliğinden toparlandı; hiçbir manuel müdahale gerekmedi. &lt;code&gt;pve-b&lt;/code&gt; geri geldikten sonra &lt;code&gt;qm start 100&lt;/code&gt;'ü &lt;code&gt;pve-a&lt;/code&gt;'dan tekrar denedim, aynı hatayı aldım; bu da tutarlıydı, çünkü hatanın sebebi "node kapalı" değil "config burada değil" olduğu için, &lt;code&gt;pve-b&lt;/code&gt; geri gelmesi bu durumu değiştirmiyor. VM'i başlatmanın doğru yolu, &lt;code&gt;pve-b&lt;/code&gt;'ye SSH ile bağlanıp oradan &lt;code&gt;qm start 100&lt;/code&gt; demekti; ki VM zaten orada duruyordu, hiç kapanmamıştı bile (sadece host çöktüğü için o da düşmüştü).&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Bu modülde, işleri hem GUI'den hem CLI'dan yapmaya çalışınca gerçek bir hatayla karşılaştım: TLS hostname doğrulaması. Bu, Modül 1'in başında yaptığım pmxcfs gözlemiyle (node adının management IP'sine çözümlenmesi) doğrudan bağlantılıydı; o gözlemi yapmamış olsaydım, hatanın kaynağını bulmak daha uzun sürerdi. Bir kavramı önceden anlamış olmak, karşılaştığın hatayı çok daha hızlı okumanı sağlıyor.&lt;/p&gt;

&lt;p&gt;Task viewer'ın donması ise ayrı bir ders: arayüzün "bir şey oluyormuş gibi görünmemesi", arka planda bir şey olmadığı anlamına gelmiyor. Terminal üzerinden çapraz doğrulama yapmak, GUI'ye kör güvenmemek için iyi bir alışkanlık.&lt;/p&gt;

&lt;p&gt;En değerlisi ise sona sakladığım migration testiydi. Cluster'ı kurmuş olmak, ona güvenmek için yeterli değil; gerçekten bir workload'u taşımadan, bir node'u çökertmeden, "çalışıyor" demek bir iddiadan ibaret kalıyor. Test, iki şeyi net gösterdi: birincisi, live migration gerçekten çalışıyor, VM kesintisiz taşınabiliyor. İkincisi, ve daha önemlisi, cluster kurmak otomatik yüksek erişilebilirlik anlamına gelmiyor. Bir node çöktüğünde, üzerindeki VM kendiliğinden başka bir yerde açılmıyor; pmxcfs veriyi her yere kopyalasa da, "bu VM'i devral" kararını hiçbir mekanizma otomatik almıyor. Bunu yapacak parça (HA Manager, fencing, watchdog) ayrı bir modülün konusu.&lt;/p&gt;

&lt;p&gt;Sonuç olarak: cluster çalışıyor, üç node quorate, pmxcfs gerçek zamanlı senkronize oluyor, migration gerçekten işe yarıyor, ve otomatik failover'ın olmadığını da artık varsayım değil, test ederek biliyorum. VMware serisinde her adımı önceden hazırlanmış bir manuel yönlendiriyordu; burada hem TLS hatasının kaynağını hem de HA'nın sınırlarını kendim bulmam gerekti. Daha yorucu, ama muhtemelen daha kalıcı bir öğrenme biçimi.&lt;/p&gt;

&lt;p&gt;Bir sonraki yazıda Modül 2'ye geçiyorum: quorum'u gerçekten kırıp gözlemleyeceğim, &lt;code&gt;pvecm expected&lt;/code&gt;'in riskini test edeceğim, ve QDevice'i devreye alacağım.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri, resmi Proxmox VE dokümantasyonundan (pve.proxmox.com) derlenen bir müfredatı takip ediyor. 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.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Kendi Laboratuvarını Kurmak: Lab Ortamı Hazırlığı (Modül 0)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Fri, 07 Aug 2026 06:01:43 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/kendi-laboratuvarini-kurmak-lab-ortami-hazirligi-modul-0-1idj</link>
      <guid>https://dev.to/hakanbaban53/kendi-laboratuvarini-kurmak-lab-ortami-hazirligi-modul-0-1idj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seri:&lt;/strong&gt; Proxmox VE Cluster ve Corosync | Hazırlık&lt;/p&gt;




&lt;p&gt;vSAN serisinde VMware'in hazırladığı bir HOL ortamı üzerinden ilerlemiştim; ekran adımları, önceden kurulmuş cluster'lar, tek yapmam gereken doğru yere tıklamaktı. Bu seri farklı bir yerden başlıyor: Proxmox VE için böyle hazır bir lab yok. Yani cluster'ı, ağı, hatta sanal makineleri bile sıfırdan ben kuruyorum.&lt;/p&gt;

&lt;p&gt;Bunun bir bedeli var: her adım biraz daha uzun sürüyor, hata yapma ihtimalim daha yüksek. Ama bir avantajı da var: bir HOL asla veremeyeceği kadar derin bir öğrenme sağlıyor, çünkü her kararı (kaç node, hangi ağ mimarisi, ne kadar kaynak) kendim veriyorum ve neden öyle verdiğimi de anlamak zorundayım.&lt;/p&gt;

&lt;p&gt;Bu ilk yazı bir "modül" değil, bir hazırlık; asıl Modül 1 (Cluster, Corosync, pmxcfs kavramları) bir sonraki yazıda geliyor. Ama o kavramları anlamlandırmadan önce, üzerinde çalışacağım zemini kurmam gerekiyordu; bu yazı o zemini nasıl hazırladığımı anlatıyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ortam Hakkında Bir Not
&lt;/h2&gt;

&lt;p&gt;Bu lab kendi dizüstü bilgisayarımda çalışıyor: CachyOS (Arch tabanlı), 11. nesil Intel Core i7-11800H (8 çekirdek/16 iş parçacığı), 32 GB RAM, NVMe depolama. Production bir ortam değil; nested virtualization ile tek bir fiziksel makinede dört sanal makineyi birbirine "cluster" olarak bağlıyorum. Gerçek sahada birden fazla fiziksel sunucu, ayrı switch'ler, gerçek ağ gecikmeleri olurdu; burada hepsi tek bir kutunun içinde simüle ediliyor.&lt;/p&gt;

&lt;p&gt;Bunu baştan söylüyorum çünkü Corosync'in gerçek gereksinimlerinden biri düşük gecikmeli bir ağ (5 milisaniyenin altı); nested bir ortamda bu neredeyse otomatik olarak sağlanıyor (sanal switch üzerinden iletişim gerçek bir fiziksel ağdan çok daha hızlı), bu yüzden bazı gerçek dünya sorunlarını (ağ gecikmesi, switch arızası) burada birebir yaşayamayacağım. Ama cluster mantığını, quorum'u, fencing'i anlamak için bu ortam fazlasıyla yeterli.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lab Mimarisi: Neden Nested Virtualization, Neden libvirt
&lt;/h2&gt;

&lt;p&gt;Üç ayrı fiziksel sunucum olmadığı için, tek makinede nested virtualization kullanıyorum: fiziksel makinede QEMU/KVM çalışıyor, bunun üzerinde dört sanal makine var, bu sanal makinelerin üçü Proxmox VE (cluster node'ları), biri de QDevice için minimal bir Debian.&lt;/p&gt;

&lt;p&gt;Bunu iki şekilde yapabilirdim: Proxmox VE'yi fiziksel makineye kurup içine nested Proxmox VM'leri koymak (bu, topluluk kaynaklarında sık görülen bir yöntem), ya da doğrudan Linux masaüstümde çalışan libvirt/QEMU'yu kullanmak. İkincisini seçtim, çünkü zaten kurulu ve çalışır durumdaydı; fazladan bir sanallaştırma katmanı eklemek (host'ta Proxmox, onun içinde nested Proxmox'lar) gereksiz karmaşıklık olurdu. Masaüstümü de kullanmaya devam edebiliyorum, bu da pratik bir avantaj.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nested Virtualization Kontrolü
&lt;/h3&gt;

&lt;p&gt;Bunu kurmadan önce doğrulamam gereken bir şey vardı: fiziksel CPU'nun nested virtualization'ı destekleyip desteklemediği. Bu, "VM içindeki VM'in de donanım hızlandırmalı çalışması" anlamına geliyor; olmazsa Proxmox node'larının içine koyacağım test VM'leri (ileride HA testleri için) çok yavaş çalışır.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /sys/module/kvm_intel/parameters/nested
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklg0ch5rxbu8oglrx7mx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fklg0ch5rxbu8oglrx7mx.png" alt="Terminal görüntüsü: nested virtualization kontrolü, çıktı Y" width="469" height="49"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Çıktı &lt;code&gt;Y&lt;/code&gt; geldi. Bu, i7-11800H'nin (Tiger Lake mimarisi) nested virtualization'ı sorunsuz desteklediğini doğruladı.&lt;/p&gt;




&lt;h2&gt;
  
  
  Kaynak Planlaması
&lt;/h2&gt;

&lt;p&gt;Donanımı (8 çekirdek/16 iş parçacığı, 32 GB RAM, NVMe üzerinde ~419 GB boş alan) dört VM'e nasıl paylaştıracağıma karar vermem gerekiyordu. Amaç, host masaüstünün (GNOME) rahatça çalışmaya devam etmesi, aynı zamanda cluster node'larının gerçekçi bir şekilde test edilebilmesiydi.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;VM&lt;/th&gt;
&lt;th&gt;vCPU&lt;/th&gt;
&lt;th&gt;RAM&lt;/th&gt;
&lt;th&gt;Disk (qcow2, thin)&lt;/th&gt;
&lt;th&gt;Rol&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pve-a&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6 GB&lt;/td&gt;
&lt;td&gt;40 GB&lt;/td&gt;
&lt;td&gt;Cluster node 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pve-b&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6 GB&lt;/td&gt;
&lt;td&gt;40 GB&lt;/td&gt;
&lt;td&gt;Cluster node 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pve-c&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6 GB&lt;/td&gt;
&lt;td&gt;40 GB&lt;/td&gt;
&lt;td&gt;Cluster node 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qdevice-1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;8 GB&lt;/td&gt;
&lt;td&gt;QDevice&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Toplam&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;19 GB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;128 GB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Bu paylaşım, 16 iş parçacığından 7'sini, 32 GB RAM'in 19 GB'ını kullanıyor; host için 9 iş parçacığı ve ~13 GB rahatça kalıyor. Disk thin-provisioned (qcow2) olduğu için 128 GB tahsis etsem bile gerçek kullanım başlangıçta çok daha az.&lt;/p&gt;

&lt;p&gt;Üç cluster node'una eşit kaynak verdim (2 vCPU / 6 GB); QDevice'e ise çok daha az (1 vCPU / 1 GB), çünkü QDevice'in işi ağır değil, sadece bir oy sağlamak.&lt;/p&gt;




&lt;h2&gt;
  
  
  ISO'ları İndirmek ve Doğrulamak
&lt;/h2&gt;

&lt;p&gt;Proxmox VE 9.2 ve QDevice için minimal bir Debian 13 (Trixie) ISO'su indirdim. Burada bir adımı atlamamak önemli: checksum doğrulaması.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"65273beed27b2df543b68b65630ba525cfbad8df2b12035732b2dff87d6664e7  debian-13.6.0-amd64-netinst.iso"&lt;/span&gt; | &lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"4e88fe416df9b527624a175f24c9aa07c714d3332afb1ee3dbf3879573ef2c6c  proxmox-ve_9.2-1.iso"&lt;/span&gt; | &lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft2v5wwmsxf31wf3sfzds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft2v5wwmsxf31wf3sfzds.png" alt="Checksum doğrulaması" width="728" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu adımı bir lab ortamında bile atlamamaya çalışıyorum; alışkanlık, üretim ortamında da aynı disiplini otomatik hale getiriyor. Bozuk bir indirme, kurulumun ortasında garip hatalar olarak geri dönüp saatler kaybettirebiliyor; iki saniyelik bir kontrol bunun önüne geçiyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ağ Mimarisi: NAT ve İzole Corosync Ağı
&lt;/h2&gt;

&lt;p&gt;Gerçek bir Proxmox cluster kurulumunda Corosync trafiğinin ayrı, adanmış bir ağda olması öneriliyor; VM trafiği veya storage trafiğiyle paylaşılan bir ağda gecikme dalgalanmaları Corosync'i etkileyebiliyor. Bunu nested lab'ımda da simüle etmek istedim, bu yüzden iki ayrı sanal ağ kurdum:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;default&lt;/code&gt; ağı:&lt;/strong&gt; libvirt'ün standart NAT ağı (&lt;code&gt;192.168.122.0/24&lt;/code&gt;). İnternete çıkış (apt update, paket indirme) ve Proxmox web arayüzüne host'tan erişim için kullanılıyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;corosync-net&lt;/code&gt; ağı:&lt;/strong&gt; Kendi tanımladığım, izole bir ağ (&lt;code&gt;10.10.10.0/24&lt;/code&gt;). Dışarıya çıkışı yok; sadece bu ağa bağlı VM'ler birbirini görebiliyor. Bunu, gerçek sahadaki "Corosync için adanmış NIC ve switch" pratiğinin bir simülasyonu olarak düşünebilirsin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;network&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;corosync-net&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;bridge&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;'virbr-coro'&lt;/span&gt; &lt;span class="na"&gt;stp=&lt;/span&gt;&lt;span class="s"&gt;'on'&lt;/span&gt; &lt;span class="na"&gt;delay=&lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ip&lt;/span&gt; &lt;span class="na"&gt;address=&lt;/span&gt;&lt;span class="s"&gt;'10.10.10.1'&lt;/span&gt; &lt;span class="na"&gt;netmask=&lt;/span&gt;&lt;span class="s"&gt;'255.255.255.0'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dhcp&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;range&lt;/span&gt; &lt;span class="na"&gt;start=&lt;/span&gt;&lt;span class="s"&gt;'10.10.10.10'&lt;/span&gt; &lt;span class="na"&gt;end=&lt;/span&gt;&lt;span class="s"&gt;'10.10.10.100'&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dhcp&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ip&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/network&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Her VM'e iki ağ arayüzü atadım: biri &lt;code&gt;default&lt;/code&gt;'a, biri &lt;code&gt;corosync-net&lt;/code&gt;'e. Proxmox kurulum sihirbazı sırasında sadece birinci arayüzü (default/NAT) yapılandıracağım; ikinci arayüzü (corosync-net) kurulumdan sonra Proxmox web arayüzünden elle ayarlayacağım. Bu ayrım bilinçli: yönetim/internet trafiği ile cluster'ın kendi iç iletişimini daha kurulum aşamasında birbirinden ayırmış oluyorum.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;corosync-net&lt;/code&gt;'i bilinçli olarak XML dosyası yazıp &lt;code&gt;virsh net-define&lt;/code&gt; ile tanımladım; virt-manager'ın "Create Virtual Network" sihirbazı da aynı işi yapardı, ama XML'i elle yazmak beni bridge adı, IP aralığı ve DHCP range gibi alanların her birini tek tek düşünmeye zorladı. Sihirbazda "ileri, ileri, bitir" derken çoğu ayarı görmeden geçebiliyorsun; XML'de her satırı kendin yazdığın için ne yaptığını daha net biliyorsun.&lt;/p&gt;

&lt;p&gt;Burada küçük ama can sıkıcı bir ayrıntıyla karşılaştım: &lt;code&gt;virsh&lt;/code&gt;'i normal kullanıcı olarak çalıştırdığımda, varsayılan olarak &lt;code&gt;qemu:///session&lt;/code&gt;'a bağlanıyor; bu, kullanıcıya özel, izole bir libvirt oturumu ve &lt;code&gt;default&lt;/code&gt; ağı dahil hiçbir sistem-geneli kaynağı görmüyor. Oysa virt-manager'ın oluşturduğu VM'ler ve &lt;code&gt;default&lt;/code&gt; NAT ağı &lt;code&gt;qemu:///system&lt;/code&gt; altında yaşıyor. &lt;code&gt;virsh net-define&lt;/code&gt;'ı &lt;code&gt;sudo&lt;/code&gt; olmadan çalıştırınca ağı yanlış tarafa (session) tanımlamış oldum; sonuç olarak &lt;code&gt;corosync-net&lt;/code&gt;, VM'lerin ağ listesinde hiç görünmedi. Çözüm basitti: komutu &lt;code&gt;sudo virsh net-define ...&lt;/code&gt; ile, yani sistem bağlantısı üzerinden çalıştırmak. Aynı ayrım &lt;code&gt;pool-define-as&lt;/code&gt; ve diğer &lt;code&gt;virsh&lt;/code&gt; komutları için de geçerli; hepsini &lt;code&gt;sudo&lt;/code&gt; ile ya da &lt;code&gt;-c qemu:///system&lt;/code&gt; ile çalıştırmak gerekiyor, aksi halde sessizce yanlış (görünmez) bir yere yazıyorsunuz.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxwst5e7xns6djjlmt9nf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxwst5e7xns6djjlmt9nf.png" alt="virsh net-list çıktısı - default ve corosync-net ağları" width="526" height="117"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Storage Pool ve VM'ler: Geri Kalanı Arayüzden
&lt;/h2&gt;

&lt;p&gt;Ağı XML ile tanımladıktan sonra, storage pool'u ve dört VM'i virt-manager'ın grafik arayüzünden oluşturdum. "Create a new virtual machine" sihirbazında sırasıyla: ISO dosyasını seçtim, bellek/vCPU değerlerini yukarıdaki tabloya göre girdim, disk boyutunu ayarladım (qcow2, thin-provisioned), ve ağ sekmesinde iki arayüzü de (&lt;code&gt;default&lt;/code&gt; ve &lt;code&gt;corosync-net&lt;/code&gt;) ekledim. CPU modeli için "Copy host CPU configuration" seçeneğini işaretledim; bu, host-passthrough ile aynı işi görüyor, fiziksel CPU'nun VMX özelliğini VM'e taşıyor ve nested virtualization zincirinin ikinci halkasını tamamlıyor.&lt;/p&gt;

&lt;p&gt;Aynı sihirbazı &lt;code&gt;pve-a&lt;/code&gt;, &lt;code&gt;pve-b&lt;/code&gt;, &lt;code&gt;pve-c&lt;/code&gt; için üç kez, &lt;code&gt;qdevice-1&lt;/code&gt; için çok daha hafif kaynaklarla bir kez daha çalıştırdım.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fetnk3gzgnvriesxwqi25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fetnk3gzgnvriesxwqi25.png" alt="virt-manager - dört VM'in listesi, kurulum bekliyor durumunda" width="755" height="391"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0s8num7u6u8myb1pw40a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0s8num7u6u8myb1pw40a.png" alt="VM oluşturma sihirbazı - CPU sekmesi, Copy host CPU configuration seçili" width="800" height="767"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Kurulumu Tamamlamak: Proxmox VE ve Debian
&lt;/h2&gt;

&lt;p&gt;VM'leri oluşturup ISO dosyalarını bağladıktan sonra kurulumları doğrudan &lt;strong&gt;virt-manager&lt;/strong&gt; konsolundan tamamladım. İlk aşamada her sanal makineye yalnızca &lt;strong&gt;Management (NAT)&lt;/strong&gt; ağı bağlıydı. Böylece Proxmox VE ve Debian kurulumları herhangi bir ek ağ yapılandırmasına ihtiyaç duymadan tamamlanabildi.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pve-a&lt;/code&gt;, &lt;code&gt;pve-b&lt;/code&gt; ve &lt;code&gt;pve-c&lt;/code&gt; için Proxmox VE kurulumu standart sihirbaz üzerinden ilerledi. Hedef disk seçimi (tek bir VirtIO disk), ülke ve saat dilimi, root parolası ve son olarak &lt;strong&gt;Management Network Configuration&lt;/strong&gt; ekranında ilk ağ arayüzüne yönetim IP adreslerini atadım.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;qdevice-1&lt;/code&gt; için ise masaüstü ortamı kurmadan, yalnızca &lt;strong&gt;SSH server&lt;/strong&gt; ve &lt;strong&gt;standard system utilities&lt;/strong&gt; paketlerini seçerek minimal bir Debian 13 kurulumu yaptım.&lt;/p&gt;

&lt;p&gt;Kurulum tamamlandıktan sonra artık virt-manager konsoluna ihtiyaç kalmadı. Bundan sonraki tüm yapılandırmayı kendi terminalim üzerinden &lt;strong&gt;SSH&lt;/strong&gt; ile yaptım. Bunun iki önemli avantajı vardı:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Komutları doğrudan kopyala-yapıştır ile çalıştırabilmek,&lt;/li&gt;
&lt;li&gt;Yapılan değişiklikleri daha rahat takip edip gerektiğinde tekrar edebilmek.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Proxmox VE'de root kullanıcısıyla SSH erişimi varsayılan olarak açık geldiği için ek bir ayar yapmam gerekmedi. Debian tarafında ise güvenlik nedeniyle root ile SSH oturumu varsayılan olarak kapalıydı. Bu nedenle &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; dosyasında aşağıdaki satırı düzenledim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PermitRootLogin yes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp99xribhku7ys71ya6i3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp99xribhku7ys71ya6i3.png" alt=" " width="799" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ardından SSH servisini yeniden başlatarak root kullanıcısıyla uzaktan bağlantıyı etkinleştirdim.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl restart sshd.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İlk kurulum tamamlandıktan sonra ikinci ağ arayüzünü (&lt;strong&gt;corosync-net&lt;/strong&gt;) yapılandırdım. Proxmox node'larında bunu &lt;code&gt;/etc/network/interfaces&lt;/code&gt; dosyası üzerinden yaptım; Debian tarafında da aynı yöntemle Corosync ağı için statik IP adresini tanımladım.&lt;/p&gt;

&lt;p&gt;Son durumda lab ortamının ağ planı şu şekilde oluştu:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Makine&lt;/th&gt;
&lt;th&gt;Management (NAT)&lt;/th&gt;
&lt;th&gt;Corosync&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pve-a&lt;/td&gt;
&lt;td&gt;192.168.122.11&lt;/td&gt;
&lt;td&gt;10.10.10.11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pve-b&lt;/td&gt;
&lt;td&gt;192.168.122.12&lt;/td&gt;
&lt;td&gt;10.10.10.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pve-c&lt;/td&gt;
&lt;td&gt;192.168.122.13&lt;/td&gt;
&lt;td&gt;10.10.10.13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;qdevice-1&lt;/td&gt;
&lt;td&gt;192.168.122.20&lt;/td&gt;
&lt;td&gt;10.10.10.20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Kurulum sırasında hostnameleri de son hâlleriyle belirledim. Bu lab'da &lt;strong&gt;&lt;code&gt;.home.arpa&lt;/code&gt;&lt;/strong&gt; alan adını kullanıyorum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pve-a.home.arpa
pve-b.home.arpa
pve-c.home.arpa
qdevice-1.home.arpa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bunun iki önemli sebebi var. Birincisi, &lt;strong&gt;&lt;code&gt;.home.arpa&lt;/code&gt;&lt;/strong&gt; RFC 8375 ile yalnızca ev ve yerel ağlar için ayrılmış özel bir alan adıdır. Gerçek internette hiçbir zaman çözümlenmez; dolayısıyla ileride gerçek bir alan adıyla çakışma riski bulunmaz. İkincisi ise sıkça kullanılan &lt;strong&gt;&lt;code&gt;.local&lt;/code&gt;&lt;/strong&gt; uzantısının mDNS (Multicast DNS) tarafından rezerve edilmiş olmasıdır. Linux sistemlerde Avahi, macOS'ta Bonjour ve diğer mDNS uygulamaları &lt;code&gt;.local&lt;/code&gt; alanını kullandığından, özellikle cluster ortamlarında isim çözümleme problemlerine yol açabilir. Bu nedenle Proxmox'un da önerdiği yaklaşımlardan biri olan &lt;strong&gt;&lt;code&gt;.home.arpa&lt;/code&gt;&lt;/strong&gt; daha doğru ve geleceğe dönük bir tercih oluyor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;strong&gt;Not:&lt;/strong&gt; Bu aşamadan sonra dört makine de birbirine Management ağı üzerinden SSH ile erişebilir, Corosync ağı ise tamamen hazır durumda bekliyor. Artık cluster oluşturma aşamasına geçebiliriz.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Bağlantıyı Doğrulamak
&lt;/h3&gt;

&lt;p&gt;Dört node'un birbirini gerçekten görüp görmediğini, &lt;code&gt;pve-a&lt;/code&gt;'dan her iki ağ üzerinden ping atarak test ettim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpyg895fywj055z09n329.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpyg895fywj055z09n329.png" alt="NAT ağı üzerinden ping" width="658" height="571"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqg1s584y13lskp2fcedc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqg1s584y13lskp2fcedc.png" alt="Corosync ağı üzerinden ping" width="658" height="571"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sıfır paket kaybı, gecikmeler milisaniyenin çok altında (Corosync'in gerektirdiği 5ms sınırının çok altında, beklendiği gibi; nested bir ortamda ağ gecikmesi neredeyse ölçülemeyecek kadar düşük). Aynı testi &lt;code&gt;pve-b&lt;/code&gt; ve &lt;code&gt;pve-c&lt;/code&gt;'den de tekrarladım, sonuçlar aynı; hepsi birbirini her iki ağdan da görüyor.&lt;/p&gt;

&lt;p&gt;Bu noktada lab hazır: dört makine kurulu, isimlendirilmiş, iki ayrı ağdan birbirine ulaşabiliyor. Bir sonraki yazıda artık kuruluma değil, doğrudan kavramlara geçebiliyorum.&lt;/p&gt;

&lt;p&gt;Küçük bir not: &lt;code&gt;qdevice-1&lt;/code&gt; üzerine &lt;code&gt;corosync-qnetd&lt;/code&gt; paketini de bu aşamada kurup servisi etkinleştirdim; ileride QDevice'i devreye alacağım modülde hazır beklesin diye. Asıl QDevice kurulumu ve testleri (&lt;code&gt;pvecm qdevice setup&lt;/code&gt;, 2-node senaryosu, quorum matematiği) kendi modülünde ayrıca işlenecek; burada sadece "ortam hazır" demek istedim.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa5m0bw5qb24iau5pvmt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa5m0bw5qb24iau5pvmt1.png" alt="Genel Topoloji" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu modülde henüz tek bir Proxmox komutu çalıştırmadım; her şey "cluster'ı kuracağım ortamı hazırlamak" üzerineydi. Ama bu hazırlık aşaması, VMware serisindeki gibi hazır bir HOL kullanırken hiç düşünmek zorunda kalmadığım kararları öne çıkardı.&lt;/p&gt;

&lt;p&gt;En çok üzerinde durduğum nokta ağ mimarisiydi. VMware HOL'da Corosync'e denk bir kavram yoktu, ama vSAN serisinin Modül 4'ünde (Stretched Cluster) gördüğüm "witness trafiğini ayrı tutma" mantığıyla burada kurduğum NAT/corosync-net ayrımı aslında aynı prensibi paylaşıyor: kritik, düşük gecikmeli bir iletişim kanalını, genel amaçlı trafikten izole tutmak. Farklı ürünler, aynı temel disiplin.&lt;/p&gt;

&lt;p&gt;İkinci nokta, checksum doğrulamasını bir lab ortamında bile atlamamaktı. Küçük bir şey ama bunun bir HOL'da hiç düşünmem gereken bir adım olduğunu fark ettim; VMware zaten doğrulanmış bir ortam sunuyordu. Kendi lab'ını kurunca, bu tür "sıradan" disiplinlerin aslında ne kadar bilinçli bir seçim olduğunu görüyorsun.&lt;/p&gt;

&lt;p&gt;Üçüncü nokta, ağı XML ile tanımlarken fark ettiğim şey. Storage pool ve VM'leri virt-manager sihirbazıyla oluşturmak hızlı ve rahattı, ama tam olarak neyi neden yaptığımı hatırlamıyorum diyebilirim; sihirbaz benim adıma çoğu kararı verdi. Ağı XML ile yazarken ise her alanı (bridge adı, IP aralığı, DHCP range) kendim belirlemek zorunda kaldım; bu yüzden şu an o ağın nasıl çalıştığını çok daha net açıklayabiliyorum. Bu, aslında GUI'nin kötü olduğu anlamına gelmiyor, sadece "hızlı yapmak" ile "anlayarak yapmak" arasında küçük bir ödünleşim olduğunu gösteriyor.&lt;/p&gt;

&lt;p&gt;Bir sonraki yazıda Modül 1'e geçiyorum: lab artık tamamen hazır ve doğrulanmış durumda, sırada Cluster, Corosync ve pmxcfs kavramları, ve cluster'ı kurmadan hemen önce pmxcfs'in tek-node haldeki davranışını gözlemlemek var.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri, resmi Proxmox VE dokümantasyonundan (pve.proxmox.com) derlenen bir müfredatı takip ediyor; hazır bir lab ortamı olmadığı için her adımı kendim kuruyor ve test ediyorum. 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.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>proxmox</category>
      <category>corosync</category>
    </item>
    <item>
      <title>vSAN Data Protection: Snapshot, Protection Group ve Immutability (Modül 7)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Sun, 26 Jul 2026 14:08:18 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/vsan-data-protection-snapshot-protection-group-ve-immutability-modul-7-190a</link>
      <guid>https://dev.to/hakanbaban53/vsan-data-protection-snapshot-protection-group-ve-immutability-modul-7-190a</guid>
      <description>&lt;p&gt;Altı haftadır SPBM'den File Services'e kadar vSAN'ın farklı katmanlarını gezdim. Modül 7, serinin son modülü ve konusu net: Data Protection. Bu modülde snapshot almayı, VM'leri "protection group" adı verilen politikalarla korumayı, silinmiş bir VM'i geri getirmeyi ve ransomware senaryolarına karşı değiştirilemez (immutable) koruma gruplarını görüyoruz.&lt;/p&gt;

&lt;p&gt;Bu modül önceki altısına göre daha "hikaye anlatan" bir yapıya sahip. Sadece bir özelliği açıp kapatmıyoruz; bir VM oluşturup koruyoruz, siliyoruz, geri getiriyoruz, klonluyoruz. Bu akış, konuyu soyut bir özellik listesinden çıkarıp gerçek bir operasyonel senaryoya dönüştürüyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  vSAN Data Protection Nedir?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8q4gyj9dejq0ll9osdyh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8q4gyj9dejq0ll9osdyh.png" alt="vSAN Data Protection" width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vSAN Data Protection (DP), vSAN 8.0 Update 3'te tanıtılan bir özellik. Amaç, VM'leri operasyonel hatalardan veya ransomware saldırılarından hızlıca kurtarabilmek; bunu vSAN cluster üzerinde yerel olarak saklanan native snapshot'larla yapıyor.&lt;/p&gt;

&lt;p&gt;Mimari olarak birkaç önemli nokta var:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Policy tabanlı "protection group" kavramıyla çalışıyor; hangi VM'lerin korunacağını, snapshot sıklığını ve saklama (retention) süresini bu gruplar üzerinden yönetiyorsunuz.&lt;/li&gt;
&lt;li&gt;Yanlışlıkla silinen VM'leri kurtarmak veya operasyonel çeviklik için VM'leri hızlıca klonlamak için kullanılabiliyor.&lt;/li&gt;
&lt;li&gt;VMware Live Cyber Recovery çözümüyle entegre olarak ransomware senaryolarından kurtarmayı da destekliyor (bu ayrı bir lisans gerektiriyor).&lt;/li&gt;
&lt;li&gt;Sadece vSAN ESA (Express Storage Architecture) ile çalışan HCI cluster'larda destekleniyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mimari tarihçesi de ilginç: vSAN 8.0u3'te bu servis ayrı indirilebilir bir "vSAN Snapmanager Appliance" olarak geliyordu. vSAN 9.0 ile birlikte vSAN Data Protection, vSphere Replication ve VMware Live Recovery tek bir appliance'da birleşti. HOL'da bu appliance zaten kurulu ve vCenter'a kayıtlı; biz doğrudan vSphere Client üzerinden Data Protection'ı kullanıyoruz.&lt;/p&gt;

&lt;p&gt;Bir not daha: vSAN 9'da protection group'lar, vCenter'lar arası vSAN-to-vSAN replikasyon içeren VMware Live Recovery ile entegre olabiliyor. Bu modül sadece yerel snapshot'ları kapsıyor; replikasyonun aksiyonda görülmesi için ayrı bir lab (HOL-2634-03-VCF-L) öneriliyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  vSAN ESA Snapshot'ları: Temel Mekanik
&lt;/h2&gt;

&lt;p&gt;ESA, VM'in durumunu ve verisini snapshot alındığı andaki haliyle koruyan entegre, yüksek performanslı bir snapshot mekanizması sunuyor. Birkaç teknik detay:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Snapshot alındığında VM'in o anki çalışan durumu yakalanıyor; snapshot'lar "quiesced" (uygulama seviyesinde tutarlılık için duraklatılmış) değil.&lt;/li&gt;
&lt;li&gt;Snapshot'lar bireysel VM'ler üzerinde çalışıyor; her VM ayrı bir snapshot gerektiriyor.&lt;/li&gt;
&lt;li&gt;Her vSAN snapshot'ı, VM'in namespace nesnesinin ve virtual disk nesnelerinin durumunu içeriyor.&lt;/li&gt;
&lt;li&gt;Protection group'lardaki VM'lerin snapshot'ları zamanlanmış aralıklarla alınıyor ve yerel olarak vSAN datastore'da saklanıyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bu, geleneksel vSphere snapshot mekanizmasından farklı bir zihniyetle çalışıyor; snapshot almak burada manuel bir "şimdi al" işlemi değil, bir politikanın parçası olarak zamanlanmış bir süreç.&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Protection Arayüzüne Giriş
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cluster-esa-01a &amp;gt; Configure &amp;gt; vSAN &amp;gt; Data Protection&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Genel Bakış (Overview)
&lt;/h3&gt;

&lt;p&gt;Overview bölümünde, cluster'daki 7 VM'den 4'ünün korunduğu görülüyor. Grafik bu korumanın türünü (yerel, replikasyon veya korumasız) gösteriyor.&lt;/p&gt;

&lt;p&gt;"vSAN Snapshot Space Usage" bölümünde snapshot'ların kullandığı kapasitenin dökümü var. Burada dikkat çeken bir uyarı kutusu var: datastore kullanımı %70'i aştığında zamanlanmış snapshot'lar alınmıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffeux7au184zz69vha2vg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffeux7au184zz69vha2vg.png" alt="Data Protection Overview - korunan VM sayısı ve Snapshot Space Usage" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu %70 eşiği bana Modül 1'deki Reserved Capacity konseptini hatırlattı; orada da benzer bir "belirli bir doluluk oranından sonra sistem kendini korumaya alır" mantığı vardı. Burada aynı mantık, snapshot alma sürecine uygulanmış.&lt;/p&gt;

&lt;h3&gt;
  
  
  Protection Groups
&lt;/h3&gt;

&lt;p&gt;HOL ortamında iki protection group önceden tanımlı:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Core PG:&lt;/strong&gt; Sadece yerel snapshot alıyor, bir VM'i aktif olarak koruyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote Acct PG:&lt;/strong&gt; Site B'ye vSAN replikasyonu yapıyor, üç VM'i koruyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Her ikisi de "Active" durumda, yani zamanlanmış snapshot'lar konfigüre edildiği gibi alınıyor. Core PG'nin iki yerel snapshot'ı var; en son snapshot belirli bir tarihte alınmış.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1d4nlpfxp7fmmge33h4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1d4nlpfxp7fmmge33h4v.png" alt="Protection Groups listesi - Core PG ve Remote Acct PG detayları" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Existing VMs, Removed VMs, Incoming VMs
&lt;/h3&gt;

&lt;p&gt;VMs sekmesi, cluster'daki VM'leri üç kategoride gruplandırıyor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Existing VMs:&lt;/strong&gt; Şu anda vSAN'da aktif olarak bulunan VM'ler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removed VMs:&lt;/strong&gt; Silinmiş ama hâlâ mevcut bir snapshot tarafından korunan VM'ler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incoming VMs:&lt;/strong&gt; Bu cluster'a replike edilmekte olan VM'ler.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Her VM için protection group'u, yerel koruma durumu, replikasyon durumu ve (varsa) hangi peer cluster'a replike edildiği gösteriliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0up6j8j1z71zk388i9e0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0up6j8j1z71zk388i9e0.png" alt="VMs sekmesi - Existing/Removed/Incoming VM kategorileri" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Removed VMs sekmesinde &lt;code&gt;core-c&lt;/code&gt; adlı bir VM görülüyor; bu VM silinmiş ama snapshot'ı hâlâ mevcut, yani geri getirilebilir durumda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7dqtbcglntuutb90x0wn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7dqtbcglntuutb90x0wn.png" alt="Removed VMs - core-c VM'inin görünümü" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Replication Pairs
&lt;/h3&gt;

&lt;p&gt;REPLICATION sekmesinde vSAN replikasyon sunucu çiftleri görülüyor. Site A cluster'ı (&lt;code&gt;cluster-esa-01a&lt;/code&gt;), Site B cluster'ına (&lt;code&gt;vsan-client-cluster-01b&lt;/code&gt;) eşleştirilmiş ve Remote Acct PG protection group'undaki üç VM'i replike ediyor. Bu özelliğin VMware Live Recovery lisansı gerektirdiği belirtiliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy0m91xc52h1vzvba58hg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy0m91xc52h1vzvba58hg.png" alt="Replication Pairs - Site A'dan Site B'ye replikasyon" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu ekran, Modül 5'te gördüğümüz Storage Cluster/Compute Cluster ayrımının farklı bir versiyonunu hatırlattı bana; orada da farklı cluster'lar birbirine bir hizmet sağlıyordu, burada ise koruma amaçlı bir replikasyon ilişkisi var.&lt;/p&gt;




&lt;h2&gt;
  
  
  Yeni Bir Protection Group Oluşturmak
&lt;/h2&gt;

&lt;p&gt;Modülün pratik kısmı burada başlıyor. Amacımız, "sales-" ön ekiyle başlayan satış uygulaması VM'lerini koruyan bir protection group oluşturmak.&lt;/p&gt;

&lt;h3&gt;
  
  
  Genel Ayarlar
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Protection Groups &amp;gt; Create Protection Group&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;İsim: &lt;code&gt;Sales Apps PG&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Protection type: üç seçenek var:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local protection and replication:&lt;/strong&gt; Yerel snapshot alıp başka bir vSAN cluster'a da replike ediyor (VMware Live Recovery lisansı gerekiyor).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local protection:&lt;/strong&gt; Sadece yerel snapshot alıyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replication:&lt;/strong&gt; Sadece başka bir cluster'a replike ediyor (VMware Live Recovery gerekiyor).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bu HOL'da &lt;strong&gt;Local protection&lt;/strong&gt; seçiliyor.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Immutability mode kutusu şimdilik işaretsiz bırakılıyor (bu konuya modülün sonunda dönülüyor).&lt;/li&gt;
&lt;li&gt;VM seçim yöntemi olarak Dynamic VM name patterns seçiliyor.&lt;/li&gt;
&lt;li&gt;NEXT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkwy6lstcbprgshglfmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkwy6lstcbprgshglfmx.png" alt="Create Protection Group - General sayfası" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  VM İsim Deseni Eklemek
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;sales*&lt;/code&gt; deseni giriliyor (tüm satış uygulaması VM'leri &lt;code&gt;sales-xxxx-y&lt;/code&gt; adlandırma kuralını kullanıyor). Add'e tıklandığında, eşleşen &lt;code&gt;sales-app-01&lt;/code&gt;, &lt;code&gt;sales-db-01&lt;/code&gt; ve &lt;code&gt;sales-web-01&lt;/code&gt; VM'leri listede görünüyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhdv6d9rba5ltsyl92asu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhdv6d9rba5ltsyl92asu.png" alt="VM name pattern ekranı - sales* deseni ve eşleşen VM'ler" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu dinamik isimlendirme yaklaşımı bence modülün en pratik fikri. Sabit bir VM listesi tutmak yerine bir isim deseni tanımlamak, gelecekte oluşturulacak yeni VM'lerin de otomatik olarak korunmasını sağlıyor; bunu birazdan test edeceğiz.&lt;/p&gt;

&lt;h3&gt;
  
  
  Snapshot Zamanlaması
&lt;/h3&gt;

&lt;p&gt;Burada önemli bir teknik sınır var: vSAN ESA snapshot'ları, nesne başına en fazla 200 kopyaya kadar ölçekleniyor. Snapshot sıklığı ve saklama süresi kombinasyonu bu sınırı aşarsa, protection group oluşturulmadan önce düzenlenmesi gerekiyor.&lt;/p&gt;

&lt;p&gt;Bu HOL'da:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Snapshot sıklığı: her 8 saatte bir&lt;/li&gt;
&lt;li&gt;Saklama süresi: 2 ay&lt;/li&gt;
&lt;li&gt;NEXT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bir protection group için birden fazla snapshot zamanlaması tanımlamak da mümkün, ama bu lab'da tek bir zamanlama kullanılıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcfb2k9xklpb33fk09mqk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcfb2k9xklpb33fk09mqk.png" alt="Snapshot schedule ekranı - 8 saat sıklık, 2 ay saklama" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;200 kopya sınırını akılda tutarak hızlıca bir hesap yaptım: 8 saatte bir snapshot, günde 3 kopya demek. 2 aylık saklama süresinde bu yaklaşık 180 kopyaya denk geliyor, sınırın altında ama yakınında. Bu tür bir hesabı protection group tasarlarken önceden yapmak, ileride "limit aşıldı" hatasıyla karşılaşmamak için gerekli.&lt;/p&gt;

&lt;h3&gt;
  
  
  Review ve Oluşturma
&lt;/h3&gt;

&lt;p&gt;Review ekranında dikkat çeken bir not var: standart vSphere Client "snapshot" arayüzünün aksine, vSAN Data Protection snapshot'ları hemen oluşturmuyor, bunun yerine zamanlıyor. Ama istenirse manuel bir snapshot da alınabileceği hatırlatılıyor. CREATE ile protection group oluşturuluyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhgdb245mcadu2j5hq2pr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhgdb245mcadu2j5hq2pr.png" alt="Review sayfası - protection group özeti" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Manuel Snapshot Almak
&lt;/h2&gt;

&lt;p&gt;Protection group oluşturulduğunda henüz hiçbir snapshot yok; bu yüzden bir uyarı üçgeni ile işaretleniyor. 8 saat beklemek yerine manuel snapshot alınabiliyor.&lt;/p&gt;

&lt;p&gt;Sales Apps PG'nin üç nokta menüsünden "Take local snapshot" seçiliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl3uidc9auu2ggtfgzyk7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl3uidc9auu2ggtfgzyk7.png" alt="Protection Groups listesi - uyarı üçgeni ve Take local snapshot seçeneği" width="799" height="203"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Snapshot ismi varsayılan olarak protection group adı, oluşturma yöntemi ve zaman damgasını içeren açıklayıcı bir isim alıyor. Saklama süresi olarak "1 gün" seçiliyor, TAKE SNAPSHOT tıklanıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftzklu8e9zchem84fal1t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftzklu8e9zchem84fal1t.png" alt="Take Snapshot ekranı - isim ve retention seçimi" width="547" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recent Tasks panelinden işlem takip ediliyor; tamamlandığında uyarı üçgeni kayboluyor ve üç Sales VM'i için snapshot'lar görünüyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dinamik İsimlendirmeyi Test Etmek: Yeni Bir VM Oluşturmak
&lt;/h2&gt;

&lt;p&gt;Bu bölüm, dinamik isim deseninin gerçekten çalıştığını kanıtlıyor. &lt;code&gt;sales-&lt;/code&gt; ön ekiyle yeni bir VM oluşturursak, protection group'a manuel müdahale etmeden otomatik olarak dahil olması bekleniyor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cluster-esa-01a&lt;/code&gt; üzerine sağ tık → New Virtual Machine → Create a new virtual machine. Sihirbaz adımları:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;İsim: &lt;code&gt;sales-lab&lt;/code&gt;, Sales klasörü seçili&lt;/li&gt;
&lt;li&gt;Compute resource: &lt;code&gt;cluster-esa-01a&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storage: &lt;code&gt;vsan-esa-01a_Datastore&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Compatibility: varsayılan (ESX 9.0 ve üzeri)&lt;/li&gt;
&lt;li&gt;Guest OS: Linux, VMware Photon OS (64-bit)&lt;/li&gt;
&lt;li&gt;Hardware: varsayılan ayarlar, FINISH&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fftt2tkn2goi70gy6mg3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fftt2tkn2goi70gy6mg3f.png" alt="New Virtual Machine wizard - sales-lab VM'i oluşturma" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VM oluşturulduktan sonra vCenter inventory'de kayıtlı olduğu doğrulanıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk6shhcnwgskzlotod45x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk6shhcnwgskzlotod45x.png" alt="cluster-esa-01a VM listesi - sales-lab VM'i" width="376" height="599"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Data Protection'a dönülüp Sales Apps PG için tekrar manuel snapshot alınıyor (yeni VM'in zamanlanmış aralığı beklemesine gerek kalmadan test etmek için). İşlem tamamlandığında dört VM'in korunduğu görülüyor: orijinal üç sales VM'i ve yeni oluşturulan &lt;code&gt;sales-lab&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Burada altı çizilen önemli nokta şu: yeni VM eklendiğinde protection group'un yeniden yapılandırılmasına gerek kalmadı, çünkü dinamik isimlendirme seçeneği kullanılmıştı. Bu, production ortamında sürekli yeni VM oluşturulan bir ortamda (örneğin bir CI/CD pipeline veya self-service VM provisioning sürecinde) manuel takip yükünü ortadan kaldıran bir tasarım.&lt;/p&gt;




&lt;h2&gt;
  
  
  VM'leri Geri Yüklemek
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mevcut Bir VM'i Önceki Bir Ana Geri Döndürmek
&lt;/h3&gt;

&lt;p&gt;Bu senaryoda &lt;code&gt;core-a&lt;/code&gt; VM'i, mevcut bir snapshot noktasına geri döndürülüyor. Önce &lt;code&gt;core-a&lt;/code&gt;'nın açık (powered on) olduğu doğrulanıyor.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;VMs &amp;gt; core-a seçili &amp;gt; Restore VM&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Data Protection burada bir uyarı veriyor: VM kapatılacak ve geri yükleme öncesinde, ileride "ileri sarma" (mevcut duruma dönme) seçeneği olabilmesi için yeni bir snapshot otomatik olarak alınacak. Mevcut snapshot'lardan biri seçilip RESTORE'a tıklanıyor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;strong&gt;[Resim: Restore VM ekranı - core-a için snapshot seçimi ve uyarı]&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyo0pbxwyqhtevzkvjyft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyo0pbxwyqhtevzkvjyft.png" alt=" " width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;İşlem tamamlandığında &lt;code&gt;core-a&lt;/code&gt;'nın kapalı (powered off) olduğu görülüyor, tıpkı uyarıldığı gibi. Snapshot sütununda snapshot sayısının 2'den 3'e çıktığı da fark ediliyor; bu, restore işleminin kendisinin de bir snapshot bıraktığını gösteriyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhsx4utznvka4x924nzy4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhsx4utznvka4x924nzy4.png" alt="Restored VM durumu - powered off ve artan snapshot sayısı" width="800" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu davranış bana mantıklı geldi: bir restore işlemi, geri dönülemez bir işlem değil. Restore öncesi durumun da bir snapshot olarak saklanması, "yanlışlıkla yanlış snapshot'a döndüm" senaryosunda ikinci bir güvenlik ağı sağlıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Silinmiş Bir VM'i Geri Getirmek
&lt;/h3&gt;

&lt;p&gt;Bu, modülün en dramatik anı: tamamen silinmiş bir VM'in snapshot'tan yeniden oluşturulması.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;VMs &amp;gt; Removed VMs &amp;gt; core-c seçili &amp;gt; Restore VM&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Sihirbaz adımları:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bir snapshot seçiliyor, NEXT&lt;/li&gt;
&lt;li&gt;İsim ve klasör: varsayılan olarak orijinal isim &lt;code&gt;core-c&lt;/code&gt; korunuyor, &lt;code&gt;dc-a&lt;/code&gt; kök klasöründe kalıyor, NEXT&lt;/li&gt;
&lt;li&gt;Compute resource: varsayılan &lt;code&gt;cluster-esa-01a&lt;/code&gt;, NEXT&lt;/li&gt;
&lt;li&gt;RESTORE&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgcw659mr27nwzsy2d6fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgcw659mr27nwzsy2d6fx.png" alt=" " width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;İşlem tamamlandığında &lt;code&gt;core-c&lt;/code&gt;, vCenter inventory'sinde tekrar görünüyor, açılmaya hazır durumda. VM'in adı "core" ile başladığı için, cluster'da kaldığı sürece otomatik olarak zaten var olan Core PG protection group'u tarafından korunmaya devam ediyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7xo3tfmowm0y99nmz8l1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7xo3tfmowm0y99nmz8l1.png" alt="vCenter inventory - geri getirilen core-c VM'i" width="384" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu son detay dikkatimi çekti: dinamik isimlendirme kullanan bir protection group, sadece yeni oluşturulan VM'leri değil, geri getirilen VM'leri de otomatik olarak kapsıyor. İsim deseni eşleştiği sürece, VM'in "geçmişi" (silinmiş olması) önemli değil.&lt;/p&gt;




&lt;h2&gt;
  
  
  VM Klonlamak
&lt;/h2&gt;

&lt;p&gt;vSAN Data Protection, protection group'a atanmış herhangi bir VM'den hızlıca klon oluşturma imkanı da sunuyor. Bu klonlar ESA snapshot'larına dayanıyor ve linked-clone mimarisi kullanıyor; hızlı oluşturma ve yüksek performans sağlıyor, ama bunlar kalıcı VM'ler değil, araştırma veya VM içindeki belirli verileri kurtarma amaçlı geçici kopyalar olarak düşünülmeli.&lt;/p&gt;

&lt;p&gt;Önemli bir ayrım: Data Protection'ın ürettiği klonlar, vCenter'ın geleneksel "clone" işleminden farklı ve bu klonlar vSAN Data Protection tarafından korunmaya &lt;strong&gt;aday değil&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Klonlama Adımları
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;VMs &amp;gt; Existing VMs &amp;gt; core-a seçili &amp;gt; Clone VM&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bir snapshot seçiliyor, NEXT&lt;/li&gt;
&lt;li&gt;İsim: varsayılan &lt;code&gt;core-a-clone&lt;/code&gt;, &lt;code&gt;dc-a&lt;/code&gt; kök klasörü, NEXT&lt;/li&gt;
&lt;li&gt;Compute resource: varsayılan &lt;code&gt;cluster-esa-01a&lt;/code&gt;, NEXT&lt;/li&gt;
&lt;li&gt;CLONE&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbl9tlppgbtxiarou0hu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcbl9tlppgbtxiarou0hu.png" alt="Clone VM sihirbazı - snapshot ve hedef seçimi" width="799" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Klon tamamlandığında &lt;code&gt;core-a-clone&lt;/code&gt; vCenter inventory'de görünüyor. VMs panelinde bu klonun durumu "Not protected" olarak işaretleniyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyz5nhhmey2i5y38r9x5i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyz5nhhmey2i5y38r9x5i.png" alt="VMs listesi - core-a-clone'un Not protected durumu" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Klonların Neden Korunmadığını Doğrulamak
&lt;/h3&gt;

&lt;p&gt;Bunu somut olarak görmek için Core PG protection group'u Edit ile açılıyor, "Individual VM selection" seçiliyor. Bu ekranda vSAN Data Protection açıkça uyarıyor: linked-clone VM'ler protection group'larda desteklenmiyor. &lt;code&gt;core-a-clone&lt;/code&gt;, aday VM listesinden zaten filtrelenmiş durumda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foj1hlnt5m1lne3iq0fhq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foj1hlnt5m1lne3iq0fhq.png" alt="Edit Protection Group - core-a-clone'un aday listesinden filtrelenmesi" width="799" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu kısıtlama mantıklı: bir linked-clone, zaten bir snapshot'a bağımlı bir yapı. Onu tekrar bir protection group'a dahil edip snapshot almaya çalışmak, muhtemelen mimari olarak dairesel bir bağımlılık yaratırdı. Data Protection bu senaryoyu en baştan engelliyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Immutable Protection Groups: Ransomware'e Karşı Bir Kilit
&lt;/h2&gt;

&lt;p&gt;Modülün son ve bence en önemli konsepti burada: değiştirilemez (immutable) protection group'lar.&lt;/p&gt;

&lt;p&gt;Bir protection group immutable olarak oluşturulduğunda, oluşturulduktan sonra değiştirilemiyor veya iptal edilemiyor. Korunan VM kriterleri (dinamik isimlendirme, bireysel VM seçimi veya ikisinin kombinasyonu), snapshot zamanlaması ve saklama süresi ilk konfigürasyondan sonra sabitleniyor. Protection group da silinemiyor.&lt;/p&gt;

&lt;p&gt;Bu tasarımın amacı açık: kötü niyetli aktörlerin (bad actors) koruma planlarına müdahale etmesini veya onları silmesini engellemek. Bu, ransomware saldırısı senaryosunda özellikle anlamlı; bir saldırgan sisteme erişim sağlasa bile, snapshot'ları ve koruma politikasını silip kurtarma imkanını ortadan kaldıramıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Immutable Protection Group Oluşturmak
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Protection Groups &amp;gt; Create Protection Group&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;İsim: &lt;code&gt;Immutable Core Apps&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Protection type: Local protection&lt;/li&gt;
&lt;li&gt;Immutability mode kutusu işaretleniyor; bu grup oluşturulduktan sonra düzenlenemeyeceğine dair bir uyarı beliriyor&lt;/li&gt;
&lt;li&gt;VM seçimi: Dynamic VM name patterns&lt;/li&gt;
&lt;li&gt;NEXT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi1ritgw5qukqiom89yb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi1ritgw5qukqiom89yb7.png" alt="Create Protection Group - Immutability mode etkinleştirme ve uyarı" width="799" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VM isim deseni olarak &lt;code&gt;core*&lt;/code&gt; giriliyor. Bu desenle üç VM eşleşiyor: &lt;code&gt;core-a&lt;/code&gt;, &lt;code&gt;core-a-clone&lt;/code&gt; ve &lt;code&gt;core-c&lt;/code&gt;.&lt;br&gt;
Immutable Core Apps&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiujboefye8xy27fonl4r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiujboefye8xy27fonl4r.png" alt="VM name pattern - core* deseni ve eşleşen VM'ler" width="799" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not: Manuel burada ilginç bir detay veriyor; &lt;code&gt;core-a-clone&lt;/code&gt; isim deseni ile eşleşse de (çünkü "core" ile başlıyor), daha önce gördüğümüz gibi linked-clone VM'ler zaten protection group'lardan otomatik filtreleniyor. Yani isim eşleşmesi, filtrelemenin önüne geçmiyor.&lt;/p&gt;

&lt;p&gt;Snapshot zamanlaması olarak her 1 günde bir snapshot, 3 aylık saklama süresi belirleniyor. NEXT, sonra CREATE.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fch90slbhbdti0u63f4w6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fch90slbhbdti0u63f4w6.png" alt="Snapshot schedule - günlük snapshot, 3 aylık saklama" width="799" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Immutability'nin Etkisini Doğrulamak
&lt;/h3&gt;

&lt;p&gt;Yeni oluşturulan protection group'un üç nokta menüsüne bakıldığında, Edit, Pause ve Delete seçeneklerinin gri renkte (devre dışı) olduğu görülüyor. Bu yetenekler immutable protection group'lar için izin verilmiyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8mp3bez4fhcsxhygtzqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8mp3bez4fhcsxhygtzqp.png" alt="Protection Groups listesi - Immutable Core Apps için devre dışı Edit/Pause/Delete" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dinamik isimlendirme kullanıldığı için, "core" ile başlayan yeni VM'ler vSAN datastore'lara eklendiğinde otomatik olarak korunacak ve snapshot'ları, VM'ler daha sonra silinse bile 3 ay boyunca saklanacak.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Modül 7, serinin kapanışı için iyi bir seçim olmuş; çünkü burada gördüğümüz her şey, önceki altı modülde öğrendiğimiz kavramların üzerine inşa ediliyor. Protection group'lar SPBM'in mantığını (politika tanımla, sistem uygula) hatırlatıyor. Replication pairs, Modül 5'teki cluster-arası ilişkileri andırıyor. %70 doluluk eşiği, Modül 1'deki Reserved Capacity mantığıyla aynı prensibi paylaşıyor.&lt;/p&gt;

&lt;p&gt;Benim için en dikkat çekici üç nokta şunlardı:&lt;/p&gt;

&lt;p&gt;Birincisi, dinamik isim deseninin gücü. Bir VM isim kuralı tanımlamak, gelecekteki tüm uyumlu VM'lerin otomatik korunmasını sağlıyor; bu, "her yeni VM için manuel yapılandırma" yükünü ortadan kaldıran zarif bir tasarım. Aynı zamanda bunun disiplinli bir isimlendirme kuralı gerektirdiğini de görmek gerekiyor; "sales-" ile başlamayan bir satış VM'i sessizce korumasız kalabilir.&lt;/p&gt;

&lt;p&gt;İkincisi, restore işleminin kendisinin bir snapshot bırakması. Bu, "geri dönülemez işlem" korkusunu azaltan küçük ama önemli bir güvenlik katmanı.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, Immutable Protection Groups. Bu özellik, teknik bir yetenekten çok bir tehdit modeline cevap veriyor: eğer bir saldırgan (ya da yanlışlıkla yetkili bir kullanıcı) sisteme erişim kazanırsa, koruma planının kendisi saldırı yüzeyi olmamalı. Bu, "backup'ınız varsa güvendesiniz" varsayımının yeterli olmadığı, backup'ın kendisinin de korunması gerektiği fikrinin somut bir uygulaması.&lt;/p&gt;




&lt;h2&gt;
  
  
  Seri Üzerine Kapanış Notu
&lt;/h2&gt;

&lt;p&gt;Yedi modül boyunca vSAN'ı SPBM'den başlayıp izleme, şifreleme, stretched cluster, storage cluster ayrımı, file services ve şimdi data protection'a kadar bir yolculuk olarak takip ettim. HOL formatının en büyük avantajı, hiçbir şeyi bozma korkusu olmadan bu kadar geniş bir yüzeyi tek bir ortamda gezebilmekti.&lt;/p&gt;

&lt;p&gt;Ama başta da söylediğim gibi, bunun sınırlarını da net tutmak istiyorum: gerçek bir production ortamında bu kararların her biri, burada göremediğimiz baskılarla (bütçe, mevcut donanım, ekip deneyimi, değişim yönetimi süreçleri) birlikte alınıyor. Bu seri, o kararları alacak kişi olmaya değil, o kararların neye dayandığını anlayacak bir zemine sahip olmaya yardımcı olmayı amaçladı.&lt;/p&gt;

&lt;p&gt;Serinin geri kalanını okuyanlara teşekkürler. Bir sonraki öğrenme serisinde görüşmek üzere.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri VMware HOL ortamı (HOL-2634-01-VCF-L) üzerinden yürütülmektedir. Buradaki gözlemler lab bağlamında değerlendirilmeli, production ortamı kararları için mutlaka resmi VMware dokümantasyonu ve deneyimli mühendisler referans alınmalıdır.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>vSAN File Services: Datastore Üzerinde Dosya Paylaşımı (Modül 6)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Sun, 19 Jul 2026 12:58:34 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/vsan-file-services-datastore-uzerinde-dosya-paylasimi-modul-6-2m70</link>
      <guid>https://dev.to/hakanbaban53/vsan-file-services-datastore-uzerinde-dosya-paylasimi-modul-6-2m70</guid>
      <description>&lt;p&gt;Beş haftadır vSAN'ın blok depolama tarafını (VMDK'lar, storage policy'ler, cluster mimarileri) işledim. Modül 6 farklı bir katmana giriyor: File Services. Bu modülde vSAN datastore üzerinde NFS ve SMB paylaşımları oluşturmayı, bunları izlemeyi ve gerçek bir client'tan mount edip dosya yazmayı görüyoruz.&lt;/p&gt;

&lt;p&gt;Bu konu ilk bakışta "neden vSAN bir NAS gibi davransın ki" sorusunu akla getirebiliyor. Ama mantığını anlayınca aslında oldukça pratik bir kullanım alanı ortaya çıkıyor: zaten var olan vSAN altyapısını, ayrı bir dosya sunucusu kurmadan, dosya paylaşımı ihtiyaçları için de kullanabilmek.&lt;/p&gt;




&lt;h2&gt;
  
  
  vSAN File Services Nedir?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3pmnqae3cpyr3kr6t39u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3pmnqae3cpyr3kr6t39u.png" alt="Dağıtılmış depolama mimarisi diyagramı" width="800" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vSAN File Services, vSAN datastore üzerinde dosya paylaşımları (file share) oluşturmayı sağlıyor; bu paylaşımlara client workstation'lar veya VM'ler erişebiliyor. Desteklenen protokoller: SMB, NFSv3 ve NFSv4.1.&lt;/p&gt;

&lt;p&gt;Mimarinin altında vSAN Distributed File System (vDFS) yatıyor. Bu, vSAN nesnelerini birleştirerek ölçeklenebilir bir dosya sistemi sağlıyor. File share'ler, mevcut Storage Policy Based Management mekanizmasına entegre; yani her paylaşıma, VMDK'lara atadığımız gibi bir storage policy atanabiliyor.&lt;/p&gt;

&lt;p&gt;Teknik olarak dikkat çeken bir nokta: File Service etkinleştirildiğinde vSAN, cluster için tek bir vDFS dağıtık dosya sistemi oluşturuyor ve bunu her host üzerinde container'lar halinde çalıştırıyor. Bu container'lar hypervisor ile sıkı entegre, dosya servislerini sağlamanın birincil aracı olarak çalışıyorlar.&lt;/p&gt;

&lt;h3&gt;
  
  
  IP Havuzu Mantığı
&lt;/h3&gt;

&lt;p&gt;File Service etkinleştirilirken statik bir IP adres havuzu tanımlanması gerekiyor. Bu havuzdaki adreslerden biri "primary IP" olarak atanıyor; SMB ve NFSv4.1 referral mekanizması sayesinde, tüm paylaşımlara bu tek IP üzerinden erişilebiliyor.&lt;/p&gt;

&lt;p&gt;Her IP adresi için ayrı bir file server başlatılıyor, ama paylaşımlar bu sunucular arasında dengeli dağıtılıyor. İdeal performans için IP adres sayısının, vSAN cluster'ındaki host sayısına eşit olması öneriliyor. Bu IP'lerin DNS'te forward ve reverse lookup kayıtlarının olması da gerekiyor.&lt;/p&gt;

&lt;p&gt;Bu detayı okurken şunu düşündüm: bu, tipik bir load-balanced servis mimarisi. Tek bir giriş noktası (primary IP) sunarken arkada birden fazla worker'a (file server) dağıtım yapması, kullanıcı deneyimini basitleştirirken ölçeklenebilirliği koruyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bir Kısıtlama: Stretched Cluster Desteklenmiyor
&lt;/h3&gt;

&lt;p&gt;Manuel'de net bir uyarı var: File Services şu anda vSAN Stretched Cluster üzerinde desteklenmiyor, sadece normal (standart) bir vSAN cluster üzerinde etkinleştirilebiliyor. Bu, Modül 4'te öğrendiğimiz stretched cluster mimarisiyle File Services'i aynı cluster'da birleştiremeyeceğimiz anlamına geliyor; bu iki özelliği aynı anda isteyen bir tasarım için ayrı cluster'lar planlamak gerekecek.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ağ Gereksinimleri
&lt;/h2&gt;

&lt;p&gt;File Services'i etkinleştirmeden önce birkaç ağ gereksinimi karşılanmalı:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dosya paylaşımlarına tek erişim noktası olacak statik IP adresleri; en iyi performans için host sayısı kadar.&lt;/li&gt;
&lt;li&gt;Bu IP'lerin DNS'te forward ve reverse lookup zone'larında kayıtlı olması.&lt;/li&gt;
&lt;li&gt;Tüm statik IP'lerin aynı subnet'te olması.&lt;/li&gt;
&lt;li&gt;DVS (Distributed Virtual Switch) sürüm 6.6.0 veya üzeri; File Service için ayrı bir dedicated port group oluşturulması.&lt;/li&gt;
&lt;li&gt;Promiscuous Mode ve Forged Transmits'in, File Services etkinleştirme süreci sırasında otomatik olarak açılması. NSX tabanlı ağlar kullanılıyorsa bu ayarların NSX admin konsolundan da yapılması gerekiyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;HOL'da File Services zaten önceden etkinleştirilmiş durumda; biz bu adımları uygulamıyoruz, ama gerçek bir kurulumda networking hazırlığının en az storage cluster networking'i kadar dikkat gerektirdiğini not etmek istedim (Modül 5'teki front-end/back-end ayrımına benzer bir dikkat seviyesi burada da geçerli).&lt;/p&gt;




&lt;h2&gt;
  
  
  File Services'in Etkin Olduğunu Doğrulamak
&lt;/h2&gt;

&lt;p&gt;Site B vCenter'a giriş yapılıyor (&lt;code&gt;vc-mgmt-b&lt;/code&gt;). Doğrulama adımları:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dc-b &amp;gt; vsan-storage-cluster-01b &amp;gt; Configure &amp;gt; vSAN &amp;gt; Services&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Aşağı kaydırılınca File Service bölümünün "Enabled" durumda olduğu görülüyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flnvgivqsi83bozwe1p54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flnvgivqsi83bozwe1p54.png" alt="vSAN Services - File Service bölümü, Enabled durumu" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu bölümde file service'in ağ detayları da görünüyor. Sol panelde &lt;code&gt;vsan-storage-cluster-01b&lt;/code&gt; altında vSAN File Service node'larının oluşturulduğu görülüyor; her vSAN node için bir tane. Her File Service VM'i (FSVM) en fazla 50 paylaşım destekliyor, cluster başına toplam paylaşım limiti 500 (bunun içinde en fazla 100 tanesi SMB paylaşımı olabiliyor).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi4lcua4f82mylz9lmwmy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi4lcua4f82mylz9lmwmy.png" alt="File Service Nodes listesi - her host için bir FSVM" width="344" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu limitleri görünce aklıma şu geldi: 500 paylaşım/cluster gibi bir üst sınır, küçük-orta ölçekli dosya paylaşımı ihtiyaçları için gayet yeterli, ama büyük bir dosya sunucusu konsolidasyonu planlıyorsanız bu sınırı erkenden hesaba katmak gerekiyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  File Server Health Check
&lt;/h2&gt;

&lt;p&gt;File Service'in sağlığını kontrol etmek için Skyline Health'e dönüyoruz, artık tanıdık bir akış:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Monitor &amp;gt; vSAN &amp;gt; Skyline Health &amp;gt; Health findings &amp;gt; ALL &amp;gt; Category filtresi &amp;gt; File Service&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1zsbh8yo0l3sq6tp8xh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff1zsbh8yo0l3sq6tp8xh.png" alt="Skyline Health - File Service kategorisi filtrelenmiş görünüm" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"File Server Health" bulgusunun üç nokta menüsünden "View Current Result" seçiliyor. Bu ekran, File Servers Service'e katkı veren host'ları, her file server node'unda çalışan servisleri ve atanmış IP adreslerini detaylı olarak gösteriyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdnc41ih5cvoame24e8gn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdnc41ih5cvoame24e8gn.png" alt="File Server Health - host bazlı servis ve IP detayları" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu adım, Modül 3'teki (şifreleme) health check akışıyla neredeyse birebir aynı desende ilerliyor: kategori filtrele, bulguyu seç, View Current Result ile detaya in. vSAN'ın health check mimarisinin tutarlılığı, farklı özellikler için bile aynı zihinsel modeli kullanmanıza izin veriyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  NFS Paylaşımı Oluşturmak
&lt;/h2&gt;

&lt;p&gt;Paylaşım isimlendirmesi için birkaç kural var, not almaya değer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ASCII olmayan karakterler içeren kullanıcı adları paylaşım verisine erişim için kullanılabiliyor.&lt;/li&gt;
&lt;li&gt;Paylaşım isimleri sadece İngilizce karakterler içerebiliyor.&lt;/li&gt;
&lt;li&gt;Salt NFSv4 tipi paylaşımlarda dosya ve dizin isimleri herhangi bir UTF-8 uyumlu karakter içerebiliyor.&lt;/li&gt;
&lt;li&gt;Salt NFSv3 ve NFSv3+NFSv4 paylaşımlarında dosya ve dizin isimleri sadece ASCII uyumlu olabiliyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bu kısıtlama listesi ilk okuyuşta teknik bir detay gibi görünüyor, ama gerçek bir ortamda özellikle Türkçe karakterler (ç, ş, ğ, ı, ö, ü) içeren dosya/dizin isimleriyle çalışırken, protokol seçiminin (salt NFSv4 mü, yoksa NFSv3 uyumlu mu) doğrudan bir etkisi olacağını gösteriyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Oluşturma Adımları
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;vsan-storage-cluster-01b &amp;gt; Configure &amp;gt; vSAN &amp;gt; File Shares &amp;gt; ADD&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;General sayfası:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;İsim: &lt;code&gt;VMSharesNFS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Protokol: NFS, hem NFS 4.1 hem NFS 3 versiyonları seçili&lt;/li&gt;
&lt;li&gt;Storage Policy: &lt;code&gt;vsan-storage-cluster-01b - Optimal Datastore Default Policy - RAID5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Share warning threshold 5 GB, share hard quota 10 GB olarak etkinleştiriliyor&lt;/li&gt;
&lt;li&gt;NEXT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq6d0u21zru1noa5ih53g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq6d0u21zru1noa5ih53g.png" alt="Create a File Share - General sayfası, isim ve protokol seçimi" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Net access control sayfası:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"Allow access from any IP" seçiliyor&lt;/li&gt;
&lt;li&gt;NEXT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0j10ptkmtcjorrc8f9zt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0j10ptkmtcjorrc8f9zt.png" alt="Net access control sayfası - IP erişim ayarı" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review sayfası:&lt;/strong&gt; Girilen bilgiler gözden geçirilip FINISH ile paylaşım oluşturuluyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg6tul9atvx54308zje49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg6tul9atvx54308zje49.png" alt="Review sayfası - paylaşım özeti" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada dikkatimi çeken şey, storage policy'nin ve quota ayarlarının (warning threshold, hard quota) aynı wizard içinde birlikte tanımlanması. Bu, bir dosya paylaşımının sadece "nerede depolanacağını" değil, aynı zamanda "ne kadar büyüyebileceğini" de aynı yerde yönetmenizi sağlıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Oluşturulan Paylaşımı Görüntülemek
&lt;/h3&gt;

&lt;p&gt;Paylaşım listesinde &lt;code&gt;VMSharesNFS&lt;/code&gt;, atanmış storage policy, kullanım/kota ve gerçek kullanım bilgileriyle görünüyor. "Show or Hide Columns" ile Hard Quota ve Warning Threshold sütunları da eklenebiliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fasd4k3n31kpls5wrthsf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fasd4k3n31kpls5wrthsf.png" alt="File Shares listesi - VMSharesNFS ve kota bilgileri" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Paylaşımı Başka Sistemlere Mount Etmek
&lt;/h2&gt;

&lt;p&gt;Bu bölüm, HOL'un daha "elle dokunulan" kısımlarından biri; gerçekten bir Linux terminalinden mount komutu çalıştırıp dosya yazıyoruz.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bağlantı Yolunu Kopyalamak
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;VMShareNFS&lt;/code&gt; seçilip "COPY PATH" dropdown'ından NFS 3 veya NFS 4.1 seçilebiliyor. NFS 4.1 seçildiğinde örnek bağlantı dizesi şöyle görünüyor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NFSv3: &lt;code&gt;vsan-fs-06a.vcf.sddc.lab:/VMSharesNFS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;NFSv4.1: &lt;code&gt;vsan-fs-01a.vcf.sddc.lab:/vsanfs/VMSharesNFS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not: NFSv4.1 referral mekanizmasıyla mount etmek için, mount path'inde kök paylaşımı (&lt;code&gt;/vsanfs&lt;/code&gt;) dahil edilmesi gerekiyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6labvyw95jn5s4ecby5s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6labvyw95jn5s4ecby5s.png" alt="Copy Path menüsü - NFS 3 ve NFS 4.1 seçenekleri" width="311" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Terminal Üzerinden Mount Etmek
&lt;/h3&gt;

&lt;p&gt;Terminal açılıp şu komut çalıştırılıyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mount vsan-fs-07b.site-b.vcf.lab:/VMSharesNFS /mnt/newfs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Şifre istendiğinde &lt;code&gt;VMware123!VMware123!&lt;/code&gt; giriliyor. Mount'un başarılı olduğu şu komutla doğrulanıyor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mount | &lt;span class="nb"&gt;grep&lt;/span&gt; /mnt/newfs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manuel'de bir not var: NFS 4.1 aynı zamanda varsayılan mount versiyonu; eğer protokol belirtilmezse, client sunucuyla en yüksek uyumlu protokolü otomatik müzakere ediyor, vSAN 9 Native File Services için bu NFS v4.1.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dosya Yazıp Okumak
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; /mnt/newfs
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"NFS 4 Share"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; newfs.txt
&lt;span class="nb"&gt;cat &lt;/span&gt;newfs.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu üç komutla paylaşıma bir dosya yazılıyor ve tekrar okunarak doğrulanıyor.&lt;/p&gt;

&lt;p&gt;Bu basit test, aslında modülün en somut kanıtı: vSAN üzerinde oluşturduğumuz bir "storage policy'ye bağlı nesne", gerçek bir Linux client'tan standart NFS protokolüyle erişilebilir, yazılabilir bir dosya sistemi olarak çalışıyor. Bunun arkasında vDFS, container'lar, IP havuzu gibi karmaşık bir mimari olsa da, client tarafında deneyim sıradan bir NFS mount'undan farksız.&lt;/p&gt;




&lt;h2&gt;
  
  
  vSAN Nesne Görünümü ve Placement Details
&lt;/h2&gt;

&lt;p&gt;Paylaşımın vSAN'ın kendi nesne yapısına nasıl entegre olduğunu görmek için:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsan-storage-cluster-01b &amp;gt; Monitor &amp;gt; vSAN &amp;gt; Virtual Objects&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;VMSharesNFS&lt;/code&gt; seçilip "VIEW PLACEMENT DETAILS" tıklanıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffebegklotu7540poeab2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffebegklotu7540poeab2.png" alt="Virtual Objects - VMSharesNFS seçili görünüm" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu ekran, dosya paylaşımının bileşenlerinin hangi host'larda ve hangi fiziksel storage cihazlarında yerleştiğini gösteriyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffounfll5lpxvltp6zxpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffounfll5lpxvltp6zxpu.png" alt="Placement Details - VMSharesNFS bileşen dağılımı" width="800" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu, Modül 1'de bir VM'in VMDK'sı için gördüğümüz Placement Details ekranıyla aynı arayüz, aynı mantık. Bir dosya paylaşımının da tıpkı bir sanal disk gibi vSAN nesnesi olarak ele alınması ve aynı görselleştirme aracıyla incelenebilmesi, vSAN'ın "her şey bir nesne" felsefesinin tutarlılığını gösteriyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  File Service Health'i Tekrar Kontrol Etmek
&lt;/h2&gt;

&lt;p&gt;Yeni paylaşım oluşturulduktan sonra Skyline Health'e dönülüp RETEST yapılıyor (health check zaten periyodik çalışıyor, ama yeni bir servis eklendiği için manuel tetiklemek öneriliyor).&lt;/p&gt;

&lt;p&gt;Filtre yine File Service kategorisine ayarlanıyor. Bu sefer "Share Health" bulgusunun üç nokta menüsünden "View Current Result" seçiliyor.&lt;/p&gt;

&lt;p&gt;Sonuç, oluşturduğumuz paylaşımın sağlıklı olduğunu gösteriyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd9tjliqnxidngs7eoyz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd9tjliqnxidngs7eoyz0.png" alt="Share Health sonucu - Healthy durumu" width="798" height="228"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Performans ve Kapasite İzleme
&lt;/h2&gt;

&lt;p&gt;File Services için de, önceki modüllerde gördüğümüz izleme mantığı geçerli.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performans:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsan-storage-cluster-01b &amp;gt; Monitor &amp;gt; vSAN &amp;gt; Performance &amp;gt; FILE SHARE &amp;gt; VMSharesNFS&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Burada file service için toplanan çeşitli metrikler görülüyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89rx7tt0p9rutfmibu8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F89rx7tt0p9rutfmibu8o.png" alt="Performance - FILE SHARE sekmesi, VMSharesNFS metrikleri" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kapasite:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Monitor &amp;gt; vSAN &amp;gt; Capacity&lt;/code&gt;, aşağı kaydırılıp "Usage breakdown" bölümünde "User Data" genişletilerek File Shares kapasite kullanımı görülüyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdix0scg7ltyfygw41lfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdix0scg7ltyfygw41lfd.png" alt="Capacity - Usage breakdown, File Shares kalemi" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu iki ekran, Modül 2'de öğrendiğimiz izleme çerçevesinin (Skyline Health, Kapasite, Performans) File Services için de birebir geçerli olduğunu gösteriyor. Yeni bir özellik öğrenirken sıfırdan bir izleme mantığı öğrenmek yerine, var olan çerçeveyi yeni bir nesne tipine uygulamak yeterli oluyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Bu modül, vSAN'ın "sadece blok depolama" olmadığını gösteren iyi bir örnekti. File Services, temelde aynı vSAN altyapısını (aynı disk grupları, aynı SPBM mekanizması, aynı health check çerçevesi) kullanarak farklı bir erişim modeli (dosya paylaşımı) sunuyor.&lt;/p&gt;

&lt;p&gt;Benim için en dikkat çekici üç nokta şunlardı:&lt;/p&gt;

&lt;p&gt;Birincisi, IP havuzu ve primary IP mekanizmasının load-balancing mantığıyla çalışması. Host sayısı kadar IP tanımlayıp bunları file server'lara dağıtmak, basit ama etkili bir ölçeklenebilirlik yaklaşımı.&lt;/p&gt;

&lt;p&gt;İkincisi, paylaşım isimlendirme kurallarındaki ASCII/UTF-8 ayrımı. Küçük bir detay gibi görünüyor ama gerçek bir ortamda, özellikle Türkçe gibi ASCII-dışı karakterler kullanan dil ortamlarında, protokol seçiminin doğrudan pratik bir etkisi oluyor.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, tüm bu modül boyunca "yeni bir şey öğreniyormuşum" hissinden çok, "tanıdık araçları yeni bir nesne tipine uyguluyormuşum" hissi baskındı. Placement Details, Skyline Health akışı, Performance ve Capacity sekmeleri; hepsi önceki modüllerden tanıdık. Bu tutarlılık, vSAN'ın farklı özelliklerini öğrenirken kümülatif bir öğrenme eğrisi sağlıyor: her yeni modül, sıfırdan başlamak yerine önceki modüllerin üzerine inşa ediyor.&lt;/p&gt;

&lt;p&gt;Bir sonraki hafta &lt;strong&gt;son&lt;/strong&gt; modül olan Modül 7'ye geçiyorum: Data Protection.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri VMware HOL ortamı (HOL-2634-01-VCF-L) üzerinden yürütülmektedir. Buradaki gözlemler lab bağlamında değerlendirilmeli, production ortamı kararları için mutlaka resmi VMware dokümantasyonu ve deneyimli mühendisler referans alınmalıdır.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vmware</category>
    </item>
    <item>
      <title>vSAN Storage Cluster: Compute'u Storage'dan Ayırmak (Modül 5)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Sun, 12 Jul 2026 10:51:18 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/vsan-storage-cluster-computeu-storagedan-ayirmak-modul-5-12pi</link>
      <guid>https://dev.to/hakanbaban53/vsan-storage-cluster-computeu-storagedan-ayirmak-modul-5-12pi</guid>
      <description>&lt;p&gt;Dört haftadır Site A üzerinde çalışıyordum: SPBM, izleme, şifreleme, stretched cluster. Modül 5 ile birlikte ilk kez Site B'ye geçiyorum ve konu da farklı bir yöne kırılıyor: vSAN Storage Cluster.&lt;/p&gt;

&lt;p&gt;Bu modül, önceki dördünden kavramsal olarak ayrı bir yerde duruyor. Şimdiye kadar gördüğümüz her şey HCI (Hyper-Converged Infrastructure) mantığıyla çalışıyordu; yani her host hem compute hem storage sağlıyordu. Storage Cluster ise bu ikisini birbirinden ayırıyor. Bunun neden var olduğunu ve HOL'da nasıl göründüğünü aktarayım.&lt;/p&gt;




&lt;h2&gt;
  
  
  vSAN Storage Cluster Nedir?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtq7fwzdt4g6858wu4e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgtq7fwzdt4g6858wu4e1.png" alt="vSAN Storage Cluster Overview" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vSAN Storage Cluster, eski adıyla vSAN Max, vSphere cluster'ları için dağıtık, scale-out bir depolama sistemi. vSAN ESA tarafından güç alıyor, yani ESA'nın sunduğu tüm yeteneklere sahip, ama sadece depolama sağlayan bir cluster olarak çalışıyor.&lt;/p&gt;

&lt;p&gt;Buradaki kritik ayrım şu: Normal vSAN'da (HCI modelinde) bir host hem VM'leri çalıştırır hem de kendi diskini vSAN datastore'a katkı verir. Storage Cluster modelinde ise bazı cluster'lar sadece depolama sağlıyor (compute çalıştırmıyor), bazı cluster'lar ise sadece compute sağlayıp bu depolamayı uzaktan tüketiyor.&lt;/p&gt;

&lt;p&gt;Bu, disaggregation (ayrıştırma) dediğimiz bir mimari yaklaşım. Compute ve storage kaynaklarını ayrı ayrı ölçeklendirebiliyorsunuz; storage ihtiyacınız artınca sadece storage cluster'ı büyütüyorsunuz, compute cluster'a dokunmadan.&lt;/p&gt;

&lt;p&gt;Cross-cluster iletişim için vSAN'ın kendi native protokolü ve data path'i kullanılıyor. Bu, yönetim deneyimini koruyor ve dağıtık bir depolama sistemi için mümkün olan en yüksek performans ve esnekliği sağlıyor iddiasında.&lt;/p&gt;




&lt;h2&gt;
  
  
  HOL Ortamındaki İki Cluster
&lt;/h2&gt;

&lt;p&gt;Site B'de iki cluster önceden hazır geliyor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;vsan-storage-cluster-01b&lt;/code&gt;&lt;/strong&gt;: Depolama sağlayan cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;vsan-client-cluster-01b&lt;/code&gt;&lt;/strong&gt;: Bu depolamayı tüketen compute cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bu ayrımı doğrulamak için ilk yapılan şey, her iki cluster'ın Configure sekmesinden &lt;code&gt;vSAN &amp;gt; Services&lt;/code&gt; altındaki "Cluster type" alanına bakmak.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsan-storage-cluster-01b&lt;/code&gt; için Cluster type "vSAN Storage Cluster" olarak görünüyor; bu cluster diğer compute cluster'lara depolama sağlamaya adanmış.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F77pjedwn6s9523oj1c67.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F77pjedwn6s9523oj1c67.png" alt="vsan-storage-cluster-01b - Services ekranı, Cluster type: vSAN Storage Cluster" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsan-client-cluster-01b&lt;/code&gt; için ise Cluster type "vSAN Compute Cluster" olarak görünüyor; bu cluster diğer vSAN storage cluster'ların depolamasını tüketmeye adanmış.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8lrt89xm35to3srku29d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8lrt89xm35to3srku29d.png" alt="vsan-client-cluster-01b - Services ekranı, Cluster type: vSAN Compute Cluster" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu iki etiketin ayrı ayrı görünmesi bana önemli geldi. Sistem, bir cluster'ın rolünü GUI seviyesinde açıkça belirtiyor; "bu cluster ne için var" sorusuna dolaşmadan cevap veriyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mount Edilmiş Datastore'u Görmek
&lt;/h2&gt;

&lt;p&gt;Compute cluster'ın, storage cluster'daki datastore'u gerçekten kullandığını doğrulamak için:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vsan-client-cluster-01b &amp;gt; Configure &amp;gt; vSAN &amp;gt; Datastore Management&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Burada &lt;code&gt;vsan_SC_Datastore&lt;/code&gt; adlı datastore'un, &lt;code&gt;vsan-storage-cluster-01b&lt;/code&gt; cluster'ında bulunduğu ve compute cluster tarafından mount edildiği görülüyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff326xmydoxr4hd05lj4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff326xmydoxr4hd05lj4p.png" alt="Datastore Management - vsan_SC_Datastore mount durumu" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu ekran, HCI modelindeki "VM burada, disk de burada" basitliğinden farklı bir gerçekliği gösteriyor: VM'in compute'u bir cluster'da, verinin fiziksel olarak bulunduğu yer başka bir cluster'da.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ağ Trafiği Ayrımı: Front-End ve Back-End
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo17msu85wsnnc8wqvfqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo17msu85wsnnc8wqvfqw.png" alt="Ağ Trafiği Ayrımı" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu modülün bence en önemli teknik detayı burada. VCF 9.0 ile vSAN Storage Cluster'lara yeni bir yapılandırma seçeneği geldi: depolama performansını artıran, ağ trafiği izolasyonunu ve güvenliği iyileştiren bir ayrım.&lt;/p&gt;

&lt;p&gt;İki tür trafik tanımlanıyor:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guest VM I/O (front-end trafik):&lt;/strong&gt; Guest VM'e giden/gelen, vSAN datastore'a erişen trafik.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vSAN I/O (back-end trafik):&lt;/strong&gt; vSAN datastore'daki node'lar arasında akan trafik; yani vSAN'ın kendi iç senkronizasyon ve replikasyon trafiği.&lt;/p&gt;

&lt;p&gt;VCF 9.0 için vSAN, bu iki trafiği ayrı VMkernel portları üzerinden ayırma yeteneği getiriyor. Bu ayrım, Modül 2'de gördüğümüz cluster seviyesindeki front-end/back-end trafik ayrımıyla kavramsal olarak aynı fikri paylaşıyor, ama burada fiziksel port seviyesinde uygulanıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storage Cluster Node'unun VMkernel Arayüzleri
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;esx-05b.site-b.vcf.lab&lt;/code&gt; üzerinde iki vSAN'a özgü VMkernel portu inceleniyor:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vmk2:&lt;/strong&gt; vSAN servisi için etkin. Storage Cluster bağlamında bu port, storage cluster node'ları arasındaki vSAN I/O'dan (back-end trafik) sorumlu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmuu64gnb22vbrhp3i1vo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmuu64gnb22vbrhp3i1vo.png" alt="esx-05b VMkernel Adapters - vmk2, vSAN servisi etkin" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vmk3:&lt;/strong&gt; vSAN Storage Cluster Client servisi için etkin. Bu port, storage cluster node'larının, client cluster'daki vSAN VMkernel portlarıyla iletişim kurup Guest VM I/O'yu (front-end trafik) taşımasından sorumlu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwm112nyvhn1etmjlctvt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwm112nyvhn1etmjlctvt.png" alt="esx-05b VMkernel Adapters - vmk3, vSAN Storage Cluster Client servisi etkin" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Compute Cluster Node'unun VMkernel Arayüzü
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;esx-09b.site-b.vcf.lab&lt;/code&gt; üzerinde ise tek bir vSAN'a özgü VMkernel portu var:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vmk2:&lt;/strong&gt; vSAN servisi için etkin. Compute Cluster bağlamında bu port, storage cluster node'larındaki vSAN Storage Cluster Client portlarıyla iletişim kurup Guest VM I/O'yu (front-end trafik) taşıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ghzrqolkrcqk09bklhv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ghzrqolkrcqk09bklhv.png" alt="esx-09b VMkernel Adapters - vmk2, vSAN servisi etkin" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada dikkatimi çeken şey, storage cluster node'unda iki ayrı port varken (biri back-end, biri front-end için), compute cluster node'unda sadece bir port olması. Mantıklı: compute cluster kendi verisini tutmuyor, sadece storage cluster'a Guest VM I/O gönderiyor; kendi içinde bir back-end senkronizasyon trafiğine ihtiyacı yok.&lt;/p&gt;

&lt;p&gt;Bu ayrım, gerçek bir ortamda ağ tasarımı yaparken önemli bir referans noktası. Storage cluster tarafında iki ayrı VMkernel portu (ve muhtemelen iki ayrı fiziksel NIC veya VLAN) planlamak, front-end ve back-end trafiğinin birbirini etkilememesi için gerekli.&lt;/p&gt;




&lt;h2&gt;
  
  
  Compute Cluster'a VM Deploy Etmek
&lt;/h2&gt;

&lt;p&gt;Bu bölümde &lt;code&gt;core-b&lt;/code&gt; VM'i klonlanarak &lt;code&gt;vsan-client-cluster-01b&lt;/code&gt; compute cluster'ına deploy ediliyor. Manuel'de vurgulanan önemli nokta şu: bu süreç, normal bir vSAN HCI cluster'ına VM deploy etmekle aynı. Tek fark, compute resource olarak compute cluster'ı, datastore olarak da storage cluster'daki vSAN datastore'unu seçmeniz.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adımlar
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;core-b&lt;/code&gt; üzerine sağ tık → Clone → Clone to Virtual Machine&lt;/li&gt;
&lt;li&gt;İsim: &lt;code&gt;clone-vm-b&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Compute resource: &lt;code&gt;vsan-client-cluster-01b&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;VM Storage Policy: &lt;code&gt;cluster-esa-01b - Optimal Datastore Default Policy - RAID1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Datastore: &lt;code&gt;vsan_SC_Datastore&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb8a9ou1zv0s2i7i5mio0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb8a9ou1zv0s2i7i5mio0.png" alt="Clone wizard - compute resource ve storage policy seçimi" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu akış, Modül 1'de &lt;code&gt;core-a&lt;/code&gt; VM'ini klonlarken gördüğümüz sürecin neredeyse birebir aynısı. Aradaki fark sadece hangi cluster'ın compute, hangi datastore'un hedef olarak seçildiği; SPBM mekanizması, wizard akışı, hepsi tanıdık.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sonucu Doğrulamak
&lt;/h3&gt;

&lt;p&gt;Klon tamamlandıktan sonra &lt;code&gt;clone-vm-b &amp;gt; Summary &amp;gt; Related Objects&lt;/code&gt; bölümünde şunlar görülüyor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VM, &lt;code&gt;vsan-client-cluster-01b&lt;/code&gt; compute cluster'ında bulunuyor.&lt;/li&gt;
&lt;li&gt;VM'in verisi ise &lt;code&gt;vsan_SC_Datastore&lt;/code&gt; datastore'unda duruyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb825mp0e1ehkjpc7yaza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb825mp0e1ehkjpc7yaza.png" alt="clone-vm-b Related Objects - compute cluster ve datastore ilişkisi" width="799" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu iki bilginin ayrı ayrı, ayrı nesneler olarak görünmesi, disaggregated mimarinin özünü gösteriyor: VM'in "nerede çalıştığı" ile verisinin "nerede durduğu" artık aynı host'a bağlı değil.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Bu modül kısa ama kavramsal olarak önceki dördünden farklı bir zihniyet gerektiriyor. HCI modelinde "compute ve storage aynı host'ta" varsayımı o kadar yerleşik ki, bunu ayırmanın ne gibi bir esneklik getirdiğini görmek için ayrı bir cluster çiftini incelemek gerekiyordu.&lt;/p&gt;

&lt;p&gt;Benim için en dikkat çekici iki nokta şunlardı:&lt;/p&gt;

&lt;p&gt;Birincisi, front-end/back-end trafik ayrımının VMkernel port seviyesinde somutlaşması. Modül 2'de bu ayrımı sadece bir monitoring sekmesi (Backend vs VM sekmeleri) olarak görmüştüm; burada aynı ayrımın fiziksel ağ tasarımına nasıl yansıdığını görmek, kavramı daha somut hale getirdi. Storage cluster node'unda iki ayrı port, compute cluster node'unda tek port olması, hangi tarafın hangi trafiği taşıdığını networking seviyesinde de ayırt edilebilir kılıyor.&lt;/p&gt;

&lt;p&gt;İkincisi, VM deploy etme sürecinin HCI'dakiyle neredeyse aynı olması. Bu bana şunu gösterdi: vSAN Storage Cluster, kullanıcı deneyimi açısından büyük bir öğrenme eğrisi getirmiyor; asıl fark mimari seviyede, admin'in cluster'ları nasıl tasarladığında. Bir VM deploy eden birisi için "bu storage cluster'dan mı geliyor, yoksa HCI'dan mı" ayrımı büyük ölçüde görünmez kalıyor, ki bu da tasarımın amaçladığı şey.&lt;/p&gt;

&lt;p&gt;Gerçek sahada bu mimariyi ne zaman tercih edeceğim sorusunu düşününce, akla gelen ilk senaryo şu: storage ve compute ihtiyaçlarının farklı oranlarda büyüdüğü ortamlar. Compute-yoğun ama storage-hafif workload'lar için (ya da tam tersi) ayrı ayrı ölçeklendirme yapabilmek, her host'a hem compute hem storage eklemek zorunda kalmaktan daha esnek bir yaklaşım olabilir. Ama bunun getirdiği ek ağ tasarımı karmaşıklığını (front-end/back-end ayrımı, ek VMkernel portları) da hesaba katmak gerekiyor.&lt;/p&gt;

&lt;p&gt;Bir sonraki hafta Modül 6'ya geçiyorum.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri VMware HOL ortamı (HOL-2634-01-VCF-L) üzerinden yürütülmektedir. Buradaki gözlemler lab bağlamında değerlendirilmeli, production ortamı kararları için mutlaka resmi VMware dokümantasyonu ve deneyimli mühendisler referans alınmalıdır.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vmware</category>
    </item>
    <item>
      <title>vSAN Stretched Cluster: Site Koruması ve Local Affinity (Modül 4)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Sun, 05 Jul 2026 07:51:38 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/vsan-stretched-cluster-site-korumasi-ve-local-affinity-modul-4-14aa</link>
      <guid>https://dev.to/hakanbaban53/vsan-stretched-cluster-site-korumasi-ve-local-affinity-modul-4-14aa</guid>
      <description>&lt;p&gt;Üç haftadır SPBM, izleme ve şifreleme konularını işledim. Bu hafta Modül 4'e geçiyorum: vSAN Stretched Cluster. Önceki modüllere göre bu konu kavramsal olarak biraz daha zorlayıcı geldi; tek bir cluster'ı iki fiziksel siteye yaymak, hem ağ mimarisi hem de failure senaryoları açısından yeni bir düşünme biçimi gerektiriyor.&lt;/p&gt;

&lt;p&gt;Şunu baştan belirtmek isterim: HOL ortamı bunu tam olarak simüle edemiyor, manuel de bunu açıkça söylüyor. İki site arası gerçek bir 10GbE bağlantısı ya da crossover kablo burada yok. Ama stretched cluster'ı hazırlama adımları ve witness trafiğini ayırma mantığı, gerçek bir direct-connect cluster'da yapılanla aynı.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stretched Cluster Nedir, Neden Var?
&lt;/h2&gt;

&lt;p&gt;Normal bir vSAN cluster'ı tek bir lokasyonda çalışır. Stretched cluster ise aynı cluster'ı iki fiziksel siteye yayıyor: veri her iki sitede de bir kopya halinde tutuluyor. Amaç, bir sitenin tamamen kaybedilmesi durumunda bile VM'lerin diğer sitede çalışmaya devam etmesi.&lt;/p&gt;

&lt;p&gt;Bunu mümkün kılan üçüncü bir bileşen var: Witness Host. Bu, veri taşımayan, sadece quorum (çoğunluk kararı) sağlayan özel bir sanal cihaz. 1+1+1 mimarisi şöyle işliyor: Site 1'de en az bir host, Site 2'de en az bir host, ve ayrı bir yerde bir witness host.&lt;/p&gt;

&lt;h3&gt;
  
  
  2-Node Direct Connect Senaryosu
&lt;/h3&gt;

&lt;p&gt;vSAN 6.5'ten itibaren 2-node konfigürasyonlarda doğrudan crossover kablo kullanımı destekleniyor. Bu özellikle ROBO (remote office/branch office) senaryolarında değerli: her lokasyona 10GbE switch altyapısı kurmak maliyetli ve karmaşık olabiliyor. İki host'u doğrudan birbirine bağlamak bu maliyeti ortadan kaldırıyor, aynı zamanda karmaşıklığı azaltıp güvenilirliği artırıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7776t9054gq2eg0pwezr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7776t9054gq2eg0pwezr.png" alt="Node Direct Connect vSAN Cluster" width="800" height="1202"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Preferred Site Kavramı
&lt;/h2&gt;

&lt;p&gt;Stretched cluster'da "preferred site" (tercih edilen site) diye bir kavram var. Bu, vSAN'a "iletişim koptuğunda hangi tarafın ayakta kalmasını istiyorum" demenin yolu. Denilebilir ki preferred site, en güvenilir olması beklenen taraf.&lt;/p&gt;

&lt;p&gt;Mantık şöyle işliyor: Site 1 ile Site 2 arasındaki bağlantı koparsa ama her iki site de witness host'a erişebiliyorsa, preferred site çalışmaya devam ediyor ve bileşenleri aktif kalıyor. Preferred olmayan site'daki storage ise "down" olarak işaretleniyor, bileşenler "absent" durumuna geçiyor.&lt;/p&gt;

&lt;p&gt;Bu, klasik bir split-brain önleme mekanizması. Witness, kimin "doğru" taraf olduğuna karar veren hakem rolünü oynuyor.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read Locality: Okuma Trafiğini Yerel Tutmak
&lt;/h2&gt;

&lt;p&gt;Bu kısım benim için modülün en pratik bilgisi oldu. Normal vSAN'da okuma istekleri, verinin tüm replika kopyaları arasında round-robin şeklinde dağıtılıyor. Stretched cluster'da ise bu davranış değişiyor.&lt;/p&gt;

&lt;p&gt;Read locality algoritması, okumaların yüzde yüzünü compute'un bulunduğu site'daki yerel veri kopyasından yapıyor. Mantığı açık: VM'in compute kaynağı Site 1'deyse, okuma isteklerini Site 2'ye göndermek gereksiz bir ağ gecikmesi (latency) yaratır. Bu yeni algoritma, okuma işlemlerindeki gecikmeyi azaltmak için tasarlanmış.&lt;/p&gt;

&lt;p&gt;Manuel'de ilginç bir eşik veriyor: Eğer siteler arası gecikme 5ms'nin altındaysa ve yeterli bant genişliği varsa, read locality kapatılabiliyor. Ama bunu kapatmak, okuma trafiğinin yarısının uzak siteye gitmesi anlamına geliyor; bu da ağ bant genişliği planlaması için ciddi bir fark yaratıyor. Manuel ayrıca bunun yalnızca VMware Global Support Services rehberliğinde ve sadece son derece düşük gecikme olan ortamlarda yapılması gerektiğini özellikle vurguluyor. Yani bu varsayılan davranışı kapatmak bir "ileri seviye ayar" değil, neredeyse bir istisna durumu.&lt;/p&gt;

&lt;p&gt;Bununla ilgili gizli bir advanced parameter de var: &lt;code&gt;VSAN.DOMOwnerForceWarmCache&lt;/code&gt;. Bu, vSphere Web Client'ta görünmüyor, sadece CLI üzerinden erişilebiliyor. Bunun gizli tutulması bana mantıklı geldi; yanlışlıkla değiştirildiğinde etkisi geniş olabilecek bir ayar.&lt;/p&gt;




&lt;h2&gt;
  
  
  Witness Host: Cluster'ın Dışında Kalan Üye
&lt;/h2&gt;

&lt;p&gt;Burada altı önemle çizilen bir kural var: Stretched cluster yapılandırılırken sadece data host'lar cluster objesinin içinde olmalı. Witness host, cluster dışında kalmalı ve hiçbir aşamada cluster'a eklenmemeli.&lt;/p&gt;

&lt;p&gt;HOL ortamında witness host önceden deploy edilmiş durumda: &lt;code&gt;esx-11a.site-a.vcf.lab&lt;/code&gt;. Inventory görünümünde bu host'un sunucu ikonunda küçük bir işaret var; bunun normal bir ESX host değil, vSAN 2-Node ve Stretched Cluster mimarilerini desteklemek için kullanılan özel bir sanal cihaz olduğunu gösteriyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmecon6wvar938nrisoyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmecon6wvar938nrisoyc.png" alt="Inventory görünümü - esx-11a witness host" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Witness Networking: İki Ayrı Arayüz
&lt;/h3&gt;

&lt;p&gt;Witness appliance'ın iki ağ adaptörü var, iki ayrı standart switch'e bağlı:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Management VMkernel (vmk0):&lt;/strong&gt; vCenter ile iletişim için, appliance yönetimi amacıyla.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;secondaryPG (vmk1):&lt;/strong&gt; vSAN ağıyla iletişim için.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bu ayrım önerilen konfigürasyon. Bu iki arayüz farklı ya da aynı ağlara bağlanabilir, yeter ki ilgili servislere erişimleri olsun. Management arayüzü vSAN trafiğini de taşıyacak şekilde tag'lenebilir, ama bu durumda vmk0'ın hem vCenter'a hem vSAN ağına erişimi olması gerekiyor.&lt;/p&gt;

&lt;p&gt;Manuel'de nested ortamlar için ilginç bir not var: VMware'in bu HOL için kullandığı platform gibi birçok nested ESX ortamında, promiscuous mode'u etkinleştirme önerisi var. Sebebi şu: sanal switch, tanımadığı nested vmnic'ler için paketleri düşürebiliyor; promiscuous mode bunu önlüyor. HOL'da bu zaten yapılandırılmış durumda, ama gerçek bir nested ortamda bu ayarı unutursanız witness trafiği sessizce kaybolabilir; bunu hatırlamak gerekiyor.&lt;/p&gt;

&lt;p&gt;Witness üzerinde &lt;code&gt;secondaryPg&lt;/code&gt; adında önceden tanımlanmış bir portgroup var, vSAN trafiği için kullanılan VMkernel port burada görünüyor. vSAN ağında DHCP sunucusu yoksa (ki genelde yok), VMkernel adaptörünün geçerli bir IP adresi olmayacaktır; bu durumda manuel IP ataması gerekiyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi7tmx33i0xyc7uhhuk7t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi7tmx33i0xyc7uhhuk7t.png" alt="ESX host VMkernel Adapters - vmk0 üzerinde vSAN servisi etkin görünümü" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Route Gerekliliği
&lt;/h3&gt;

&lt;p&gt;Stretched cluster yapılandırılmadan önceki son adım, her sitedeki host'lar ile witness host arasında bağlantının sağlandığından emin olmak. Bu bağlantıyı yapılandırmadan önce doğrulamak önemli.&lt;/p&gt;

&lt;p&gt;vSAN ağı, veri siteleri arasında stretched bir L2 broadcast domain olarak öneriliyor, ama witness appliance'ın vSAN ağına ulaşmak için L3 (routing) gerekiyor. Bu yüzden veri host'ları ile witness arasında static route'lar tanımlanması gerekiyor; ama farklı sitelerdeki veri host'larının birbiriyle iletişimi için bu gerekmiyor, çünkü onlar zaten aynı L2 domain'de.&lt;/p&gt;

&lt;p&gt;Bir static route eklemek için kullanılan esxcli komutu manuel'de örnek olarak veriliyor; route bilgisini görüntülemek için ayrı komutlar da mevcut (network komşularını listeleyen ve gateway bilgisini gösteren komutlar). Bu adımın her host için tekrarlanması gerektiği özellikle vurgulanıyor.&lt;/p&gt;

&lt;p&gt;Bu kısmı okurken şunu düşündüm: GUI üzerinden yapılan çoğu adımın aksine, bu networking hazırlığı CLI bilgisi gerektiriyor. HOL'da bu adım atlanmış, zaten hazır geliyor, ama gerçek bir kurulumda muhtemelen en çok zaman alacak ve en çok hata yapılacak adım burası olurdu.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mevcut Cluster'ı Stretched Cluster'a Dönüştürmek
&lt;/h2&gt;

&lt;p&gt;HOL'da var olan 4-node cluster'ı (esx-05a, 06a, 07a, 08a) stretched cluster'a çeviriyoruz. İki host daha (esx-09a, esx-10a) cluster'a ekleniyor, toplam 6 node oluyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Host'ları Cluster'a Eklemek
&lt;/h3&gt;

&lt;p&gt;Önce her iki host'ta da (&lt;code&gt;esx-09a&lt;/code&gt; ve &lt;code&gt;esx-10a&lt;/code&gt;) vSAN VMkernel adaptörünün doğru yapılandırıldığı, &lt;code&gt;Configure &amp;gt; VMkernel Adapters&lt;/code&gt; üzerinden kontrol ediliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0oa3pfdlyd9kl42u3wqp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0oa3pfdlyd9kl42u3wqp.png" alt="ESX host VMkernel Adapters - vmk0 üzerinde vSAN servisi etkin görünümü" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ardından host'lar sürükle-bırak ile cluster'a ekleniyor. Açılan onay penceresi varsayılan ayarlarla geçiliyor. Host cluster'a eklendikten sonra, eğer maintenance mode'daysa sağ tık ile Exit Maintenance Mode uygulanıyor. Bu işlem birkaç dakika sürebiliyor, Recent Tasks üzerinden takip edilebiliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9utydu5dc502oesr0107.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9utydu5dc502oesr0107.png" alt="esx-09a ve esx-10a host'larının cluster-esa-01a'ya sürüklenmesi" width="386" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fault Domain Yapılandırması
&lt;/h3&gt;

&lt;p&gt;Asıl dönüşüm burada başlıyor:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cluster-esa-01a &amp;gt; Configure &amp;gt; vSAN &amp;gt; Fault Domains &amp;gt; CONFIGURE STRETCHED CLUSTER&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Açılan ekranda host'lar iki domain'e ayrılıyor. Varsayılan olarak hepsi "preferred" tarafında görünüyor; &lt;code&gt;esx-08a&lt;/code&gt;, &lt;code&gt;esx-09a&lt;/code&gt; ve &lt;code&gt;esx-10a&lt;/code&gt; seçilip &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; ile secondary domain'e taşınıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhocbwtt4ihzkwehsw76r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhocbwtt4ihzkwehsw76r.png" alt="Fault Domains yapılandırma - host'ların preferred/secondary olarak ayrılması" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sonraki adımda witness host seçiliyor: &lt;code&gt;esx-11a&lt;/code&gt;. vSAN burada otomatik bir uyumluluk kontrolü çalıştırıyor; witness'ın bu cluster ile kullanılabilir olup olmadığını doğruluyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkody7rbb28pgu9npfmeo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkody7rbb28pgu9npfmeo.png" alt="Witness host seçim ekranı ve uyumluluk kontrolü" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Review ekranında vSAN, oluşturacağı cluster konfigürasyonunun özetini gösteriyor; burada, dönüştürme işlemi tamamlanmadan önce düzeltme yapma fırsatı da veriliyor. FINISH ile cluster oluşturuluyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ux55dojzrwkcth9hv2x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4ux55dojzrwkcth9hv2x.png" alt="Stretched cluster yapılandırma özeti - Review ekranı" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;İşlem sırasında Recent Tasks panelinden ilerleme izlenebiliyor; tüm görevler "Completed" olana kadar beklemek gerekiyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sonucu Doğrulamak
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;cluster-esa-01a &amp;gt; Configure &amp;gt; vSAN &amp;gt; Fault Domains&lt;/code&gt; ekranına dönüldüğünde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Failures To Tolerate (FTT) değeri 1 olarak görünüyor. Bu, cluster'ın herhangi bir site'ın (ya da witness host'un) kaybını tolere edip VM'leri çalışır tutabileceği anlamına geliyor.&lt;/li&gt;
&lt;li&gt;İki fault domain ve bunlara ait host'lar listede görünüyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5bsdsa7kl7ovoa1tgmnu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5bsdsa7kl7ovoa1tgmnu.png" alt="Fault Domains özet ekranı - FTT=1 ve iki domain" width="799" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Manuel'de önemli bir mimari notu var: Site Mirroring ile FTT=1 kombinasyonu, stretched cluster'lar için önerilen standart mimari. 6 node ve üzeri büyük stretched cluster'larda, site içi ek koruma katmanı da isteğe bağlı olarak yapılandırılabiliyor; bu seçimler tipik vSAN politikalarıyla (RAID-1 mirroring, RAID-5 ve RAID-6 erasure coding) uyumlu. Yani site-level koruma ile site-içi koruma birbirinden ayrı, üst üste konumlandırılabilen iki katman.&lt;/p&gt;




&lt;h2&gt;
  
  
  Nested Ortam Uyarıları
&lt;/h2&gt;

&lt;p&gt;HOL, nested bir vSphere ortamında çalıştığı için vCenter, vSAN cluster'ının sağlığı hakkında birkaç uyarı gösteriyor. Manuel açıkça şunu söylüyor: bu lab kapsamında bu uyarıları görmezden gelmek veya susturmak sorun değil, ama gerçek workload barındıran herhangi bir "canlı" vSAN cluster'ında bu tür uyarıları Skyline Health servisi üzerinden detaylıca araştırmak gerekiyor.&lt;/p&gt;

&lt;p&gt;Bu küçük ama önemli bir uyarı; HOL'da görülen "her şey kırmızı/sarı" görünümünün gerçek ortamda aynı ciddiyetle ele alınmaması gerektiğini hatırlatıyor, ama aynı zamanda gerçek ortamda bu uyarıların asla göz ardı edilmemesi gerektiğini de.&lt;/p&gt;




&lt;h2&gt;
  
  
  Skyline Health: Stretched Cluster'a Özel Kontroller
&lt;/h2&gt;

&lt;p&gt;Cluster oluşturulduktan sonra Skyline Health'te yeni bulgular ortaya çıkıyor. RETEST'e basıldığında "vSAN optimal datastore default policy configuration" başlıklı bir uyarı görülüyor; üç nokta menüsünden TROUBLESHOOT seçilince detaylar açılıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzm2fqm97ltg7s4gniorq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzm2fqm97ltg7s4gniorq.png" alt="Skyline Health - optimal datastore default policy uyarısı ve Troubleshoot görünümü" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Datastore Default Policy'yi Güncellemek
&lt;/h3&gt;

&lt;p&gt;Cluster yapısı değiştiği için (standart cluster'dan, her sitede üç host olan bir stretched cluster'a geçiş), Skyline Health iki değişiklik öneriyor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standart cluster'dan stretched cluster'a (site mirroring ile) geçiş.&lt;/li&gt;
&lt;li&gt;Her site içinde RAID-5'ten RAID-1'e geçiş.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"UPDATE Cluster DS Policy" butonuna basılıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1mwm6r1yklm8a5d9v93.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1mwm6r1yklm8a5d9v93.png" alt="Update datastore default policy onay penceresi" width="799" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Açılan onay penceresinde OK tıklanıyor. Default policy değiştirildiği için, orijinal policy'i kullanan VM'lerin yeni policy'e geçmesi için ayrıca reapply işlemi gerekiyor. Bu ortamdaki VM'ler varsayılan ESA RAID-5 policy'sini kullandığından, policy'yi manuel olarak yeni Optimal Storage Policy'ye değiştirmek gerekiyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mevcut VM'lere Yeni Policy'i Uygulamak
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Policies and Profiles&lt;/code&gt; menüsüne gidilip yeni oluşan &lt;code&gt;cluster-esa-01a - Optimal Datastore Default Policy - stretched RAID1&lt;/code&gt; policy'si seçiliyor, REAPPLY'a tıklanıyor. Bir uyarı, bu işlemin zaman alabileceğini ve birkaç VM'i etkileyeceğini bildiriyor; OK ile onaylanıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcc3vmiw5xoa26a913au2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcc3vmiw5xoa26a913au2.png" alt="Policies and Profiles - REAPPLY işlemi ve uyarı penceresi" width="799" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Skyline Health'e dönülüp tekrar RETEST yapıldığında, policy uyarısının kaybolduğu görülüyor. Manuel'de bir not daha var: bazen bu uyarı bir kez daha görünebiliyor, RETEST ile geçiyor.&lt;/p&gt;

&lt;p&gt;Stretched cluster'a özel diğer health check'leri görmek için filtre üzerinden "Stretched cluster" kategorisi seçilebiliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp3d6gqv77e2jpnjlywuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp3d6gqv77e2jpnjlywuh.png" alt="Skyline Health - Stretched cluster kategorisi filtrelenmiş görünüm" width="799" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;vSAN health check, vSAN kurulumlarının performans ve sağlık testlerine derinlemesine inmek için değerli bir araç; vSAN ortamını izlemek için gidilecek ilk yer olmalı. Güncel durumu görmek için health check'i düzenli olarak yeniden çalıştırmak iyi bir pratik.&lt;/p&gt;




&lt;h2&gt;
  
  
  vSAN Site Affinity: Her VM'in Çok Site Koruması İstemediği Durumlar
&lt;/h2&gt;

&lt;p&gt;Modülün ikinci yarısı farklı bir soruna eğiliyor. Bir veri merkezinde, uygulama seviyesinde zaten dahili yüksek erişilebilirlik veya yedeklilik sağlayan pek çok workload var. Ama tipik production workload'ları çoğunlukla daha iyi veri yedekliliği için çok-site koruması gerektiriyor. Peki, kopyaların farklı sitelerde tutulmasını gerektirmeyen workload'lar için ne yapılabilir?&lt;/p&gt;

&lt;p&gt;Bu soruya cevap: &lt;strong&gt;Local Affinity&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Affinity Mantığı
&lt;/h3&gt;

&lt;p&gt;Local Affinity, bir policy aracılığıyla veriyi tek bir site'da tutmayı sağlıyor. Bunun teknik karşılığı Primary Failures To Tolerate (PFTT) değerinin 0 olarak ayarlanması. PFTT=0 olduğunda nesneler ikincil siteye replike edilmiyor, bu da siteler arası gereken bant genişliğini azaltıyor. Ayrıca affinity kuralları kullanılarak VM/VMDK atamaları belirli host'lara da sabitlenebiliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv5xlvy0r403x9kl8p314.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv5xlvy0r403x9kl8p314.png" alt="Local Affinity" width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Manuel, test senaryosu olarak şu kombinasyonu öneriyor: PFTT=0, Secondary Failures To Tolerate (SFTT)=2, Failure Tolerance Method (FTM)=RAID-5. Bu kombinasyonla tüm I/O'nun yerel olarak yapılması, hiçbirinin ikincil siteye gitmemesi bekleniyor. Yani site koruması olmadan, host/disk seviyesinde koruma sorunsuzca elde edilmiş oluyor.&lt;/p&gt;

&lt;p&gt;Birkaç kısıtlama da var:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Affinity, sadece Stretched Cluster etkinleştirilmiş cluster'larda kullanılabiliyor.&lt;/li&gt;
&lt;li&gt;DRS/HA kuralları, data locality ile uyumlu olmalı.&lt;/li&gt;
&lt;li&gt;OSA'da Hybrid konfigürasyonlarda RAID-0 ve RAID-1 destekleniyor, All-Flash'te RAID-0, RAID-1, RAID-5 ve RAID-6 destekleniyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bu son madde aklımda kaldı: Local Affinity kullanılırken DRS/HA kurallarının manuel olarak hizalanması gerekiyor. Bu, "policy ayarladım, iş bitti" diyemeyeceğiniz, cluster'ın diğer otomasyon katmanlarıyla da koordinasyon gerektiren bir özellik.&lt;/p&gt;

&lt;h3&gt;
  
  
  Single Site Storage Policy Oluşturmak
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Policies and Profiles &amp;gt; VM Storage Policies &amp;gt; CREATE&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;İsim: &lt;code&gt;Single Site Storage Policy&lt;/code&gt;. "Enable rules for vSAN storage" seçiliyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdub9xfw7mzqowm39ji3r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdub9xfw7mzqowm39ji3r.png" alt="VM Storage Policy oluşturma - isim ve vSAN storage kuralları etkinleştirme" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Availability sekmesinde:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Site disaster tolerance: &lt;strong&gt;None - keep data on Preferred (stretched cluster)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Failures to tolerate: &lt;strong&gt;1 failure - RAID-1 (Mirroring)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsg9cz2aub5cxmguozz0a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsg9cz2aub5cxmguozz0a.png" alt="Availability sekmesi - Site disaster tolerance ve FTT seçimleri" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Datastore uyumluluğu doğrulanıyor (&lt;code&gt;vsan-esa-01a_Datastore&lt;/code&gt; Compatible görünmeli), FINISH ile policy tamamlanıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhc0r34paxkwi8ivpkviw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhc0r34paxkwi8ivpkviw.png" alt="VM Storage Policies listesi - Single Site Storage Policy ve kuralları" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Affinity Policy ile VM Oluşturmak
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;core-a&lt;/code&gt; VM'i klonlanarak &lt;code&gt;Local Affinity VM&lt;/code&gt; adıyla yeni bir VM oluşturuluyor. Clone wizard'ında:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Datacenter: &lt;code&gt;dc-a&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Cluster: &lt;code&gt;cluster-esa-01a&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Storage Policy: &lt;code&gt;Single Site Storage Policy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Datastore: &lt;code&gt;vsan-esa-01a_Datastore&lt;/code&gt; (compatible olarak görünüyor)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffy5bf900ttdai3ooxq25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffy5bf900ttdai3ooxq25.png" alt="Clone wizard - Single Site Storage Policy seçimi" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Klon tamamlandığında VM Summary'den policy'nin atandığı ve "Compliant" olduğu doğrulanıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Yerleşimi Doğrulamak: Preferred Fault Domain
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;cluster-esa-01a &amp;gt; Configure &amp;gt; vSAN &amp;gt; Fault Domains&lt;/code&gt; ekranından preferred fault domain'in hangi host'ları içerdiği görülüyor. HOL'daki örnekte &lt;code&gt;esx-05a&lt;/code&gt;, &lt;code&gt;esx-06a&lt;/code&gt; ve &lt;code&gt;esx-07a&lt;/code&gt; preferred domain'de.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fibmwch6a830pfcjfd7ow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fibmwch6a830pfcjfd7ow.png" alt="Fault Domains - Preferred domain ve içerdiği host'lar" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Local Affinity VM &amp;gt; Monitor &amp;gt; vSAN &amp;gt; Physical disk placement&lt;/code&gt; ekranından, bileşenlerin gerçekten preferred fault domain üzerinde konumlandığı doğrulanıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc50haunisxy0la7rvfny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc50haunisxy0la7rvfny.png" alt="Physical disk placement - bileşenlerin Preferred domain'de görünmesi" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu doğrulama adımı önemli, çünkü policy'nin "doğru göründüğünü" varsaymak yerine bileşenlerin gerçekte nerede oturduğunu kontrol etmek, "compliant" etiketinin arkasındaki gerçekliği teyit ediyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Policy'i Değiştirip Site Geçişini Görmek
&lt;/h3&gt;

&lt;p&gt;Modülün son kısmında, &lt;code&gt;Single Site Storage Policy&lt;/code&gt; düzenlenerek Site disaster tolerance ayarı &lt;strong&gt;"None - keep data on Secondary"&lt;/strong&gt; olarak değiştiriliyor. Bu, verinin artık preferred yerine secondary site'da tutulmasını söylüyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffq5c8a4d13opt1xnrmgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffq5c8a4d13opt1xnrmgf.png" alt="Policy düzenleme - Site disaster tolerance Secondary olarak değiştirme" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Policy zaten bir VM tarafından kullanıldığı için, "Reapply to VMs" seçeneği "Now" olarak ayarlanıp YES ile onaylanıyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyralqx9dzl1ye9vo3tnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyralqx9dzl1ye9vo3tnp.png" alt="Reapply to VMs - Now seçeneği ve onay" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Son doğrulama adımında &lt;code&gt;Local Affinity VM &amp;gt; Monitor &amp;gt; vSAN &amp;gt; Physical disk placement&lt;/code&gt; tekrar kontrol ediliyor; bu sefer bileşenlerin Secondary Fault Domain'e taşındığı görülüyor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs0u7874h3kji2uk47x3p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs0u7874h3kji2uk47x3p.png" alt="Physical disk placement - bileşenlerin Secondary domain'e taşınmış hali" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu son adım, Local Affinity'nin sadece statik bir yerleşim olmadığını, policy değiştiğinde verinin gerçekten fiziksel olarak başka bir site'a taşındığını gösteriyor. vMotion gibi VM'in compute'unun taşınması değil, doğrudan storage nesnelerinin yeniden yerleştirilmesi (re-placement) söz konusu.&lt;/p&gt;




&lt;h2&gt;
  
  
  Genel Değerlendirme
&lt;/h2&gt;

&lt;p&gt;Bu modül, önceki üçünden farklı bir karaktere sahip. SPBM, izleme ve şifreleme tek bir site içinde çalışan kavramlardı. Stretched cluster ise coğrafi/fiziksel bir boyut ekliyor; ağ topolojisi, gecikme süreleri ve "hangi taraf hayatta kalmalı" gibi sorular devreye giriyor.&lt;/p&gt;

&lt;p&gt;Benim için en çok düşündüren üç nokta şunlardı:&lt;/p&gt;

&lt;p&gt;Birincisi, witness host'un cluster'ın &lt;strong&gt;dışında&lt;/strong&gt; tutulması gerekliliği. İlk bakışta tuhaf geliyor; quorum sağlayan bir bileşenin neden cluster üyesi olmadığını sorgulamak doğal. Ama mantığı şu: witness veri taşımıyor, sadece karar verici. Cluster üyesi olsaydı, kendisi de bir failure noktası haline gelebilirdi.&lt;/p&gt;

&lt;p&gt;İkincisi, read locality'nin varsayılan davranış olması ve kapatılmasının neredeyse istisnai bir durum olarak tanımlanması. Bu, "ne zaman varsayılanı değiştirmemeliyim" sorusuna iyi bir örnek; bazen en iyi karar, ayarı olduğu gibi bırakmak.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, Local Affinity'nin son demosu; policy değiştiğinde verinin fiziksel olarak taşındığını göstermesi. Bu, SPBM'in sadece "uyumlu/uyumsuz" etiketlemekle kalmadığını, gerçek veri hareketini tetiklediğini somut olarak gösteriyor. Modül 1'de gördüğümüz Placement Details ekranının burada da işe yaraması, serinin kendi içinde nasıl bağlandığını da hissettirdi.&lt;/p&gt;

&lt;p&gt;HOL'un nested ortam kısıtlamaları burada daha belirgin hissettiriyor kendini; gerçek bir stretched cluster kurulumunda WAN gecikmesi, bant genişliği sınırlamaları ve gerçek bir site kaybı senaryosu test etmek, bu modülün kapsamının çok ötesinde bir konu. Ama temel kavramları, doğru terminolojiyle ve doğru sırayla görmüş olmak, gerçek bir tasarım dokümanını okurken işe yarayacak bir zemin oluşturuyor.&lt;/p&gt;

&lt;p&gt;Bir sonraki hafta Modül 5'e geçiyorum.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri VMware HOL ortamı (HOL-2634-01-VCF-L) üzerinden yürütülmektedir. Buradaki gözlemler lab bağlamında değerlendirilmeli, production ortamı kararları için mutlaka resmi VMware dokümantasyonu ve deneyimli mühendisler referans alınmalıdır.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vmware</category>
      <category>vsan</category>
    </item>
  </channel>
</rss>
