<?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># VCF 9.1: Memory Tiering, vSAN Global Deduplication ve Oracle RAC / WSFC için Hot Extend (Modül 3)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Thu, 15 Oct 2026 05:23:15 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/-vcf-91-memory-tiering-vsan-global-deduplication-ve-oracle-rac-wsfc-icin-hot-extend-modul-3-1b1c</link>
      <guid>https://dev.to/hakanbaban53/-vcf-91-memory-tiering-vsan-global-deduplication-ve-oracle-rac-wsfc-icin-hot-extend-modul-3-1b1c</guid>
      <description>&lt;p&gt;HOL-2701-01 serisinin son yazısı. İlk modülde arayüz ve VCF Operations'ı, ikinci modülde VCF Automation'ı gezdim. Bu yazıda vSphere tarafında Memory Tiering, vSAN tarafında Auto RAID, Global Deduplication ve clustered uygulamalar için Hot Extend'i ele alıyoruz.&lt;/p&gt;

&lt;p&gt;Her zamanki gibi bunları sahadan değil, HOL ortamından yazıyorum. Production'da Memory Tiering ya da vSAN ESA işletmedim. Lab'ı "bunu gerçek bir ortamda açmadan önce ne sorardım" gözüyle okumaya çalıştım. Yanlış anladığım yer olursa yorumlarda düzeltirseniz sevinirim.&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%2Fc9iyobro62vr5qc0sufu.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%2Fc9iyobro62vr5qc0sufu.png" alt="Lab konsolunda vc-wld01-a vCenter ana ekranı" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory Tiering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Kılavuzun anlattığı problem
&lt;/h3&gt;

&lt;p&gt;Kılavuzun bu bölümü, bir okuma kısmıyla başlıyor ve çıkış noktası şu: pratikte bellek kullanımı genelde CPU kullanımından yüksek oluyor. Bellek neredeyse dolarken CPU düşük kalıyor ve o CPU'yu kullanamıyorsunuz, çünkü ona bağlı bellek yok. Host ya da koca bir küme &lt;strong&gt;memory-bound&lt;/strong&gt; hale geliyor. Kılavuza göre bunun sonucu verimsiz kaynak kullanımı, güç ve soğutma israfı ve bellek maliyetinin TCO içindeki büyük payı yüzünden artan maliyet.&lt;/p&gt;

&lt;p&gt;Çözüm olarak ESX host'una takılı yerel NVMe cihazlarını "tiered memory" olarak kullanıp belleği iki katmana ayırıyorlar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tier 0:&lt;/strong&gt; DRAM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tier 1:&lt;/strong&gt; NVMe. Yalnızca host üzerinde çalışan VM'ler için kullanılıyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mantık sayfaların ne kadar kullanıldığına göre sınıflandırılması:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hot:&lt;/strong&gt; Zamanın %50'sinden fazlasında aktif.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warm:&lt;/strong&gt; Zamanın %50'sinden azında kullanılıyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold:&lt;/strong&gt; Zamanın %20'sinden azında kullanılıyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Very cold:&lt;/strong&gt; Neredeyse hiç kullanılmayan sayfalar. Kılavuz bunu aşırı provisioning'e bağlıyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cold ve very cold sayfalar NVMe'ye iniyor, DRAM boşalıyor. Böylece aynı CPU kapasitesiyle daha fazla VM çalıştırabiliyorsunuz.&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%2F23070xhxvbaz7gt5w74c.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%2F23070xhxvbaz7gt5w74c.png" alt="Memory Tiering, Tier 0 DRAM ve Tier 1 NVMe katman diyagramı" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kılavuzun listelediği hedefler arasında şunlar var: uygulamalara şeffaf, DRAM ve NVMe üzerinde tek bir tüketim modeli, ortak bir yönetim modeli ve &lt;strong&gt;VM bazında Memory Tiering'i kapatabilme&lt;/strong&gt;. HA, DRS, vMotion, Fast Suspend/Resume ve RAID desteği de kılavuzda açıkça sayılmış.&lt;/p&gt;

&lt;h3&gt;
  
  
  VCF Operations'ta "ya eklesem" simülasyonu
&lt;/h3&gt;

&lt;p&gt;Bu bölümün en pratik cümlesi bence şu: VCF Operations, NVMe eklemeden önce bunu simüle etmenizi sağlıyor. Mevcut CPU ve bellek kullanım örüntülerine bakarak potansiyel maliyet tasarrufunu, olası VM sayısı artışını, projeksiyonla bellek durumunu ve CPU kullanımındaki beklenen iyileşmeyi gösteriyor. Maliyet tahminleri VCF Operations'taki cost driver'lara dayanıyor ve güncel piyasa fiyatlarına göre güncellenebiliyor. Aktif bellek kullanımı &lt;strong&gt;%50'nin altında&lt;/strong&gt; ve boş CPU kapasitesi &lt;strong&gt;%50'nin üstünde&lt;/strong&gt; olan kümeler güçlü aday olarak işaretleniyor.&lt;/p&gt;

&lt;p&gt;Donanım satın almadan önce "bu bana ne kazandırır" sorusuna veri ile cevap verebilmek hoşuma gitti. Bir bütçe konuşmasında bu tür bir çıktı iş görür. Ama bu simülasyonun ekranını lab'da görmedik, sadece okuma kısmında anlatılıyor. Tahminin ne kadar doğru çıktığı, ya da hangi metriklerle ne kadar süreyle toplanan veriye dayandığı da bilgi olarak 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%2F53no5eplw4vux2g09bqc.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%2F53no5eplw4vux2g09bqc.png" alt="VCF Operations'ta Memory Tiering simülasyonu" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lab'da gördüğüm: ayarlar
&lt;/h3&gt;

&lt;p&gt;Lab'da Memory Tiering açılmıyor, sadece ayarlar inceleniyor. Kılavuz, ayrıntılı kurulum için &lt;strong&gt;HOL-2703-01-VCF-L&lt;/strong&gt; adlı ayrı lab'ı öneriyor. Orada tiering'in gerçekten yapılandırıldığı ve vCenter ile VCF Operations'taki yeni gözlemlenebilirlik raporlarının ve dashboard'ların gezildiği anlatılıyor.&lt;/p&gt;

&lt;p&gt;Yol şöyle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;vCenter'da (&lt;code&gt;vc-wld01-a&lt;/code&gt;) &lt;strong&gt;Hosts and Clusters&lt;/strong&gt; &amp;gt; &lt;code&gt;cluster-wld01-01a&lt;/code&gt; &amp;gt; &lt;strong&gt;Configure&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Soldaki menüde &lt;strong&gt;Desired State &amp;gt; Configuration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Önceden bir draft varsa &lt;strong&gt;Discard Draft&lt;/strong&gt;, sonra &lt;strong&gt;Draft&lt;/strong&gt; sekmesinde &lt;strong&gt;CREATE DRAFT&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;esx&lt;/strong&gt; kategorisi altında &lt;strong&gt;memtier&lt;/strong&gt; &amp;gt; &lt;strong&gt;nvme&lt;/strong&gt; ayarı &amp;gt; &lt;strong&gt;CONFIGURE SETTINGS&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Memory Tiering ayarı küme genelinde Desired State yapılandırmasının bir parçası. Yani ayarı tek tek host'larda yapmıyorsunuz, draft üzerinden küme için tanımlı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%2F3giplhookb1qqd04mszi.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%2F3giplhookb1qqd04mszi.png" alt="Cluster &gt; Configure &gt; Desired State &gt; Configuration, Draft sekmesi" width="800" height="433"&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%2Fx5cxkl3s8nnwb8wa79nk.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%2Fx5cxkl3s8nnwb8wa79nk.png" alt="esx kategorisi altında memtier &gt; nvme ayarı" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ayar ekranında şunlar var:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enabled:&lt;/strong&gt; TRUE yapınca Memory Tiering açılıyor. Varsayılan olarak &lt;strong&gt;kapalı&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;device:&lt;/strong&gt; Her host için birincil NVMe cihazı.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mirror_device:&lt;/strong&gt; İkincil ya da mirror NVMe cihazı. Birincil NVMe'de sorun olursa yedeklilik için.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;encryption:&lt;/strong&gt; NVMe'de tutulan bellek sayfalarının şifrelenmesi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yüzde değeri:&lt;/strong&gt; Memory Tiering için kullanılacak NVMe miktarı, fiziksel belleğin yüzdesi olarak. Varsayılan &lt;strong&gt;100&lt;/strong&gt;, yani fiziksel belleğin %100'ü.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sonra &lt;strong&gt;CANCEL&lt;/strong&gt; diyorsunuz, hiçbir şey kaydedilmiyor.&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%2Fwdz3hhzpq7ib2zq4vflc.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%2Fwdz3hhzpq7ib2zq4vflc.png" alt="Memory Tiering ayarları, enabled, device, mirror_device, encryption ve yüzde alanı" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Gerçek ortamda soracağım sorular
&lt;/h3&gt;

&lt;p&gt;Kılavuzun anlattığı faydalar (daha fazla VM yoğunluğu, daha iyi CPU kullanımı, düşen TCO) mantıklı geliyor. Ama lab hiçbirini ölçmüyor. Bende kalan sorular şunlar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cold sayfaya erişim gerekirse ne olur?&lt;/strong&gt; NVMe, DRAM'den yavaş. Kılavuz "şeffaf" diyor, ama gecikmeye duyarlı iş yüklerinde bunun etkisini bilmek isterim. VM bazında kapatabilmek tam bu yüzden değerli bir seçenek olabilir.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hangi NVMe cihazları destekleniyor?&lt;/strong&gt; Dayanıklılık (yazma ömrü) ve performans gereksinimleri nelerdir, kılavuz değinmiyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mirror cihaz zorunlu mu, tavsiye mi?&lt;/strong&gt; Birincil cihaz arızalanırsa o host'taki VM'lere ne olacağını lab'da denemedik.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;%100 varsayılanı ne anlama geliyor?&lt;/strong&gt; Fiziksel belleğin yüzde yüzü kadar NVMe kullanmak, toplam belleği iki katına çıkarmak gibi okunabilir, ama kılavuz bunu açıkça yazmıyor. Kendi yorumum, o yüzden emin değilim.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  vSAN
&lt;/h2&gt;

&lt;p&gt;Bu modül üç özellik üzerine kurulu: Auto RAID, Global Deduplication ve clustered uygulamalar için Hot Extend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Auto RAID
&lt;/h3&gt;

&lt;p&gt;vSAN ESA'da &lt;strong&gt;Auto-RAID&lt;/strong&gt; storage policy'si, site disaster tolerance ve failures to tolerate değerlerini küme yapılandırmasına göre kendisi belirliyor. Yeni storage policy oluştururken bu varsayılan ayar. Kılavuza göre:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3-5 host'luk kümelerde:&lt;/strong&gt; RAID-5 erasure coding, 1,5x RAID overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 ve üzeri host'ta:&lt;/strong&gt; RAID-6 erasure coding, aynı 1,5x overhead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Küme yapılandırması değişirse (örneğin host eklerseniz) nesneler otomatik olarak yeni optimal ayara göre yeniden yapılandırılıyor. Kılavuz bunun performansı etkilemeden daha iyi veri koruması sağladığını söylüyor.&lt;/p&gt;

&lt;p&gt;Bu bölüm tamamen okuma. Lab'da Auto-RAID policy'si oluşturmuyoruz. İşletme gözüyle sorum şu: host sayısı 5'ten 6'ya çıkınca RAID-5'ten RAID-6'ya geçiş sırasında yeniden yapılandırma (resync) trafiği ne kadar olur, bunu bakım penceresine nasıl yerleştiririm? Lab bunu göstermiyor. Auto-RAID ayrıca bir sonraki bölümdeki effective capacity görünümünü de açıyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Global Deduplication ve Effective Capacity Reporting
&lt;/h3&gt;

&lt;p&gt;vSAN ESA artık küme seviyesinde &lt;strong&gt;global deduplication&lt;/strong&gt; yapabiliyor. Kılavuza göre sıkıştırma 9.1'de varsayılan olarak açık. Global dedup ise ESA kümesini yapılandırdıktan sonra açılabiliyor ve vSAN nesne seviyesinde uygulanıyor. Çalışma biçimi: kümedeki tekrarlanan veri bloklarını kaldırıp yerine tek bir örneğe işaret eden pointer'lar koyuyor. Modül girişinde bunun küme geneli ve post-processing bir ayar olduğu, şifreleme desteğiyle geldiği ve dedup etkinliğini düşürmeden data-at-rest güvenliği sağladığı belirtiliyor.&lt;/p&gt;

&lt;p&gt;vSAN serisinde (Modül 3) şifrelemeye bakmıştık. Dedup ile şifrelemenin birlikte çalışması bu yüzden dikkatimi çekti, çünkü bunlar genelde birbirini köreltir. Kılavuz bunun mekanizmasını anlatmıyor, sadece "etkinliği düşürmeden" diyor.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dedup'un getirdiği kısıtlar
&lt;/h4&gt;

&lt;p&gt;Kılavuz bunları açıkça sayıyor ve bence bu bölümün en değerli kısmı bu:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thick-provisioned VM'ler dedup edilmiyor.&lt;/strong&gt; Global dedup açıldıktan sonra kümedeki thick VM'ler dedup dışı kalıyor. Thin'den thick'e çevrilen bir VM için de dedup duruyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stretched cluster'a dönüşüm yok.&lt;/strong&gt; Standart bir vSAN kümesinde global dedup açıldıysa, o küme sonradan stretched cluster'a çevrilemiyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;İkincisini tasarım aşamasında bilmezseniz ileride pahalıya patlayabilir: "şimdilik standart kuralım, sonra stretched'a geçeriz" planı varsa dedup'u açmadan önce iki kere düşünmek gerekir.&lt;/p&gt;

&lt;h4&gt;
  
  
  Lab'da gördüğüm
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;vCenter'da &lt;code&gt;cluster-wld01-01a&lt;/code&gt; &amp;gt; &lt;strong&gt;Configure &amp;gt; vSAN &amp;gt; Services&lt;/strong&gt;. Lab'da deduplication zaten &lt;strong&gt;açık&lt;/strong&gt; görünüyor. Kapalı olsaydı &lt;strong&gt;EDIT&lt;/strong&gt; ile açabilirdik, ama gerek yok.&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%2F96dexmh0p8h705mrldke.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%2F96dexmh0p8h705mrldke.png" alt="Configure &gt; vSAN &gt; Services, Deduplication açık" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Aynı kümede &lt;strong&gt;Monitor &amp;gt; vSAN &amp;gt; Capacity&lt;/strong&gt;. &lt;strong&gt;Space Efficiency&lt;/strong&gt; bölümünde kullanılan kapasite &lt;strong&gt;83,82 GB&lt;/strong&gt;, data reduction tasarrufu &lt;strong&gt;57,55 GB&lt;/strong&gt; görünüyor. Kılavuz sizin ortamınızda rakamların biraz farklı çıkabileceğini söylüyor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data reduction ratio&lt;/strong&gt; altında &lt;strong&gt;SHOW DETAILS&lt;/strong&gt; diyince dedup oranı ve sıkıştırma oranı ayrı ayrı görünüyor. 9.1'de sıkıştırma varsayılan açık olduğu için ikisini birbirinden ayırabilmek güzel.&lt;/p&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%2F7ozali9dmsw21r0g1hqp.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%2F7ozali9dmsw21r0g1hqp.png" alt="Monitor &gt; vSAN &gt; Capacity, Space Efficiency bölümü" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada dürüst olmam gereken şey şu: lab'ın küçük bir veri setiyle çalıştığını rakamlardan görüyorsunuz (83 GB civarı). Bu oranlar production'daki gerçek veri için bir fikir vermez. Dedup'un gerçek faydası iş yükünün tipine (çok sayıda aynı OS imajı mı, veritabanı mı) bağlı ve bunu lab'da test etme şansımız yok. Ayrıca post-processing olduğunu düşününce, dedup'un ne zaman ve ne kadar sürede etki edeceğini, arka planda ne kadar kaynak tükettiğini de bilmek isterim.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clustered uygulamalar için Hot Extend: Oracle RAC ve WSFC
&lt;/h3&gt;

&lt;p&gt;VCF 9.1, clustered uygulamaların disklerini, o uygulamayı barındıran VM'leri kapatmadan genişletmenize izin veriyor. Kılavuza göre hem &lt;strong&gt;Oracle RAC multi-writer&lt;/strong&gt; hem de &lt;strong&gt;Windows Server Failover Cluster (WSFC)'taki shared VMDK&lt;/strong&gt; destekleniyor. Multi-writer attribute'unu kaldırmanız da gerekmiyor.&lt;/p&gt;

&lt;p&gt;Lab'da bunun demosu, Oracle RAC yerine &lt;strong&gt;OCFS2&lt;/strong&gt; (Oracle Cluster File System v2) kullanan üç VM üzerinden yapılıyor. Yani Oracle RAC'in kendisini değil, aynı multi-writer VMDK'yı paylaşan bir OCFS2 kümesini görüyoruz. WSFC tarafı lab'da hiç gösterilmiyor, sadece kılavuz "destekleniyor" diyor.&lt;/p&gt;

&lt;p&gt;Adımlar:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Multi-writer VMDK'yı görmek.&lt;/strong&gt; &lt;code&gt;ub1&lt;/code&gt; VM'ine sağ tık &amp;gt; &lt;strong&gt;Edit Settings&lt;/strong&gt;, &lt;strong&gt;Hard disk 2&lt;/strong&gt;'yi genişlet, &lt;strong&gt;Sharing&lt;/strong&gt; altında &lt;strong&gt;Multi-writer&lt;/strong&gt; seçili görünüyor. &lt;code&gt;ub2&lt;/code&gt; ve &lt;code&gt;ub3&lt;/code&gt; için de aynı VMDK'ya bağlı olduğunu (Disk File yolu aynı) doğrulayabiliyorsunuz.&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%2Fnb3h8rznb4a7alsd24p6.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%2Fnb3h8rznb4a7alsd24p6.png" alt="ub1 Edit Settings, Hard disk 2, Sharing: Multi-writer" width="689" height="811"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. OCFS2 kümesine bakmak.&lt;/strong&gt; &lt;code&gt;ub1&lt;/code&gt;'in web console'unda sırasıyla:&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;o2cb list-clusters
&lt;span class="nb"&gt;sudo &lt;/span&gt;o2cb cluster-status ocfs2
&lt;span class="nb"&gt;sudo &lt;/span&gt;o2cb list-nodes ocfs2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Birincisi &lt;code&gt;ocfs2&lt;/code&gt; adında tek bir küme olduğunu, ikincisi kümenin online olduğunu, üçüncüsü de üç node'u (&lt;code&gt;ub1&lt;/code&gt;, &lt;code&gt;ub2&lt;/code&gt;, &lt;code&gt;ub3&lt;/code&gt;) 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%2F8wdgpqjr34v7hxhxorms.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%2F8wdgpqjr34v7hxhxorms.png" alt="o2cb komutlarının çıktısı" width="800" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Volume'u görmek.&lt;/strong&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="nb"&gt;sudo df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; /dev/sdb
&lt;span class="nb"&gt;ls&lt;/span&gt; /mnt/ocfs2
&lt;span class="nb"&gt;cat&lt;/span&gt; /mnt/ocfs2/test_file.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;/dev/sdb&lt;/code&gt; cihazı &lt;code&gt;/mnt/ocfs2&lt;/code&gt; altına mount edilmiş ve boyutu &lt;strong&gt;25 GB&lt;/strong&gt;. Klasörde &lt;code&gt;test_file.txt&lt;/code&gt; var ve içinde dosyanın &lt;code&gt;ub1&lt;/code&gt; üzerinde oluşturulduğu yazı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%2F6w3tufmadzf7fo8v4s8p.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%2F6w3tufmadzf7fo8v4s8p.png" alt="df -h /dev/sdb çıktısı, 25 GB" width="800" height="673"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. VMDK'yı büyütmek.&lt;/strong&gt; vCenter'da &lt;code&gt;ub1&lt;/code&gt;'in Edit Settings'inde Hard disk 2'yi &lt;strong&gt;25 GB'dan 30 GB'a&lt;/strong&gt; çıkarıp OK diyorsunuz. VM'ler açık, multi-writer attribute'u olduğu gibi duruyor.&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%2F75naamwtweuq4tjf8vl8.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%2F75naamwtweuq4tjf8vl8.png" alt="Hard disk 2 boyutunu 30 GB yapma ekranı" width="689" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Volume'u genişletmek.&lt;/strong&gt; &lt;code&gt;ub2&lt;/code&gt;'nin console'unda lab'ın hazırladığı bir script var:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./expand_volume.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kılavuz bu script'in &lt;code&gt;tunefs.ocfs2&lt;/code&gt; komutuyla &lt;code&gt;/dev/sdb&lt;/code&gt; volume'unu genişlettiğini söylüyor. Çıktıda volume'un önce 25 GB, script'ten sonra 30 GB olduğu görünüyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Doğrulamak.&lt;/strong&gt; &lt;code&gt;ub2&lt;/code&gt;'de &lt;code&gt;test_file.txt&lt;/code&gt; aynı dosya olarak açılıyor. Sonra &lt;code&gt;ub1&lt;/code&gt;'in console'unda &lt;code&gt;sudo df -h /dev/sdb&lt;/code&gt; çalıştırınca yeni boyutun (30 GB) orada da göründüğünü teyit ediyorsunuz. &lt;code&gt;ub3&lt;/code&gt; için de aynısı yapılabilir. Ben ikinci kez çalıştırdığım için &lt;code&gt;Confirming Current Volume Size&lt;/code&gt; da 30GB 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%2F61yghsywxuqtwvpmqkj7.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%2F61yghsywxuqtwvpmqkj7.png" alt="ub2'de expand_volume.sh çıktısı, 25 GB'dan 30 GB'a" width="705" height="431"&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%2F8lrx6mpqmguzeiuwtxl1.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%2F8lrx6mpqmguzeiuwtxl1.png" alt="ub1'de df -h /dev/sdb, 30 GB" width="705" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu, sistem tarafı için en somut kazanım gibi duruyor. Kılavuz bunu 9.1'in yeni bir yeteneği olarak sunuyor, yani öncesinde bu işi kesintisiz yapmak mümkün değildi ya da desteklenmiyordu, ama önceki sürümlerde tam olarak ne olduğunu kılavuz anlatmıyor. Burada üç VM çalışırken disk büyüyor. Ama burada iki şeye dikkat edilmeli. Birincisi, volume genişletme adımını bir script yapıyor ve kılavuz script'in içini göstermiyor. Yani &lt;code&gt;tunefs.ocfs2&lt;/code&gt; ile ne yapıldığını ve gerçek bir Oracle RAC kurulumunda (ASM gibi) bu adımların nasıl olacağını lab'dan çıkaramıyorum. İkincisi, VMDK'yı vSphere tarafında büyütmek bu özelliğin kolay kısmı, asıl iş guest OS tarafında yürüyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Genel olarak neler dikkatimi çekti
&lt;/h2&gt;

&lt;p&gt;Birkaç şey kafamda kaldı.&lt;/p&gt;

&lt;p&gt;İlk olarak, bu modüllerin ikisi de &lt;strong&gt;"donanım ya da yazılım maliyetini düşür"&lt;/strong&gt; mesajı veriyor. Memory Tiering DRAM maliyetini, global dedup disk kapasitesini hedefliyor. Mantıklı. Ama ikisinin de "faydası" iş yükünüze bağlı ve lab'ın küçük, temiz ortamında bu faydayı ölçemiyoruz.&lt;/p&gt;

&lt;p&gt;İkincisi, &lt;strong&gt;kısıtlar kılavuzda açıkça yazılıyor&lt;/strong&gt; ve asıl okunması gereken yer orası. Thick VM'lerin dedup dışı kalması, global dedup sonrası stretched cluster'a geçilememesi, Memory Tiering'in varsayılan kapalı olması. Bunları okumadan "9.1'e geçince hepsini açarım" demek yanlış olur.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, &lt;strong&gt;bu iki modül de aslında tanıtım&lt;/strong&gt;. Memory Tiering'i açmadık, Auto-RAID policy'si oluşturmadık, dedup'u kendimiz açmadık (zaten açık geldi). Gerçekten uygulamalı olan tek kısım Hot Extend'di. Kılavuz Memory Tiering için ayrı bir lab'a (HOL-2703-01-VCF-L) yönlendiriyor, bu da konunun bir tur kadarıyla anlaşılmayacağını kabul ediyor gibi.&lt;/p&gt;

&lt;p&gt;Son olarak, her zamanki gibi: bu yazıdaki her şey lab ortamında, küçük ve temiz bir kurulumda gördüklerime dayanıyor. Production'da ölçek, iş yükü ve alışkanlıklar işi değiştirir. Memory Tiering, vSAN ESA ya da clustered uygulama işletenler "şu aslında böyle olmuyor" derse öğrenmek isterim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seri hakkında
&lt;/h2&gt;

&lt;p&gt;HOL-2701-01 ile üç yazıda HOL'ın ilk laboratuvarını bitirmiş oldum: arayüz ve VCF Operations, VCF Automation, sonra Memory Tiering ve vSAN. Genel izlenimim, 9.1'in "her şeyi tek platformdan yönet" fikrini sertleştirdiği yönünde. Log, güvenlik, sertifika, namespace, policy, hepsi VCF Operations ve Automation etrafında toplanıyor. Bir sistemci olarak bunun getireceği kolaylığı da, getireceği bağımlılığı da görebiliyorum.&lt;/p&gt;

&lt;p&gt;Katalogda daha ayrıntılı lab'lar var, kılavuzun kendisi bile Memory Tiering için başka bir lab öneriyor. Onlara bakarsam yine buradan yazarım.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri VMware HOL ortamı (HOL-2701-01-VCF-L) üzerinden yürütülmektedir. Buradaki gözlemler lab bağlamında değerlendirilmeli, production kararları için resmi VMware dokümantasyonu ve deneyimli mühendisler referans alınmalıdır.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>VCF 9.1 Automation: Namespace Self-Service, Namespace Capture ve Infrastructure Policies (Modül 2)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Fri, 09 Oct 2026 05:46:25 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/vcf-91-automation-namespace-self-service-namespace-capture-ve-infrastructure-policies-modul-2-3eha</link>
      <guid>https://dev.to/hakanbaban53/vcf-91-automation-namespace-self-service-namespace-capture-ve-infrastructure-policies-modul-2-3eha</guid>
      <description>&lt;p&gt;Önceki modülde HOL-2701-01 serisine VCF 9.1'in yeni menüleri ve VCF Operations tarafıyla başlamıştım. Operations modülünde çoğunlukla ekran gezdik, burada gerçekten bir şeyler oluşturuyoruz: namespace açıyoruz, bir namespace'i blueprint'e çeviriyoruz, tag ve policy zinciri kurup VM'in başka bir host'a kendiliğinden taşınmasını izliyoruz.&lt;/p&gt;

&lt;p&gt;Her zamanki not: bunları sahadan değil, HOL ortamından yazıyorum. Production'da VCF Automation işletmedim. Lab'da gördüklerimi, "bunu gerçek bir ortamda kullanacak olsam ne sorardım" gözüyle okumaya çalıştım. Yanlış yorumladığım yer olursa yorumlarda düzeltirseniz sevinirim.&lt;/p&gt;

&lt;p&gt;Kılavuz dört bölümden oluşuyor: Namespace Self-Service, Namespace Capture, Infrastructure Policies ve Service Framework. Sırayla gidiyorum.&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%2Fh49k47xw2vdssed9m7p9.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%2Fh49k47xw2vdssed9m7p9.png" alt="Lab konsolunda VCF Automation Organization portal giriş ekranı" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Önce roller: bu modülde üç farklı kişi var
&lt;/h2&gt;

&lt;p&gt;Bu modülü takip ederken en çok işime yarayan şey, kimin hangi portalda ne yaptığını baştan netleştirmek oldu. Çünkü lab sürekli portal değiştiriyor ve ne zaman hangi hesapla girdiğinizi karıştırmak kolay.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provider admin:&lt;/strong&gt; VCF Automation Provider portalında çalışıyor. Infrastructure Policy'leri burada tanımlıyor, Organization'lara Region Quota üzerinden atıyor, servisleri (Service Management) yönetiyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organization admin:&lt;/strong&gt; Organization portalında (lab'da ACME). Ağları, namespace class'larını, namespace servislerini sahipleniyor ve project'lere self-service'i açıyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project admin:&lt;/strong&gt; Kendi project'i sınırları içinde, org admin'in izin verdiği kaynaklarla namespace oluşturuyor, blueprint yayınlıyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bu ayrım bana vCenter'daki "herkes admin" alışkanlığından farklı geldi. Self-service'in mantığı bu: org admin çerçeveyi çiziyor, project admin o çerçevenin içinde istediği gibi hareket ediyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespace Self-Service
&lt;/h2&gt;

&lt;p&gt;Kılavuzdaki girişte iş akışı şöyle anlatılıyor: ağlar, namespace class'ları ve namespace servisleri org admin tarafından sağlanıyor. Project admin'ler bunları kendi project'leri sınırları içinde kullanıyor. Namespace oluşturabilmeleri için önce org admin'in o project için self-service'i yapılandırması gerekiyor. Bu ayarlar, hangi paylaşılan kaynakların ve hangi şablonların kullanılabileceğini belirliyor.&lt;/p&gt;

&lt;p&gt;Lab'da bu kurulum zaten yapılmış halde geliyor. Yani org admin'in self-service'i nasıl açtığını görmüyoruz, sadece yapılmış ayarlara bakıyoruz. Bunu not düşmek istiyorum, çünkü gerçek ortamda en çok emek harcanacak yer bence orası.&lt;/p&gt;

&lt;p&gt;Ayarlara şuradan ulaşıyorsunuz: &lt;strong&gt;Manage &amp;amp; Govern &amp;gt; default-project &amp;gt; Namespace Self-Service&lt;/strong&gt; sekmesi.&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%2Fzgyk9ir2mu9ndczs8h87.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%2Fzgyk9ir2mu9ndczs8h87.png" alt="Manage &amp;amp; Govern altında default-project detayı" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sekmede şu bölümler var:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Associated Regions:&lt;/strong&gt; Namespace'lerin hangi region'larda oluşturulabileceği.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Associated Namespace Classes:&lt;/strong&gt; Önceden tanımlanmış boyutlar. Project admin bunları değiştiremiyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Associated VPCs:&lt;/strong&gt; Namespace oluştururken seçilebilecek paylaşılan VPC'ler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Associated Connectivity Profiles:&lt;/strong&gt; Bu profil seçilirse namespace için ayrı (dedicated) bir VPC oluşturuluyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Associated Subnets:&lt;/strong&gt; Namespace oluştururken seçilebilecek önceden tanımlı subnet'ler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure Policies:&lt;/strong&gt; Varsa project'e buradan bağlanıyor. Bu konuya modülün ortasında geri döneceğiz.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Associated Service Engine Groups:&lt;/strong&gt; Avi Load Balancer'dan Service Engine Group tüketmek için.&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%2Fubqvhw8opm9mi5a41605.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%2Fubqvhw8opm9mi5a41605.png" alt="Namespace Self-Service sekmesi, Regions ve Namespace Classes bölümü" width="800" height="105"&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%2Fxabfvinpt7cm0b1x150y.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%2Fxabfvinpt7cm0b1x150y.png" alt="Namespace Self-Service sekmesi, VPC, Connectivity Profile, Subnet ve Policy bölümleri" width="799" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Yeni namespace oluşturmak
&lt;/h3&gt;

&lt;p&gt;Sonra kılavuz bir namespace açtırıyor: &lt;strong&gt;Namespaces &amp;gt; New Namespace&lt;/strong&gt;. Sihirbazdaki alanlar şöyle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;İsim: &lt;code&gt;sales&lt;/code&gt; (isim kurallarına dikkat edin diyor).&lt;/li&gt;
&lt;li&gt;Namespace class: &lt;code&gt;small&lt;/code&gt;. Sağ tarafta seçilen class'a göre kaynak sınırları değişiyor.&lt;/li&gt;
&lt;li&gt;Region: &lt;code&gt;us-west&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Zone: &lt;code&gt;z-wld-a&lt;/code&gt;. Namespace'e ayrılan kaynaklar seçilen region'daki bir ya da birden fazla zone'dan geliyor.&lt;/li&gt;
&lt;li&gt;Networking: &lt;strong&gt;Shared VPC&lt;/strong&gt; (diğer seçenek Dedicated VPC) ve VPC olarak &lt;code&gt;default-us-west&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Shared subnet: lab'daki hazır subnet.&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%2F01mh0g6l4zhhbdjwpocd.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%2F01mh0g6l4zhhbdjwpocd.png" alt="New Namespace sihirbazı, class, region, zone ve VPC seçimleri" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Namespace hazır olunca sağ taraftaki detay panelini açıyorsunuz. Burada VM class'larını (ekleyip çıkarabiliyorsunuz), storage class'ı ve storage limitini (EDIT ile), infrastructure policy ayarını ve kullanılabilir servisleri görü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%2Fwjh0a657sfjix1i95e5t.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%2Fwjh0a657sfjix1i95e5t.png" alt="Oluşturulan namespace'in detay paneli, VM Classes, Storage Class ve Services" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada aklıma gelen sorular şunlar: Namespace class'larının sınırları ne kadar katı? Bir project admin kaç namespace açabilir, toplam limit nerede uygulanıyor? Lab bunları göstermiyor, sadece "oluşturdum, hazır" noktasına kadar götürüyor. Bir de dedicated VPC seçeneğini denemedik, sadece shared VPC kullandık.&lt;/p&gt;

&lt;p&gt;Kılavuzun bu bölümün sonunda söylediği şey şu: bu özellik, namespace'i VM ya da ağ gibi bir kaynak olarak istemeyi mümkün kılıyor ve bir sonraki özelliğin (Namespace Capture) temeli.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespace Capture
&lt;/h2&gt;

&lt;p&gt;Bence modülün en ilginç kısmı bu. Kılavuzun tanımı şöyle: çalışan bir namespace'i (VPC, VM'ler, diskler, subnet'ler, load balancer'lar ve ayarları dahil) alıp standart bir VCF Automation blueprint'ine, yani YAML'a çeviriyor. Bu blueprint versiyonlanıp catalog item olarak yayınlanabiliyor ve yetkili project kullanıcıları orijinalin birebir, bağımsız bir kopyasını isteyebiliyor.&lt;/p&gt;

&lt;p&gt;Kılavuz bir de şunu söylüyor: 9.1 öncesinde blueprint'leri elle YAML olarak yazmanız gerekiyordu, bilinen bir namespace'i "kaydedip" dağıtılabilir bir şeye çevirmenin yolu yoktu. Şimdi project admin iş yükünü gerçek bir namespace'te kuruyor, doğruluyor ve blueprint'i VCF Automation üretiyor. Test/dev/lab ortamlarını "golden" bir şablondan tekrar tekrar basmak için düşünülmüş.&lt;/p&gt;

&lt;p&gt;Proxmox otomasyon serisinde Terraform ve Ansible ile zero-touch VM provisioning yazmıştım. Orada her şeyi elle tanımlamanız gerekiyor ve bu işin asıl emeği. Burada ise tersini yapıyor: önce çalışan bir ortam kuruyorsunuz, sonra ondan tanım çıkarıyorsunuz. Hangi yaklaşımın daha iyi olduğunu söylemek için erken. Ama bu üretilen YAML'ın Git gibi bir akışa nasıl oturduğunu merak ediyorum, lab bunu göstermiyor. Blueprint ve versiyonlar VCF Automation'ın içinde tutuluyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Capture öncesi gerekenler
&lt;/h3&gt;

&lt;p&gt;Kılavuz ön koşulları açıkça sayıyor, ben de aynen aktarayım çünkü gerçek hayatta bunlar işi belirler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Org admin'in o project için Namespace self-service'i açmış olması.&lt;/li&gt;
&lt;li&gt;Namespace ile ilişkili en az bir project content library olması. Yakalanan VM image'ları buraya kaydediliyor. Project content library OVA/OVF destekliyor, ISO ve çoklu VM içeren OVA desteklenmiyor.&lt;/li&gt;
&lt;li&gt;Namespace içinde tam olarak bir VM Group olması ve namespace'teki her VM'in bu gruba ait olması.&lt;/li&gt;
&lt;li&gt;Tüm VM'lerin başlatılmış (initialized) ve capture anında &lt;strong&gt;kapalı&lt;/strong&gt; olması, veri tutarlılığı için.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;İki kısıt da var: &lt;strong&gt;VKS cluster içeren namespace'ler capture edilemiyor.&lt;/strong&gt; vSphere pod içeren namespace'ler capture edilebiliyor ama pod'lar blueprint'e dahil olmuyor.&lt;/p&gt;

&lt;p&gt;Bu kısıtlar bana şunu düşündürdü: çalışan bir uygulama ortamını "yakalamak" için VM'leri kapatmanız gerekiyor. Golden bir lab ortamı için sorun değil, ama canlı bir ortamı kopyalamak için değil. VKS'in capture dışında kalması da, Kubernetes ağırlıklı bir kurulumda bu özelliğin kapsamını ciddi biçimde daraltabilir.&lt;/p&gt;

&lt;h3&gt;
  
  
  İki capture türü
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capture as an identical copy:&lt;/strong&gt; Namespace'i birebir yeniden üretiyor: namespace class ve region, VPC connectivity profile ve private CIDR'lar, VM donanımı (VM class, sanal BIOS, NIC IP/MAC), ağ ve storage ayarları. Bootstrap alanları temizleniyor ki guest customization tekrar çalışmasın. Referans verilen secret'lar yeniden oluşturulmuyor. "Bana bundan bir tane daha ver, aynısı olsun" durumu için.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Capture with customizations:&lt;/strong&gt; Aynısını yapıyor ama catalog'dan isteyen kişiye VM başına guest OS ayarları açıyor: hostname, parola (kullanıcının girdiği ya da otomatik üretilen, isterseniz ilk girişte değiştirmeye zorlayan), pre/post script'ler (Windows'ta Sysprep GuiRunOnce ya da PowerShell, Linux'ta LinuxPrep shell script'leri) ve Windows Active Directory domain join. Her dağıtımın benzersiz olması ya da domain'e katılması gerektiğinde.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Domain join seçeneğini görünce bir sistemci olarak rahatladım. Çünkü "aynı VM'den on tane" fikrinin ilk takıldığı yer hep hostname, SID ve domain oluyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lab'da yaptıklarım
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. VM Group oluşturmak.&lt;/strong&gt; Build &amp;amp; Deploy &amp;gt; Virtual Machine &amp;gt; VM Groups &amp;gt; &lt;strong&gt;+NEW VM GROUP&lt;/strong&gt;. Sihirbazda Power State'i Powered Off yapıyorsunuz, listeden VM'i seçiyorsunuz, start order adımını geçiyorsunuz ve bitiriyorsunuz. VM açıksa grup oluşturulurken kapatı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%2Fm3qnk2i4xfv86av78krg.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%2Fm3qnk2i4xfv86av78krg.png" alt="VM Groups sekmesi, New VM Group sihirbazı" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Ekran görüntüsündeki &lt;code&gt;[object Object]&lt;/code&gt; ifadesi web arayüzündeki bir görüntüleme hatası: arayüz bir metin beklerken nesne almış. İşleyişi etkilemiyor, sihirbaz normal şekilde devam ediyor.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;2. Capture'ı başlatmak.&lt;/strong&gt; Namespace Overview &amp;gt; &lt;strong&gt;CAPTURE AS A BLUEPRINT&lt;/strong&gt;. Önce bir dizi precheck çalışıyor. Başarısız olan olursa burada raporlanıyor, hepsi geçerse Capture Wizard'a devam ediyorsunuz.&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%2Ff2mkfxnyjr5dp48886h2.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%2Ff2mkfxnyjr5dp48886h2.png" alt="Capture Prechecks ekranı" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Blueprint detayları.&lt;/strong&gt; İsim olarak &lt;code&gt;HOL Namespace Capture&lt;/code&gt;, content library olarak &lt;code&gt;ACME Default Project Library&lt;/code&gt; seçiyorsunuz, türü &lt;strong&gt;Capture with customizations&lt;/strong&gt; yapıyorsunuz ve guest customization'ı açıyorsunuz. Sonra VM kaynağını seçip &lt;strong&gt;CONFIGURE&lt;/strong&gt; diyorsunuz. Lab'da parola seçeneği olarak &lt;strong&gt;User specified password&lt;/strong&gt; seçiliyor. Sonra Next ve &lt;strong&gt;CAPTURE&lt;/strong&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%2Fggsa16l5czfmv4p6p6lv.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%2Fggsa16l5czfmv4p6p6lv.png" alt="Blueprint Details, Capture with customizations seçili" width="800" height="405"&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%2Fzbz0k0124j5r47xu7j7w.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%2Fzbz0k0124j5r47xu7j7w.png" alt="VM için Configure ekranı, User specified password" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. İzlemek.&lt;/strong&gt; &lt;strong&gt;Recent Captures&lt;/strong&gt; sekmesinde durumu görü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%2F47vuet516y0fuj7px8sq.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%2F47vuet516y0fuj7px8sq.png" alt="Recent Captures sekmesi" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Blueprint ile catalog item farkı
&lt;/h3&gt;

&lt;p&gt;Kılavuzun burada anlattığı ayrım önemli: capture bir &lt;strong&gt;blueprint&lt;/strong&gt; üretiyor, yani versiyonlanabilen ve düzenlenebilen bir YAML tasarım dosyası. Bunu yayınlamak ayrı bir adım. Blueprint'i açıp Version diyorsunuz, bir versiyon numarası ve açıklama giriyorsunuz, "Publish this version to the catalog" seçeneğini açıp Create diyorsunuz. Bir blueprint'in çok versiyonu olabilir ama catalog'da sadece yayınladıklarınız görünüyor.&lt;/p&gt;

&lt;p&gt;Bunun mantığı şu: tasarımı (YAML'ı düzenleyip tekrar capture edip versiyonu artırarak) mevcut kullanıcıları bozmadan geliştirebiliyorsunuz, hangi versiyonun dağıtımda olduğunu kontrol ediyorsunuz, belirli versiyonları organization'ınızdaki başka project'lerle ya da başka VCF Automation organization'larıyla paylaşabiliyorsunuz. Catalog item olmadan blueprint'e sadece org admin'ler ve project admin'ler ulaşıyor, project kullanıcıları isteyemiyor.&lt;/p&gt;

&lt;p&gt;Lab'da: &lt;strong&gt;Blueprint Design &amp;gt; HOL Namespace Capture&lt;/strong&gt; diyerek blueprint'i açıyoruz. Topology diyagramını ve YAML'ı inceliyoruz. Kılavuzun vurguladığı şey, capture'ın standart VCF Automation YAML'ı üretmesi. Sonra &lt;strong&gt;VERSION&lt;/strong&gt; &amp;gt; versiyon &lt;code&gt;1&lt;/code&gt;, açıklama &lt;code&gt;Initial Capture Catalog Item&lt;/code&gt;, &lt;strong&gt;Publish this version to the catalog&lt;/strong&gt; açık &amp;gt; &lt;strong&gt;CREATE&lt;/strong&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%2F99nqbgqtyg4k2j3vpzs5.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%2F99nqbgqtyg4k2j3vpzs5.png" alt="Blueprint Design, capture diyagramı (topology) ve Capture'ın ürettiği YAML" width="800" height="433"&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%2Fppii39cqbinp9rrx3e2j.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%2Fppii39cqbinp9rrx3e2j.png" alt="Create Version ekranı, Publish this version to the catalog" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Catalog'dan dağıtmak
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Catalog&lt;/strong&gt; sayfasında &lt;code&gt;HOL Namespace Capture&lt;/code&gt; item'ında &lt;strong&gt;REQUEST&lt;/strong&gt; diyorsunuz, dağıtım adı (&lt;code&gt;HOL Deployment 1&lt;/code&gt;) ve VM parolası giriyorsunuz, &lt;strong&gt;SUBMIT&lt;/strong&gt;. Dağıtım birkaç dakika sürüyor.&lt;/p&gt;

&lt;p&gt;Bittiğinde dağıtımın özetini görüyorsunuz: Power State, IP adresi, VM Class. Kılavuzun bu noktada dikkat çektiği bir şey var: gördüğünüz IP, VM'in namespace'in özel ağındaki IP'si ve &lt;strong&gt;routable değil&lt;/strong&gt;. VM'e ulaşmak için VM Load Balancer'a bakmanız gerekiyor. Topology sekmesinde &lt;code&gt;vmService_vm_lb_...&lt;/code&gt; öğesine tıklayıp Load Balancer Ingress IP'yi alıyorsunuz, sonra terminalden SSH ile bağlanı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%2Ff6xgag17dd60383jwqvl.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%2Ff6xgag17dd60383jwqvl.png" alt="Deployment tamamlandı, VM özeti" width="800" height="433"&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%2Fp95guxc0h4is4k1icqpx.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%2Fp95guxc0h4is4k1icqpx.png" alt="Topology sekmesi, VM load balancer ve ingress IP" width="800" height="433"&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%2Fxgg9htyybgt4bz5ogoxl.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%2Fxgg9htyybgt4bz5ogoxl.png" alt="SSH ile VM'e bağlantı" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada gözüme batan şey şu: yeni dağıtılan VM'e ulaşmak için ilk bakacağınız yer olan IP, erişilemeyen IP. Bunu bilmeyen biri bir süre uğraşabilir. Ayrıca ben bu bölümde sadece tek VM'li bir namespace capture ettim. Birden fazla VM, birden fazla disk ya da gerçek bir uygulama yığını yok. "Golden dev/test ortamını basma" iddiası kâğıt üzerinde güçlü, ama lab bunu tek VM ile gösteriyor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infrastructure Policies
&lt;/h2&gt;

&lt;p&gt;Bu bölüm en uzun kısım (yaklaşık 50 sayfa) ve zincirleme çok adımı olduğu için ayrıca anlatmaya değer.&lt;/p&gt;

&lt;p&gt;Kılavuzun tanımı: Infrastructure Policy'ler, cloud admin'in hizmet seçeneklerini ayırması (CPU yoğun ya da yüksek bellekli profiller gibi) ve lisans uyumluluğu için host yerleşimini yönetmesi için bir mekanizma. Bir Infrastructure Policy, bir VM'in hangi host'a ya da host grubuna yerleşeceğini tanımlıyor. VM-host affinity kurallarını uygulamak için. Policy'ler VCF Automation'da oluşturuluyor ve Region Quota üzerinden Organization'lara atanıyor.&lt;/p&gt;

&lt;p&gt;İki uygulama biçimi var:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mandatory:&lt;/strong&gt; Organization'a zorunlu atanırsa, o organization'da oluşturulan her namespace'e otomatik uygulanıyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional:&lt;/strong&gt; Org admin ya da project admin namespace oluştururken/güncellerken opsiyonel policy listesinden seçiyor, kullanıcılar da iş yükü dağıtırken bunlardan seçiyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lab sadece &lt;strong&gt;optional&lt;/strong&gt; policy'leri gösteriyor. Mandatory olanlar ve bunları otomatik uygulayan criteria builder için kılavuz "gelecekteki bir modül" diyor. Bunu açıkça yazıyorum, çünkü zorunlu uygulama production'da asıl merak edilen kısım ve burada görmüyoruz.&lt;/p&gt;

&lt;p&gt;Policy'ler arkada vCenter Compute Policy'lerini kullanıyor. Kılavuzdaki dört adımlı akış şöyle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tag oluşturma:&lt;/strong&gt; VCF Operations'ın tag özelliğiyle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute Policy:&lt;/strong&gt; Bu tag'leri vCenter'da bir Compute Policy'ye bağlamak.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure Policy tanımı:&lt;/strong&gt; VCF Automation Provider portalında.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uygulama:&lt;/strong&gt; Organization'ların Region Quota'sına eklemek.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Yani tek bir özellik için dört farklı yerde çalışıyorsunuz. Bu bana zincirin her halkasının sahibinin kim olduğu sorusunu getirdi: tag'ler platform ekibinde mi, vCenter policy'leri sanallaştırma ekibinde mi, Automation tarafı başka bir ekipte mi? Lab bunu tek kişinin yaptığı bir egzersiz olarak gösteriyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Tag'ler (VCF Operations)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Manage &amp;gt; Tags &amp;gt; Tag Definitions &amp;gt; + CREATE.&lt;/strong&gt; Category adı &lt;code&gt;infrastructure&lt;/code&gt;, altına üç tag: &lt;code&gt;backup&lt;/code&gt;, &lt;code&gt;disaster-recovery&lt;/code&gt;, &lt;code&gt;production&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%2Fnnp5tuy8ntodnq8o08st.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%2Fnnp5tuy8ntodnq8o08st.png" alt="Tag Definitions, infrastructure kategorisi ve üç tag" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sonra bu kategorileri vCenter'lara gönderiyorsunuz: &lt;strong&gt;PUSH CATEGORIES&lt;/strong&gt; &amp;gt; ilgili vCenter'ı seç (lab'da &lt;code&gt;wld01-a&lt;/code&gt;) &amp;gt; &lt;strong&gt;PUSH&lt;/strong&gt;. Kılavuz, tag kategorilerini tek seferde birden fazla vCenter'a push edebildiğinizi özellikle vurguluyor. Çok vCenter'lı ortamlarda tek tek tag kategorisi oluşturmak zorunda kalmamak güzel.&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%2Fxf764slzqhs8kxztn6nm.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%2Fxf764slzqhs8kxztn6nm.png" alt="Push Categories, vCenter seçimi" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ardından &lt;strong&gt;Tag Assignments&lt;/strong&gt; sekmesinde filtre uyguluyorsunuz: VCF Components altında &lt;code&gt;wld01-a&lt;/code&gt;, Object Types altında Host. Atamalar şöyle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listelenen tüm host'lara &lt;code&gt;infrastructure:backup&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;esx-05a&lt;/code&gt; host'una &lt;code&gt;infrastructure:disaster-recovery&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;esx-06a&lt;/code&gt; ve &lt;code&gt;esx-07a&lt;/code&gt; host'larına &lt;code&gt;infrastructure:production&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Her atamada Assign Tags penceresinde seçilen nesneleri kontrol edebiliyorsunuz. Bu tasarım bana mantıklı geldi: backup tag'i tüm host'larda olduğu için, backup ve disaster-recovery policy'lerini birlikte seçen bir VM'in &lt;code&gt;esx-05a&lt;/code&gt;'ya düşmesi beklenir. Bunu kılavuz açıkça yazmıyor, benim yorumum.&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%2Fklucorcoqyhpg9l8ab9g.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%2Fklucorcoqyhpg9l8ab9g.png" alt="Tag Assignments, filtreler ve host seçimi" width="800" height="433"&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%2Fj3vm7i04zult78l87hjg.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%2Fj3vm7i04zult78l87hjg.png" alt="Assign Tags penceresi" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Compute Policy'ler (vCenter)
&lt;/h3&gt;

&lt;p&gt;vCenter'a (workload domain'in &lt;code&gt;vc-wld01-a&lt;/code&gt;'sı) geçiyorsunuz. Önce bir lab ayarı: kümenin vSphere DRS Automation Level'ı lab'daki kaynak kısıtları yüzünden &lt;strong&gt;Partially Automated&lt;/strong&gt; gelmiş. Policy'nin otomatik yerleşimi gösterebilmesi için &lt;strong&gt;Fully Automated&lt;/strong&gt; yapıyorsunuz (Hosts and Clusters &amp;gt; &lt;code&gt;cluster-wld01-01a&lt;/code&gt; &amp;gt; Configure &amp;gt; vSphere DRS &amp;gt; Edit).&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%2F8aosjv4svry8f7gejuzo.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%2F8aosjv4svry8f7gejuzo.png" alt="DRS ayarı, Automation Level Fully Automated" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sonra &lt;strong&gt;Policies and Profiles &amp;gt; Compute Policies &amp;gt; ADD&lt;/strong&gt;. Üç tane &lt;strong&gt;VM-Host affinity&lt;/strong&gt; policy oluşturuyorsunuz:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;backup-vm-host-affinity&lt;/code&gt;: VM tag'i &lt;code&gt;infrastructure:backup&lt;/code&gt;, host tag'i &lt;code&gt;infrastructure:backup&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;disaster-recovery-vm-host-affinity&lt;/code&gt;: VM ve host tag'i &lt;code&gt;infrastructure:disaster-recovery&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;production-vm-host-affinity&lt;/code&gt;: VM ve host tag'i &lt;code&gt;infrastructure:production&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mantık: bu tag'e sahip VM'ler, aynı tag'e sahip host'lara yerleşecek.&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%2Fvxms4heikkrrnbojaikb.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%2Fvxms4heikkrrnbojaikb.png" alt="New Compute Policy, VM-Host affinity ve tag seçimleri" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kılavuz bu policy'lerin "must" mu "should" mu olduğunu belirtmiyor. Bu fark production'da önemli: host arızasında HA'nın bu kuralı çiğneyip çiğneyemeyeceği buna bağlı. Lab'da bunu görmedik.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Infrastructure Policy'ler (VCF Automation Provider portal)
&lt;/h3&gt;

&lt;p&gt;Provider portalında &lt;strong&gt;Infrastructure Policies &amp;gt; vCenter Compute Policies&lt;/strong&gt; sekmesinde üç compute policy'yi görüyorsunuz. Kılavuz bu policy'lerin VCF Automation'da görünmesinin birkaç dakika alabileceğini söylüyor. Sonra &lt;strong&gt;Infrastructure Policies&lt;/strong&gt; sekmesinde &lt;strong&gt;CREATE INFRASTRUCTURE POLICY&lt;/strong&gt; ile &lt;code&gt;backup&lt;/code&gt;, &lt;code&gt;disaster-recovery&lt;/code&gt; ve &lt;code&gt;production&lt;/code&gt; adında üç policy tanımlıyorsunuz, her biri ilgili compute policy'ye bağlı.&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%2Fmdj0gxoeyzbg81gg0wen.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%2Fmdj0gxoeyzbg81gg0wen.png" alt="Provider portal, vCenter Compute Policies sekmesi" width="800" height="433"&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%2Fibx5ysg214qqfp7e0lyv.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%2Fibx5ysg214qqfp7e0lyv.png" alt="New Infrastructure Policy sihirbazı" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Organization'a atamak
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Organizations &amp;gt; Acme &amp;gt; Region Quota &amp;gt; us-west (&amp;gt;&amp;gt;) &amp;gt; Infrastructure Policies &amp;gt; EDIT&lt;/strong&gt;, hepsini seçip &lt;strong&gt;SAVE&lt;/strong&gt;. Sonra &lt;strong&gt;LAUNCH ORGANIZATION PORTAL&lt;/strong&gt; ile org portalına geçiyorsunuz.&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%2Fvxbph1noljfzlq9ihs2h.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%2Fvxbph1noljfzlq9ihs2h.png" alt="Region Quota, Infrastructure Policies bölümü" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Test: namespace ve VM
&lt;/h3&gt;

&lt;p&gt;Org portalında yeni bir namespace açıyorsunuz: &lt;code&gt;production-all-apps&lt;/code&gt;, project &lt;code&gt;default-project&lt;/code&gt;, class &lt;code&gt;small&lt;/code&gt;, region &lt;code&gt;us-west&lt;/code&gt;, zone &lt;code&gt;z-wld-a&lt;/code&gt;, Infrastructure Policies alanında hepsini seçili, VPC &lt;code&gt;default-us-west&lt;/code&gt;. Namespace &lt;strong&gt;Active&lt;/strong&gt; olunca açıp Infrastructure Policies'in atandığını görüyorsunuz.&lt;/p&gt;

&lt;p&gt;Sonra Services altında Virtual Machine servisinden &lt;strong&gt;+ CREATE VM&lt;/strong&gt;: Deploy from OVF, VM adı &lt;code&gt;web-vm&lt;/code&gt;, Infrastructure Policy alanında &lt;strong&gt;backup&lt;/strong&gt; ve &lt;strong&gt;disaster-recovery&lt;/strong&gt;, image &lt;code&gt;hol-ubuntu24&lt;/code&gt;, VM class &lt;code&gt;best-effort-xsmall&lt;/code&gt;, &lt;strong&gt;DEPLOY VM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;VM Ready olunca nesne detayında iki policy'nin atandığını görüyorsunuz. vCenter'da &lt;code&gt;web-vm&lt;/code&gt;'i aratıp açınca, Tags widget'ında vSphere tag'lerini ve Related Objects widget'ında dağıtım konumunu doğruluyorsunuz.&lt;/p&gt;

&lt;h3&gt;
  
  
  Policy değişince VM ne yapıyor?
&lt;/h3&gt;

&lt;p&gt;Lab'ın en iyi gösterdiği şey bu. VM oluştuktan sonra Infrastructure Policy'yi düzenliyorsunuz: &lt;code&gt;disaster-recovery&lt;/code&gt;'yi kaldırıp &lt;code&gt;production&lt;/code&gt;'ı seçiyorsunuz, Save. vCenter'ı yenileyince &lt;code&gt;disaster-recovery&lt;/code&gt; tag'inin yerini &lt;code&gt;production&lt;/code&gt; tag'inin aldığını görüyorsunuz. Tag değiştiği için DRS, VM'i uygun bir host'a taşıyor. Monitor &amp;gt; Tasks altında &lt;strong&gt;Migrate virtual machine&lt;/strong&gt; ve &lt;strong&gt;Reconfigure virtual machine&lt;/strong&gt; görevlerini inceleyebiliyorsunuz.&lt;/p&gt;

&lt;p&gt;Bunu görmek gerçekten iyiydi: policy değişikliği tag'e dönüşüyor, tag DRS'i tetikliyor, VM kendiliğinden taşınıyor. Ama aynı zamanda bir uyarı da: production'da bir policy düzenlemek, o policy'ye bağlı tüm VM'leri taşıyabilir. Kaç VM etkilenir, bunu düzenlemeden önce nasıl görürüm, taşıma sırasında ne olur, lab bunları cevaplamıyor. Üstelik lab'da DRS'i Fully Automated'a çekmemiz gerekti. Partially Automated olan bir ortamda bu akış aynı çalışmaz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Framework
&lt;/h2&gt;

&lt;p&gt;Son bölüm kısa. Provider portalındaki &lt;strong&gt;Service Management&lt;/strong&gt; arayüzüyle, VCF Automation'ı Broadcom'un ve üçüncü tarafların sunduğu servislerle genişletebiliyorsunuz. Bir servis UI plugin'leri, service account'lar, Supervisor Service'ler, roller, rights bundle'lar, runtime defined entity'ler gibi birçok öğe içerebiliyor. İki tür servis var: &lt;strong&gt;VCF services&lt;/strong&gt; (Broadcom'dan, örneğin VMware Data Services Manager ve Secret Store) ve &lt;strong&gt;partner services&lt;/strong&gt; (dış üreticilerden).&lt;/p&gt;

&lt;p&gt;Lab'da &lt;strong&gt;Service Management&lt;/strong&gt; altında &lt;strong&gt;Secret Store Service&lt;/strong&gt;'i buluyorsunuz ve &lt;strong&gt;Install&lt;/strong&gt; diyorsunuz. Sertifikaları kabul ediyorsunuz, tüm region'lara ya da belirli region'lara dağıtmayı seçebiliyorsunuz (lab'da &lt;code&gt;us-west&lt;/code&gt;), servis özelliklerini gözden geçiriyorsunuz (gerekirse elle değiştirilebiliyor) ve son adımda &lt;strong&gt;kurulumu tamamlamadan Cancel&lt;/strong&gt; diyorsunuz.&lt;/p&gt;

&lt;p&gt;Kılavuzun Secret Store tanımı: vSphere Supervisor ortamlarında secret yönetimi için merkezi bir servis. Supervisor ve VKS cluster'larla entegre, yöneticiler, DevOps mühendisleri ve uygulama kiracıları için rol tabanlı erişim sağlıyor, Kubernetes-native API'leri destekliyor.&lt;/p&gt;

&lt;p&gt;Bu bölüm bir ekran turundan ibaret. Kurulumu tamamlamadığımız için servisin nasıl çalıştığını, yükseltmelerin nasıl yapıldığını, partner servislerin destek sınırlarını ve bir servis bozulduğunda ne olacağını göremiyoruz. Soru işaretlerim burada en fazla.&lt;/p&gt;

&lt;h2&gt;
  
  
  Genel olarak neler dikkatimi çekti
&lt;/h2&gt;

&lt;p&gt;İlk olarak, bu modülün ana fikri &lt;strong&gt;self-service'i yönetilebilir hale getirmek&lt;/strong&gt;. Namespace Self-Service, Capture ve Infrastructure Policies'in üçü de aynı yöne bakıyor: platform ekibi çerçeveyi çiziyor, kullanıcı o çerçevenin içinde kendi başına iş görüyor. Mantığını anlıyorum. Ama bu çerçevenin kurulumu lab'da hazır geliyor, yani asıl emeği göremiyoruz.&lt;/p&gt;

&lt;p&gt;İkincisi, &lt;strong&gt;ön koşullar ve kısıtlar&lt;/strong&gt; çok belirleyici. Capture için VM'lerin kapalı olması, tek VM Group, VKS'in dışarıda kalması, ISO ve çoklu VM OVA'nın desteklenmemesi. Bunları okumadan "ortamımı yakalayıp çoğaltırım" demek yanlış olur.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, Infrastructure Policy'lerde &lt;strong&gt;zincirin uzunluğu&lt;/strong&gt;. Tag, compute policy, infrastructure policy, region quota. Her halka ayrı bir yerde ve muhtemelen ayrı bir ekibin elinde. Sorun çıktığında hangi halkada baktığınızı bilmek gerekecek.&lt;/p&gt;

&lt;p&gt;Dördüncüsü, &lt;strong&gt;lab'ın göstermedikleri&lt;/strong&gt;: mandatory policy'ler, DRS'in Fully Automated olmadığı durum, çoklu VM'li capture, Service Framework'ün işletme tarafı. Kılavuz bazılarını kendisi de "gelecek modül" diye erteliyor.&lt;/p&gt;

&lt;p&gt;Son olarak, her zamanki gibi: bu yazıdaki her şey lab ortamında, küçük ve temiz bir kurulumda gördüklerime dayanıyor. Production'da ölçek ve alışkanlıklar işi değiştirir. Orada VCF Automation işletenler "şu aslında böyle olmuyor" derse öğrenmek isterim.&lt;/p&gt;

&lt;p&gt;Gelecek hafta serinin son yazısı: kılavuzun 4. ve 5. modülleri. vSphere'de &lt;strong&gt;Memory Tiering&lt;/strong&gt;, vSAN'da &lt;strong&gt;Global Deduplication, Effective Capacity Reporting&lt;/strong&gt; ve Oracle RAC ile WSFC için &lt;strong&gt;Hot Extend&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri VMware HOL ortamı (HOL-2701-01-VCF-L) üzerinden yürütülmektedir. Buradaki gözlemler lab bağlamında değerlendirilmeli, production kararları için resmi VMware dokümantasyonu ve deneyimli mühendisler referans alınmalıdır.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vcf</category>
      <category>vmware</category>
    </item>
    <item>
      <title>VCF 9.1'de Neler Değişti? Yeni Menü, Health, Log Management ve Fleet Yönetimi (Modül 1)</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Mon, 05 Oct 2026 05:11:57 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/vcf-91de-neler-degisti-yeni-menu-health-log-management-ve-fleet-yonetimi-modul-1-7hk</link>
      <guid>https://dev.to/hakanbaban53/vcf-91de-neler-degisti-yeni-menu-health-log-management-ve-fleet-yonetimi-modul-1-7hk</guid>
      <description>&lt;p&gt;Bir süredir VMware tarafına bakmıyordum. vSAN HOL serisini bitirdikten sonra Proxmox'a geçtim, önce cluster ve Corosync, ardından Terraform ve Ansible ile otomasyon üzerine çalışıp bazı yazılar yazdım. Şimdi VMware HOL'a geri dönüyorum, çünkü katalog değişti.&lt;/p&gt;

&lt;p&gt;VMware, HOL kataloğunu VCF 9.0'dan 9.1'e taşıdı ve 9.0 lab'larının (HOL-26xx) çoğunu kaldırdı. O yüzden yeni katalogdaki ilk lab olan &lt;strong&gt;HOL-2701-01-VCF-L (What's New in VCF 9.1: Highlights)&lt;/strong&gt; ile baştan başlıyorum. Kılavuzda 5 modül var. Bu hafta ilk ikisini, yani arayüz değişikliklerini ve VCF Operations tarafını inceleyeceğim ve gördüklerimi aktaracağım. İlk 104 sayfa bu ikisine denk geliyor. Yazılarda "Modül" dediğim yer serinin haftalarını, "kılavuzun 2. modülü" dediğim yer ise PDF'in kendi bölümlerini anlatıyor, karışmasın diye ayırıyorum.&lt;/p&gt;

&lt;p&gt;Her zamanki not: bu yazıyı sahadan değil, HOL ortamından yazıyorum. Production'da bir VCF fleet'i yönetmedim, yöneten birinin gözüyle bakamam. Ama lab'i bir sistemci gibi okumaya çalıştım. Yani "bu özellik harika" demek yerine "bunu gerçek bir ortamda açmadan önce ne sorardım" diye düşündüm. Yanlış anladığım yer olursa yorumlarda düzeltirseniz sevinirim.&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%2Fsoy0icjvhxma9v8tem4t.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%2Fsoy0icjvhxma9v8tem4t.png" alt="HOL-2701-01 lab konsolunda " width="419" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Önce arayüz: dört ana başlık
&lt;/h2&gt;

&lt;p&gt;VCF Operations'ın ana menüsü artık dört başlığa ayrılmış: &lt;strong&gt;Operate, Manage, Protect, Build&lt;/strong&gt;. Lab'ın ilk modülü bu menülerin içinde dolaşmaktan ibaret. Uygulamalı bir iş yok, tur atıyorsunuz. Ama 9.0'dan geliyorsanız menülerin yerinin değişmesi ilk gün sizi en çok yoracak şey olabilir, o yüzden buraya vakit ayırmaya değer.&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%2Fre0f44sxk9hor1sgx67y.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%2Fre0f44sxk9hor1sgx67y.png" alt="VCF Operations üst menüsü, Operate / Manage / Protect / Build görünür halde" width="539" height="49"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operate&lt;/strong&gt; günlük izleme ve sorun giderme tarafı. Overview altında Compute, Storage ve Network sayfaları var. Lab'a göre Compute yeni bir görünüm, Storage ve Network ise eski "Storage Operations" ve "Network Operations" sayfalarının yeniden adlandırılmış hali. Bunun dışında Inventory, Alerts, Dashboards ve Automation Central duruyor. Workbench'in yanına üç yeni parça eklenmiş: Metrics (özel sorgularla metrik analizi), Logs (entegre log ekranı) ve Flows (ağ akışı analizi). Findings, VCF Health ve Organizations da 9.1 arayüzünde yeni geçiyor. Business Applications ve Green Score da bu menü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%2Fillc9udhegzve0r8wwc0.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%2Fillc9udhegzve0r8wwc0.png" alt="Operate Sayfası Genel Görünüm / İlk İzlenim" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Administration altında Configurations, Integrations, Cloud Proxies, SDDC Manager, Control Plane ve Global Settings var. Bu kısmı not alın, çünkü kılavuzun 2. modülündeki birçok ayar (log yönetimi, realtime metrik politikaları, access control) buraya düşü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%2Ffcek778dqaic3a8rcp85.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%2Ffcek778dqaic3a8rcp85.png" alt="Operate menüsü açık, sol taraftaki alt başlıklar" width="224" height="697"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Manage&lt;/strong&gt; fleet yönetimi: sertifikalar, şifreler, kimlik ve erişim, tag'ler, konfigürasyon yönetimi ve fleet ayarları (şifre politikası, DNS, NTP). Bunun yanında Capacity (Assess, Optimize, Plan), Cost (Showback, Chargeback, Bills) ve Licensing de burada. Lab bu üçüne sadece isim ve tek cümlelik açıklama düzeyinde değiniyor, içine girmiyor.&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%2Fap4p5aruhf090dnf3f9w.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%2Fap4p5aruhf090dnf3f9w.png" alt="Manage Sayfası Genel Görünüm / İlk İzlenim" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protect&lt;/strong&gt; altında Security Operations, Audit Records, Security Posture Management, Compliance ve Protection and Recovery var. İki küçük ayrıntı önemli: "Audit Events" artık &lt;strong&gt;Audit Records&lt;/strong&gt; adını taşıyor, işlev aynı. "Compliance" bölümü ise 9.1'de kullanımdan kaldırılıyor ve Security Posture Management altına taşınıyor. Eski bir ortamda compliance ile uğraştıysanız ya da ona dayanan bir runbook yazdıysanız, bu değişiklik sizi doğrudan ilgilendirir.&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%2Fb8fqso5951vkr7jhymia.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%2Fb8fqso5951vkr7jhymia.png" alt="Protect Sayfası Genel Görünüm / İlk İzlenim" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build&lt;/strong&gt; altında Software Depot, Lifecycle ve Tasks var. Developer Center'da API &amp;amp; SDK'lar ile no-code çalışan Management Pack Builder bulunuyor. Sonradan göreceğiniz gibi realtime metriklerin altyapı bileşenleri de Build &amp;gt; Lifecycle altından açılıyor, yani "Build" sadece geliştirici menüsü değil, platformun kendi bileşenlerinin yönetildiği yer 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%2Fdt2qqki0bopcknlf4xws.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%2Fdt2qqki0bopcknlf4xws.png" alt="Build Sayfası Genel Görünüm / İlk İzlenim" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bu bölümdeki en büyük beklentim, 9.0'dan gelen biri için yerleri bulmayı kolaylaştıran bir eşleşme tablosu olurdu. Lab bunu vermiyor, sadece "şu yeni, şu yeniden adlandı" diyor. Yine de menü haritasını bilmek, kılavuzun 2. modülünü takip etmek için yeterli.&lt;/p&gt;

&lt;h2&gt;
  
  
  Health ve Diagnostics: artık sadece "host düştü mü" demiyor
&lt;/h2&gt;

&lt;p&gt;Kılavuzun 2. modülünün ilk konusu bu. 9.0'da Diagnostic Findings ve VCF Health, "Infrastructure Operations" altındaydı. 9.1'de Operate sayfasının sol menüsüne doğrudan link olarak çıkmış. "Diagnostic Findings" sayfası da sadece &lt;strong&gt;Findings&lt;/strong&gt; adını almış.&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%2Fd3i0ijrjhyp6spualw1m.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%2Fd3i0ijrjhyp6spualw1m.png" alt="Operate sayfası, Active Findings sekmesi seçili" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Findings Catalog sekmesinde sistemin tarattığı tüm kural imzaları listeleniyor. Lab yazıldığı sırada bu sayı &lt;strong&gt;890&lt;/strong&gt;'dı (lab, 9.0'a göre birkaç yüz fazla olduğunu söylüyor). Bunlar özellik ve log bazlı kurallar, Diagnostics Content Management Pack ile de yenileri ekleniyor. Filtreyle bileşene ve önem derecesine göre daraltabiliyorsunuz. Sayı kulağa etkileyici geliyor ama pratikte kritik olan kuralların ne kadar güvenilir ve ne kadar gürültülü çıktığı. Lab bunu ölçmüyor, çünkü ortam küçük ve kontrollü.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VCF Health&lt;/strong&gt; tarafında iki görünüm var: VCF View ve Component View. VCF View, instance'tan başlayıp management domain, workload domain, vCenter, NSX, vSAN ve ESX host'a kadar inen hiyerarşiyi gösteriyor. Component View ise sertifika, NTP, DNS, vCenter, ESX, vSAN, NSX ve VCF Management Services için tile'lar sunuyor.&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%2Ftcgy75pdrysegs85njwp.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%2Ftcgy75pdrysegs85njwp.png" alt="Operate sayfası, VCF Health Sekmesi Seçili, VCF View sekmesi, Summary bölümü" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;9.1'de gözüme en çok çarpan şey &lt;strong&gt;ESX Health&lt;/strong&gt; tile'ı. 9.0'da yalnızca cevap vermeyen host'ları görüyordunuz. Şimdi bağlantı sorunları, servis sorunları, donanım sorunları, PSOD ve kullanım ayrı ayrı sayılıyor. Lab örneğinde 7 donanım sorunu ve 4 PSOD görünüyordu. Detaya girince host tablosunda "Hardware Status Check", "PSOD" ve "Tunnels" gibi sütunlarla hangi host'ta ne olduğunu görüyorsunuz. Sabah ilk baktığım yer bu olurdu.&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%2Ft7c150j5qqr3dy9r013t.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%2Ft7c150j5qqr3dy9r013t.png" alt="ESX Health tile'ı ve View Details sonrası host listesi" width="800" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;İkinci yenilik &lt;strong&gt;vSAN Diagnostics&lt;/strong&gt;. Sağlık sorunlarını Availability, Performance, Capacity ve Compliance başlıklarında topluyor. Lab'ın vSAN ortamında sorun yoktu, o yüzden bu ekranlar boş çıktı ve ne gösterdikleri sadece ekranın yapısından anlaşılıyor. Performance Insights sekmesinde ise gerçekten bir şey çalıştırdık: "Run New Diagnostics" ile hedefi (production kümede sorun giderme veya yeni kümede benchmark) seçiyorsunuz, kümeyi seçiyorsunuz (labda &lt;code&gt;cluster-wld01-01a&lt;/code&gt;), zaman aralığını seçiyorsunuz (son bir saat) ve çalıştırıyorsunuz. Sorun çıkarsa vCenter'daki performans görünümüne ya da Operations içindeki cluster dashboard'una geçiş linki var. Sonucu ben de lab'da sadece gözle inceledim, anlamlı bir bulgu çıkmadı.&lt;/p&gt;

&lt;p&gt;Bu da vSAN serisindeki Modül 2'yi hatırlattı, orada sağlık ve performansa vSphere Client'tan bakmıştık. Burada aynı soruları VCF Operations'tan soruyoruz.&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%2Fbe9w84vhmpp2jr9ytymq.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%2Fbe9w84vhmpp2jr9ytymq.png" alt="vSAN Diagnostics, Performance Insights, Run New Diagnostics ekranı" width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Üçüncüsü &lt;strong&gt;NSX Instances&lt;/strong&gt; tile'ı. Yönetim kümesi durumu, NSX Manager sağlık sorunları, kapasite sorunları, kullanım, Edge ve ESXi host ağ sorunları ayrı ayrı izleniyor. Lab'da iki NSX instance vardı. Büyük bir ortamda filtre kutusunun işe yarayacağını kılavuz da söylüyor. Son olarak &lt;strong&gt;VCF Management Services&lt;/strong&gt; tile'ı var, lab'da 10 servis izleniyordu ve sorun yoktu.&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%2Fhfk5u38gyquak2rcrwn4.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%2Fhfk5u38gyquak2rcrwn4.png" alt="NSX Instances Detail ekranı" width="799" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada kılavuzda geçen bir cümleyi özellikle işaretlemek istiyorum: VCF Health, &lt;strong&gt;sadece VCF Installer ile kurulmuş ortamlarda&lt;/strong&gt; çalışıyor. Sertifika ve konfigürasyon gibi merkezi veriyi bu yolla topluyor, bileşenleri elle eklenmiş ortamlarda bu veri yok. Sahada bir ortama sonradan eklenmiş ya da elle kurulmuş bileşenler olması çok normal. Bu kısıt, "VCF Health herkese yarar" beklentisini daraltıyor ve 9.1'e geçiş planı yaparken ilk kontrol edeceğim şey bu olurdu.&lt;/p&gt;

&lt;h2&gt;
  
  
  Realtime Metrics: 20 saniye ve 2 saniye
&lt;/h2&gt;

&lt;p&gt;Realtime Metrics, belirli metrikler için 20 saniyelik, bazıları için 2 saniyelik veri noktaları getiriyor. Performans tepe noktalarını ve çukurlarını görmek için Workbench &amp;gt; Real Time Analysis altında bakılıyor. Kılavuza göre bu, yeni VCF management services'in bir parçası ve varsayılan olarak açık.&lt;/p&gt;

&lt;p&gt;Lab'da zaten açıktı ama nasıl açıldığını da gösteriyor: Build &amp;gt; Lifecycle &amp;gt; VCF Management &amp;gt; Add Component ile &lt;code&gt;OPS_DATA_PLATFORM&lt;/code&gt; ve &lt;code&gt;VCFMS_METRICS_STORE&lt;/code&gt; bileşenleri ekleniyor. Yani bu özellik Operations'ın içinde bir anahtar değil, altında ek bileşenler çalıştı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%2Fh00g8q36na788nqah5da.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%2Fh00g8q36na788nqah5da.png" alt="Build &gt; Lifecycle &gt; VCF Management, Add Component penceresi" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kullanımı basit. Workbench'te bir nesne arıyorsunuz (lab'da &lt;code&gt;ub3&lt;/code&gt; adlı VM), Real Time Analysis'e giriyorsunuz ve üç sekme çıkıyor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Overview:&lt;/strong&gt; Seçtiğiniz metrik kategorisini (örneğin CPU) grafik olarak gösteriyor. Grafiği PDF olarak kaydedebiliyor, panoya kopyalayabiliyor veya Notes'a ekleyebiliyorsunuz.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top N:&lt;/strong&gt; Bir metrik seçip (lab'da VM Memory Consumed) çalıştırıyorsunuz, en yüksek nesneler listeleniyor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Query:&lt;/strong&gt; Elle sorgu yazabiliyorsunuz ya da Quick Query Builder'ı kullanıyorsunuz. Sample Queries sekmesinde hazır örnekler var, mesela &lt;code&gt;cpu.capacity.usage.HOST&lt;/code&gt;. Kılavuz her örneğin her nesneye uymayacağını da hatırlatı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%2F0ofje7xxmtdwpgue58px.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%2F0ofje7xxmtdwpgue58px.png" alt="Real Time Analysis, Overview sekmesinde CPU grafiği" width="800" height="352"&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%2F006nudgw2xmqkb6269y5.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%2F006nudgw2xmqkb6269y5.png" alt="Custom Query sekmesi, sample query çalıştırılmış, 20 saniyelik noktalar" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Varsayılan açılan paket &lt;strong&gt;Essential&lt;/strong&gt; ve 856 realtime metrik içeriyor. Daha fazlası için &lt;strong&gt;Standard&lt;/strong&gt; seti var. Bunu Operate &amp;gt; Administration &amp;gt; Configurations &amp;gt; Policy Definition altından politika üzerinden açıyorsunuz: Real Time Metrics'i düzenleyip vCenter için State'i "Activated" yapıyorsunuz. Host System için aynısını yaptığınızda ESX Top tarzı &lt;strong&gt;2 saniyelik&lt;/strong&gt; ESXi host metrikleri geliyor. Ayrıca Operate &amp;gt; Dashboards altında bir Real-time metrics Health dashboard'u var.&lt;/p&gt;

&lt;p&gt;Gerçek ortamda bu bölümle ilgili sorularım şunlar: Saklama süresi ne kadar? Depolama ve kaynak maliyeti nedir? Tüm host'lar için 2 saniyelik veri açmak mantıklı mı, yoksa sadece sorun yaşayan küme için geçici mi açılmalı? Lab bunların hiçbirini cevaplamıyor ve ben de uydurmak istemiyorum. Bu sayıları sizlerden duymak isterim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Posture Management
&lt;/h2&gt;

&lt;p&gt;Protect &amp;gt; Security Posture Management, VCF bileşenlerini güvenlik benchmark'larına göre değerlendiren merkezi bir yer. Lab'daki hazır benchmark &lt;strong&gt;VCF 9 General Controls v1.0&lt;/strong&gt; ve 140 kural içeriyor. "View More" ile hangi bileşenden kaç kural geldiğini görüyorsunuz. "Browse More Benchmarks" ile ek benchmark'ları indirip kurabiliyorsunuz.&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%2F72zbxvk6ccxikph9fr8r.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%2F72zbxvk6ccxikph9fr8r.png" alt="Security Posture Management ana sayfası, benchmark kartları ve compliance score" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Benchmark'ın içine girince kuralları isme göre filtreleyebiliyorsunuz (lab'da "session timeout" yazdık), CSV'ye aktarabiliyorsunuz, açık değilse Enable Benchmark ile açıyor ve Run Assessment ile istediğiniz an çalıştırıyorsunuz. View Results'ta genel uyumluluk skoru, bileşen bazlı sonuç ve önem derecesine göre uyumsuz kural sayıları çıkıyor. Seçtiğiniz kurallar için Remediate, Export as CSV ve Generate Report aksiyonları var.&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%2Fgsgfr7351p3pg7gql3qa.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%2Fgsgfr7351p3pg7gql3qa.png" alt="View Results, Overall Compliance Score ve Non-Compliant Results by Severity" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lab'da hiçbir kuralı remediate etmedik, kılavuz da bunu açıkça yazıyor. "Tek tıkla düzeltme" kulağa hoş geliyor ama bir kurala tıklayınca ortamda tam olarak neyin değişeceğini, geri alınıp alınamayacağını ve bakım penceresi gerektirip gerektirmediğini görmeden production'da çalıştırmazdım. Lab bunu göstermediği için sadece "var" diyebiliyorum.&lt;/p&gt;

&lt;p&gt;Bence bu bölümün en gerçekçi kısmı &lt;strong&gt;benchmark'ı klonlayıp düzenlemek&lt;/strong&gt;. "VCF 9 General Controls v1.0"ı klonlayıp &lt;code&gt;HOL VCF 9 General Controls v1.0&lt;/code&gt; adıyla kaydettik. Sonra "login" araması yapıp "The vCenter server should meet max failed login attempts" kuralını Edit Rule ile açtık ve kural değerini değiştirebildiğimizi gördük. Kendi kurumunuzun politikası hazır benchmark'tan farklıysa (ki neredeyse hep farklıdır) hazır kuralı olduğu gibi kullanmanıza gerek yok. Kaydetmeden iptal ettik, o yüzden değiştirdiğimiz bir şey 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%2Fn3jdl4opeeg3l15yqa69.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%2Fn3jdl4opeeg3l15yqa69.png" alt="Clone Benchmark penceresi ve Edit Rule içindeki Rule Value alanı" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Log Management: Aria Operations for Logs'a veda
&lt;/h2&gt;

&lt;p&gt;Bu bölüm 9.1'in en büyük mimari değişikliği gibi duruyor. Log Management artık VCF Operations'ın içinde. &lt;strong&gt;Aria Operations for Logs'un yerini alıyor&lt;/strong&gt;, ayrı bir arayüz ve ayrı bir sanal appliance yok. Altında &lt;strong&gt;OpenSearch&lt;/strong&gt; çalışıyor ve kılavuza göre daha ölçeklenebilir, hata durumlarına karşı daha dayanıklı. Content pack'ler kaldırılmış, içerik management pack'lerin içine alınmış. Deployment, patch, upgrade ve persistent volume boyutlandırma gibi yaşam döngüsü işleri de VCF management services akışına bağlanmış.&lt;/p&gt;

&lt;p&gt;Mimaride üç parça var: &lt;strong&gt;Gateway Pod&lt;/strong&gt; (Envoy, log kaynaklarından gelen trafiği karşılıyor), &lt;strong&gt;Log Processor&lt;/strong&gt; (alma, sorgulama, maskeleme, yönlendirme, filtreleme ve partition işlerini yapıyor) ve &lt;strong&gt;Log Store&lt;/strong&gt; (OpenSearch, indeksleme ve saklama). Hepsi VCF management services kümesi içinde çalışıyor.&lt;/p&gt;

&lt;p&gt;Proxmox otomasyon serisinde rsyslog ile QRadar'a log göndermeyi, disk destekli kuyruğuyla birlikte kendim kurmuştum. Orada toplama, iletme ve kuyruk dayanıklılığı tamamen sizin işiniz. Burada bunların hepsi platformun içinde hazır geliyor. Bu rahatlık güzel, ama aynı zamanda o katmanı ne kadar ayarlayabildiğiniz ve QRadar gibi harici bir SIEM'e log yönlendirmenin nasıl olduğu sorusunu açıyor. Lab bunu göstermiyor.&lt;/p&gt;

&lt;p&gt;Bir de &lt;strong&gt;log standardizasyonu&lt;/strong&gt; var. Eskiden vCenter, ESX gibi ürünler kendi log formatlarını kullanıyordu (çoğu RFC 5424 syslog tabanlıydı). 9.1'de OpenTelemetry prensipleriyle uyumlu ortak bir format geliyor. Log'larla uğraşan biri için bu, ürünler arası arama ve parse etme işini ciddi biçimde kolaylaştırabilir. Ama mevcut Aria Operations for Logs'a yazdığınız sorgular, alarmlar ve dashboard'lar yeni yapıya nasıl taşınıyor, lab'da bunu göremedim.&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%2F61h2xnrqa9nbf5dvrs3k.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%2F61h2xnrqa9nbf5dvrs3k.png" alt="Operate &gt; Logs, Analyze Logs ekranı" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lab'da gezdiğimiz yerler:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log Collection:&lt;/strong&gt; Administration &amp;gt; Configurations &amp;gt; Log Management altında. Log kaynaklarını, agent'ları, agent gruplarını ve entegre load balancer ayarlarını görüyorsunuz. Lab'da yalnızca VCF Operations için log toplama açıktı. Edit ile açınca log seviyesini (info, debug, warning, error) ve hangi log dosyalarının toplanacağını grup bazında ayarlayabiliyorsunuz. Agent sekmesinde tüm VCF bileşenlerinde agent'ın varsayılan olarak kurulu olduğunu ve otomatik agent yükseltmesini açıp kapatabildiğinizi görüyorsunuz. Agent'lar Linux'ta syslog ve cfapi protokolüyle çalışıyor, ayarları web arayüzünden ya da &lt;code&gt;liagent.ini&lt;/code&gt; dosyasından yönetebiliyorsunuz.&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%2Ff7l08ngpq30gq5vv5d54.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%2Ff7l08ngpq30gq5vv5d54.png" alt="Log Collection, Log Sources listesi ve VCF Operations" width="800" height="352"&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%2Fudd5uejsgw3g9m6dx1kr.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%2Fudd5uejsgw3g9m6dx1kr.png" alt="VCF Operations edit ekranı" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fields Library:&lt;/strong&gt; Alanları indeksli ya da indekssiz yapabiliyorsunuz. İndeksli alanlar aramayı hızlandırıyor ama kılavuz, yeniden indekslemenin sistem performansını ve depolamayı geçici olarak etkileyebileceğini açıkça söylüyor. Lab'da bir alanı "Index Field" ile indeksledik. Kendi ortamımda hangi alanları indeksleyeceğime karar vermek için log hacmini bilmem gerekirdi, lab'da bunu test edemedik.&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%2Fkfl62al34xftr3gqm3w4.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%2Fkfl62al34xftr3gqm3w4.png" alt="Fields Library, Index Field penceresi" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Arşivlenmiş log import:&lt;/strong&gt; 9.1'de arşivlenmiş logları geri yükleyebiliyorsunuz, hem yeni Log Management arşivlerinden hem de eski Aria Operations for Logs arşiv konumlarından. Kılavuz iki önemli not düşüyor: Import küçük zaman aralıklarıyla yapılmalı, çünkü depolama %80'in üstüne çıkarsa görev başarısız oluyor. Ayrıca olay sonrası inceleme ve denetim için bu özellik değerli. Lab'da NFS ya da S3 deposu olmadığı için import'u gerçekten yapamadık, sadece formu açıp alanlara baktık (arşive isim, hedef harici depolama, arşiv yolu, zaman aralığı). Compare Logs ekranında import edilen arşivin nasıl görüneceğini de sadece anlatıyorlar.&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%2Fu8ytkop0tjvay40vzgqm.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%2Fu8ytkop0tjvay40vzgqm.png" alt="Log Processing &gt; Log Partition &gt; Initiate New Log Import formu" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Access Control:&lt;/strong&gt; Log verisi kümesine göre kapsam (scope) tanımlayabiliyorsunuz. Mesela bir kullanıcının sadece NSX loglarını görmesini sağlamak için. Lab'da &lt;code&gt;Logs only errors&lt;/code&gt; adında bir scope oluşturup "Text – Contains – error" filtresi verdik. Gerçek bir senaryoda bu scope'u bir kullanıcıya atamanız gerekiyor, lab o adımı yapmıyor. Roller de log yetkilerini kapsayacak şekilde genişletilmiş. Rol düzenleme ekranı menü yapısını (Operate, Manage, Protect, Build) birebir yansıtıyor, hangi alt başlığa kimin erişeceğini seçiyorsunuz.&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%2Fgi2fj51qnv4ky27477y0.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%2Fgi2fj51qnv4ky27477y0.png" alt="Access Control &gt; Scopes, " width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sd_comp_id:&lt;/strong&gt; Yeni formatla gelen bu alan, logları bileşene göre filtrelemeye yarıyor (ops, logs, vidb gibi). Lab'da &lt;code&gt;vmsp&lt;/code&gt;, &lt;code&gt;ops&lt;/code&gt;, &lt;code&gt;logs&lt;/code&gt; ve &lt;code&gt;vidb&lt;/code&gt; bileşenlerinden log geldiğini gördük.&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%2F5x9bkcrgrg2no2avg2a5.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%2F5x9bkcrgrg2no2avg2a5.png" alt="Logs ekranında sd_comp_id alanının dağılımı" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Fleet Management
&lt;/h2&gt;

&lt;p&gt;Son konu, Manage altındaki fleet yönetimi. Dört başlık var.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kimlik ve erişim (IAM/SSO).&lt;/strong&gt; Çok düğümlü bir Identity Broker, harici bir kimlik sağlayıcıyla (AD ya da LDAP) çalışıyor ve vCenter ile NSX gibi bileşenlerde SSO sağlıyor. Manage &amp;gt; Identity &amp;amp; Access &amp;gt; VCF SSO Overview altında akışı ve ön koşulları görüyorsunuz. Asıl yenilik &lt;strong&gt;VCF Roles&lt;/strong&gt;: Tek tek vCenter, NSX, VCF Automation ve VCF Operations'a girip yetki tanımlamak yerine, yetkiyi VCF Operations'tan fleet geneline veriyorsunuz. Arkada bu roller her bileşendeki gerçek rollerle eşleşiyor. Hazır roller var, özel rol de oluşturabiliyorsunuz. Lab'da &lt;code&gt;HOL-VCF-Default&lt;/code&gt; adında bir rol yarattık: vCenter için Administrator, VCF Operations için PowerUser seçtik. İki önemli ayrıntı var: VCF Roles kullanmak zorunlu değil, bileşen bazlı yetkilendirmeye devam edebilirsiniz. Ayrıca sadece 9.1 ve üstü sürümdeki bileşenler VCF rolü atamasını destekliyor.&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%2Fm63g7hbiscznisfik196.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%2Fm63g7hbiscznisfik196.png" alt="VCF Roles, Create New Custom Role adımı, vCenter ve VCF Operations rol seçimi" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sertifikalar.&lt;/strong&gt; Burada 9.1'in "toplu işlem" yeniliği var: Birden fazla sertifika için aynı anda CSR üretme, yenileme, import ve değiştirme. CA tarafında harici Microsoft CA ya da SDDC Manager üzerinde yapılandırılan OpenSSL seçilebiliyor. Kapsam geniş: VCF yönetim bileşenleri, VCF instance'ları (5.2 ve üstü) ve bağımsız vCenter ile ESXi host'ları (8.0 Update 3 ve üstü). Otomatik yenilemeyi açıp kapatabiliyorsunuz. Sertifika yenileme gerçek ortamda zaman kaybettiren, hata yapıldığında servis aksatan bir iş. Toplu yapabilmek burada gerçekten değer katar, ama lab'da bir yenileme çalıştırmadık, sadece ekranları ve seçenekleri gördük.&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%2Fep7sw7qtz75tr4st585z.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%2Fep7sw7qtz75tr4st585z.png" alt="Certificates sayfası, Configure CA for Fleet ve bileşen seçimi sonrası aksiyon menüsü" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Şifre politikaları.&lt;/strong&gt; Uzunluk, karmaşıklık, süre sonu, hesap kilitleme, değiştirme aralığı ve şifre geçmişi için merkezi politika tanımlıyorsunuz. Lab'da &lt;code&gt;MaxExpiration&lt;/code&gt; adında hazır bir politika vardı ve &lt;strong&gt;Non Compliant&lt;/strong&gt; görünüyordu. VCF Operations Component'ine tıklayınca beklenen değer ile mevcut değerin JSON olarak karşılaştırmasını görüyorsunuz. Kılavuz, VCF Operations'ın hazır, düzenlenebilir bir şifre politikasıyla gelmediğini, lab'daki politikanın örnek olarak eklendiğini özellikle belirtiyor. Create Policy ekranına bakıp iptal ettik.&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%2Fsvj0gcfr6a34ko2gnews.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%2Fsvj0gcfr6a34ko2gnews.png" alt="Password Policy listesi, MaxExpiration ve Non Compliant durumu" width="800" height="352"&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%2Fv207r5tnv2mukt0tqgyq.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%2Fv207r5tnv2mukt0tqgyq.png" alt="Not Compliant detayında Desired Value / Current Value JSON karşılaştırması" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Konfigürasyon yönetimi.&lt;/strong&gt; vCenter instance'larının ve vSphere cluster'larının konfigürasyonunu bir şablonla karşılaştırıp &lt;strong&gt;drift&lt;/strong&gt; (sapma) tespit ediyor. Lab'da &lt;code&gt;HOL-vCenter-Template-1&lt;/code&gt; adlı örnek bir şablon vardı. Şablonu açınca konfigürasyon öğelerini gezip JSON'da ilgili yere atlayabiliyor, indirip kopyalayıp düzenleyebiliyorsunuz. Drifts sekmesinde hangi vCenter'a kaç şablon atandığı (VCF Operations politikalarıyla) ve drift durumu görünüyor. Detect Drift ve Download Drifts Status Report aksiyonları var. Şifre politikasında olduğu gibi burada da kılavuz, şablonların hazır gelmediğini, lab için eklendiğini söylüyor. Yani bu özelliği kullanmak için önce kendi "doğru" konfigürasyonunuzu tanımlamanız gerekiyor ve işin asıl emeği orada.&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%2Fiv1nuptl4mv14zxszqn8.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%2Fiv1nuptl4mv14zxszqn8.png" alt="Configuration Templates, HOL-vCenter-Template-1 detayı" width="800" height="352"&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%2Fl2abnnmo9qya69a9c3yq.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%2Fl2abnnmo9qya69a9c3yq.png" alt="Drifts sekmesi, vCenter Instances ve Detect Drift butonu" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Genel olarak neler dikkatimi çekti
&lt;/h2&gt;

&lt;p&gt;Birkaç şey kafamda kaldı.&lt;/p&gt;

&lt;p&gt;İlk olarak, 9.1'in ana fikri "her şey VCF Operations'ta" gibi görünüyor. Log, güvenlik, sertifika, şifre, kimlik, konfigürasyon, hepsi aynı arayüzde. Operasyon tarafında farklı araçlar arasında gezmek zaten yorucu bir iştir, bunu azaltma fikri çok mantıklı. Öte yandan her şeyin tek yerde toplanması, o tek yerin sağlıklı çalışmasına çok bağımlı olmak anlamına geliyor. Realtime metrikler, log yönetimi ve diğerleri VCF management services üzerinde koşuyor. Lab bu altyapının kaynak ihtiyacını, yedeğini ve bakımını anlatmıyor.&lt;/p&gt;

&lt;p&gt;İkincisi, lab'ın "ilk açılışta hiçbir şey yok" durumunu göstermemesi. Şifre politikası, konfigürasyon şablonu ve çoğu benchmark hazır geliyor. Gerçek ortamda önce bunları kurmak, kendi standardınızı belirlemek gerekiyor ve işin büyük kısmı da bu.&lt;/p&gt;

&lt;p&gt;Üçüncüsü, bazı özelliklerin ön koşulları var: VCF Health için VCF Installer kurulumu, VCF Roles için 9.1 ve üstü bileşenler, sertifika yönetimi için belirli sürüm aralıkları. Bunları okumadan "9.1'e geçince hepsi çalışır" diye düşünmek yanlış olur.&lt;/p&gt;

&lt;p&gt;Son olarak, bu yazıdaki her şey lab ortamında, küçük ve temiz bir kurulumda gördüklerime dayanıyor. Production'da ölçek, gürültü ve alışkanlıklar işi değiştirir. Orada deneyimi olan biri "şu aslında böyle olmuyor" derse öğrenmek isterim.&lt;/p&gt;

&lt;p&gt;Gelecek hafta serinin Modül 2'sinde, yani kılavuzun 3. modülünde VCF Automation'a geçiyorum: namespace self-service, infrastructure policy'ler ve service framework.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Bu seri VMware HOL ortamı (HOL-2701-01-VCF-L) üzerinden yürütülmektedir. Buradaki gözlemler lab bağlamında değerlendirilmeli, production kararları için resmi VMware dokümantasyonu ve deneyimli mühendisler referans alınmalıdır.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vcf</category>
      <category>vmware</category>
    </item>
    <item>
      <title>Bir Hafta Sonu Projesi: AWS EC2 Üzerinde V2Ray (3X-UI) ve Cloudflare WARP ile Datacenter IP Engellerini Aşmak</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Mon, 14 Sep 2026 06:30:46 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/bir-hafta-sonu-projesi-aws-ec2-uzerinde-v2ray-3x-ui-ve-cloudflare-warp-ile-datacenter-ip-e0</link>
      <guid>https://dev.to/hakanbaban53/bir-hafta-sonu-projesi-aws-ec2-uzerinde-v2ray-3x-ui-ve-cloudflare-warp-ile-datacenter-ip-e0</guid>
      <description>&lt;p&gt;Bu hafta sonu, elimde AWS Free Tier'ın verdiği 6 aylık (181 gün), 200 dolara kadar kredi ve basit bir sorunla oturdum: kendi proxy sunucumu kurmak istiyordum ama datacenter IP'lerin ChatGPT veya Netflix gibi servislerde nasıl engellendiğini de biliyordum. Bu yazı, o sorunu çözene kadar attığım adımları, karşılaştığım gerçek hataları ve onları nasıl çözdüğümü anlatıyor. Her komut, kendi terminalimden aldığım gerçek çıktılarla birlikte.&lt;/p&gt;

&lt;p&gt;Kurulum, CachyOS (Arch Linux tabanlı) bir istemci üzerinden AWS EC2'ye SSH ile bağlanılarak gerçekleştirildi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adım 1: AWS EC2 ve SSH Kurulumu
&lt;/h2&gt;

&lt;p&gt;İlk adım AWS konsolundan uygun bir sunucu ayağa kaldırmaktı. AWS konsoluna girip EC2 (Elastic Compute Cloud) altında launch instance 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%2F080nmvyp92i8oa6t4thj.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%2F080nmvyp92i8oa6t4thj.png" alt="AWS EC2 konsolu, Launch instance butonuna basılmadan önceki ekran" width="799" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada direkt olarak bana "getting started walkthroughs" önerdi. Fakat ne yaptığımı bildiğim için "Launch without a walkthrough" seçeneğini seçtim.&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%2Fzd4awie8mm1eov79hzpc.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%2Fzd4awie8mm1eov79hzpc.png" alt="AWS'nin önerdiği " width="799" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Evet, burada bizi AWS'nin "Launch an instance" konfigürasyon arayüzü karşıladı. Ben burada bütçe dostu bir çözüm aradığım için, kredi havuzumu az tüketen &lt;code&gt;t3.micro&lt;/code&gt; instance tipini seçili bıraktım. İşletim sistemi olarak da Ubuntu 26.04 LTS'i seçtim. İkisi de Free Tier eligible olarak işaretliydi.&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%2Fxae92esj3c26hpaxn8mc.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%2Fxae92esj3c26hpaxn8mc.png" alt="Launch an instance ekranında t3.micro instance tipinin seçilmesi" width="800" height="604"&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%2Fmipr0lc2uir1aafa1sm2.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%2Fmipr0lc2uir1aafa1sm2.png" alt="İşletim sistemi olarak Ubuntu 26.04 LTS seçimi, Free Tier eligible etiketi" width="799" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Daha sonrasında ise login için Key Pair istedi. Burada "yeni bir key pair oluştur" 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%2F0hr45np8htezlc3fn2js.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%2F0hr45np8htezlc3fn2js.png" alt="Key pair oluşturma ekranı, yeni bir anahtar çifti oluşturma adımı" width="594" height="508"&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%2Fozdk1lizfo1127amqvuo.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%2Fozdk1lizfo1127amqvuo.png" alt="Key pair formatı seçimi, .pem uzantısının işaretlenmesi" width="799" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada anahtarımın .pem uzantılı olduğuna dikkat ettim, çünkü SSH bağlantısında bu formatı kullanacaktım. Sonrasında anahtarı bilgisayarıma indirdi.&lt;/p&gt;

&lt;p&gt;Daha sonrasında ise AWS Network ayarlarında şu Firewall (security groups) kurallarını tanımladım:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH (Port 22) - My IP&lt;/li&gt;
&lt;li&gt;HTTP (Port 80) - Anywhere (panel erişimi için, sonradan kapatılacak)&lt;/li&gt;
&lt;li&gt;HTTPS (Port 443) - Anywhere (V2Ray bağlantısı için)&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%2Fb7420ksjpk5kphksk4dp.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%2Fb7420ksjpk5kphksk4dp.png" alt="Network settings kısmında tanımlanan SSH/HTTP/HTTPS inbound kuralları" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kısaca konfigürasyonum bu şekildeydi; advanced ayarlara falan gerek yoktu. Sadece AWS'de çalışan, internete açık bir IP'si olan (CGNAT arkasında değil) ve fazla kaynak gerektirmeyen basit bir makine yeterliydi. Bu arada "Launch instance"a basmadan önce gözüme takılan çok güzel bir özellik vardı: Preview Code.&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%2Fo26q8xlcte1hgw9drsnu.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%2Fo26q8xlcte1hgw9drsnu.png" alt="Launch instance öncesi " width="529" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Burada, instance hazırlanırken hangi komutların CLI üzerinden çalıştırılacağını gösteriyor. Daha da güzeli, formatı değiştirerek diğer dillerde nasıl kullanılacağını da gösteriyor, örneğin Python SDK için:&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%2Fwrkgmsdmq38u80122mx3.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%2Fwrkgmsdmq38u80122mx3.png" alt="Preview code panelinde dil seçeneği Python SDK'ya çevrilmiş hali" width="529" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Otomasyon script'leri yazarken cidden işe yarayacak bir özellik.&lt;/p&gt;

&lt;p&gt;Şimdi ise launch instance diyelim ve makinemizi AWS tarafından oluşturmaya bırakalım (kısa bir süre):&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%2Fsdq2joyqf0hhy0amequ8.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%2Fsdq2joyqf0hhy0amequ8.png" alt="Instance'ın oluşturulma sürecini gösteren ekran" width="800" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;5 sn falan sürdü.&lt;/p&gt;

&lt;p&gt;İlk dashboard izlenimi:&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%2Fdasj6z64tsxqrmazuzv7.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%2Fdasj6z64tsxqrmazuzv7.png" alt="EC2 instance dashboard'unun ilk görünümü (IPv4, instance state ve diğer sekmeler)" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Benim aşırı fazla bir AWS kullanmışlığım veya bununla ilgili detaylı çalışmalarım yok ama aradığım şeylerin (örneğin IPv4 ve instance state) ve diğer monitoring, security gibi sekmelerin direkt olarak beni karşılaması işimi kolaylaştırdı.&lt;/p&gt;

&lt;p&gt;İstemciden sunucuya ilk bağlantı denemesi:&lt;/p&gt;

&lt;p&gt;İndirdiğim anahtarla (Downloads klasöründen) giriş 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;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; ~/Downloads/aws-key.pem ubuntu@54.93.233.182
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İlk bağlantıda bilinen hostlar listesine ekleme onayı istendi, giriş sorunsuz sağlandı:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The authenticity of host '54.93.233.182 (54.93.233.182)' can't be established.
ED25519 key fingerprint is: SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Welcome to Ubuntu 26.04 LTS (GNU/Linux 7.0.0-1006-aws x86_64)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Evet. Uzak EC2 makinemizin içindeyiz. Artık kuruluma geçebiliriz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adım 2: 3X-UI Panel Kurulumu ve İlk Engeller
&lt;/h2&gt;

&lt;p&gt;Sunucuya girdikten sonra root yetkisi aldım ve 3X-UI (V2Ray/Xray yönetim paneli) kurulum script'ini ç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="nb"&gt;sudo &lt;/span&gt;su -
bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-Ls&lt;/span&gt; https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kurulum sırasında veritabanı olarak SQLite'ı seçtim. Büyük bir veritabanı yöneticisine ihtiyacım yoktu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;═══════════════════════════════════════════
     Database Selection
═══════════════════════════════════════════
  1) SQLite     (default — recommended for &amp;lt; 500 clients)
  2) PostgreSQL (recommended for high client counts / many nodes)
Choose [1]: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Panel portu özelleştirme sorusuna &lt;code&gt;y&lt;/code&gt; yanıtı verip port &lt;code&gt;80&lt;/code&gt; olarak ayarladım.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Would you like to customize the Panel Port settings? (If not, a random port will be applied) [y/n]: y
Please set up the panel port: 80
Your Panel Port is: 80
Port set successfully: 80
Username and password updated successfully
Base URI path set successfully
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kurulumun son aşamasında SSL kurulumu soruldu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;═══════════════════════════════════════════
     SSL Certificate Setup (RECOMMENDED)
═══════════════════════════════════════════
SSL is strongly recommended. Skip only if a reverse proxy
or SSH tunnel handles TLS for you.
Let's Encrypt now supports both domains and IP addresses!

Choose SSL certificate setup method:
1. Let's Encrypt for Domain (90-day validity, auto-renews)
2. Let's Encrypt for IP Address (6-day validity, auto-renews)
3. Custom SSL Certificate (Path to existing files)
4. Skip SSL (advanced — behind reverse proxy / SSH tunnel only)
Note: Options 1 &amp;amp; 2 require port 80 open. Option 3 requires manual paths.
Note: Option 4 serves the panel over plain HTTP — only safe behind nginx/Caddy or an SSH tunnel.
Choose an option (default 2 for IP): 4

⚠ Panel will be installed WITHOUT SSL/TLS.
Login credentials and cookies will travel as plain HTTP.
Only safe when:
  • A reverse proxy (nginx, Caddy, Traefik) terminates TLS for you, or
  • You access the panel exclusively via SSH tunnel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SSL'i atladım (4). Ama script, panelin &lt;code&gt;127.0.0.1&lt;/code&gt;'e mi bağlanacağını da sordu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bind the panel to 127.0.0.1 only? (recommended — forces SSH tunnel / reverse-proxy access) [y/N]: N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Burada &lt;code&gt;N&lt;/code&gt; seçtim. Nedeni, ilk aşamada paneli tarayıcıdan test etmek istememdi; &lt;code&gt;y&lt;/code&gt; deseydim panele sadece SSH tüneli ile erişilebilecekti, bu da ilk hatayı tespit etmeyi zorlaştıracaktı.&lt;/p&gt;

&lt;h3&gt;
  
  
  Karşılaşılan Hata: 404 Not Found
&lt;/h3&gt;

&lt;p&gt;Tarayıcıdan &lt;code&gt;http://54.93.233.182&lt;/code&gt; adresine gittiğimde karşılama ekranı yerine &lt;code&gt;404 Not Found&lt;/code&gt; hatası aldım.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gözlem ve Tespit:&lt;/strong&gt; 3X-UI'nin son sürümleri, güvenlik gereği paneli ana dizine (&lt;code&gt;/&lt;/code&gt;) değil, rastgele oluşturulmuş gizli bir yola (&lt;code&gt;webBasePath&lt;/code&gt;) kuruyor. Ana IP'ye girince 404 vermesi bir hata değil, bir güvenlik özelliği.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Gizli yolu bulmak için terminalden panel ayarlarını sorguladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;x-ui settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Çıktı şu şekilde geldi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[INF] current panel settings as follows:
port: 80
webBasePath: /mubjbN3SXSEBOdEhtd/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tarayıcı adresini &lt;code&gt;http://54.93.233.182/mubjbN3SXSEBOdEhtd/&lt;/code&gt; olarak güncelledim ve panele başarıyla girdim.&lt;/p&gt;

&lt;p&gt;Ama giriş ekranı geldikten sonra bir sorun vardı. Kurulum yaparken bana kullanıcı adı ve şifre için sorular sormamıştı!&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%2Ffqulkv6obizt2lo27hpp.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%2Ffqulkv6obizt2lo27hpp.png" alt="Kullanıcı adı/parola bilgisi bilinmeyen 3X-UI giriş ekranı" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bunun için panel ayarlarını açtım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ip-172-31-38-106:~# x-ui
The OS release is: ubuntu

╔────────────────────────────────────────────────╗
│  3X-UI Panel Management Script                │
│  0. Exit Script                               │
│────────────────────────────────────────────────│
│  1. Install                                   │
│  2. Update                                    │
│  3. Update to Dev Channel (latest commit)     │
│  4. Update Menu                               │
│  5. Legacy Version                            │
│  6. Uninstall                                 │
│────────────────────────────────────────────────│
│  7. Reset Username &amp;amp; Password                 │
│  8. Reset Web Base Path                       │
│  9. Reset Settings                            │
│  10. Change Port                              │
│  11. View Current Settings                    │
│────────────────────────────────────────────────│
│  12. Start                                    │
│  13. Stop                                     │
│  14. Restart                                  │
|  15. Restart Xray                             │
│  16. Check Status                             │
│  17. Logs Management                          │
│────────────────────────────────────────────────│
│  18. Enable Autostart                         │
│  19. Disable Autostart                        │
│────────────────────────────────────────────────│
│  20. SSL Certificate Management               │
│  21. Cloudflare SSL Certificate               │
│  22. IP Limit Management                      │
│  23. Firewall Management                      │
│  24. SSH Port Forwarding Management           │
│  25. PostgreSQL Management                    │
│────────────────────────────────────────────────│
│  26. Enable BBR                               │
│  27. Update Geo Files                         │
│  28. Speedtest by Ookla                       │
╚────────────────────────────────────────────────╝

Panel state: Running
Start automatically: Yes
xray state: Running

Please enter your selection [0-28]: 7

Are you sure to reset the username and password of the panel? [Default n]: y
Please set the login username [default is a random username]: ********
Please set the login password [default is a random password]: ********
Do you want to disable currently configured two-factor authentication? (y/n): n
Panel login username has been reset to:  ******** 
Panel login password has been reset to:  ******** 
 Please use the new login username and password to access the X-UI panel. Also remember them! 

Restart the panel, Attention: Restarting the panel will also restart xray [Default y]: 
[INF] x-ui and xray Restarted successfully 

Press enter to return to the main menu: 

╔────────────────────────────────────────────────╗
│  3X-UI Panel Management Script                │
│  0. Exit Script                               │
│────────────────────────────────────────────────│
│  1. Install                                   │
│  2. Update                                    │
│  3. Update to Dev Channel (latest commit)     │
│  4. Update Menu                               │
│  5. Legacy Version                            │
│  6. Uninstall                                 │
│────────────────────────────────────────────────│
│  7. Reset Username &amp;amp; Password                 │
│  8. Reset Web Base Path                       │
│  9. Reset Settings                            │
│  10. Change Port                              │
│  11. View Current Settings                    │
│────────────────────────────────────────────────│
│  12. Start                                    │
│  13. Stop                                     │
│  14. Restart                                  │
|  15. Restart Xray                             │
│  16. Check Status                             │
│  17. Logs Management                          │
│────────────────────────────────────────────────│
│  18. Enable Autostart                         │
│  19. Disable Autostart                        │
│────────────────────────────────────────────────│
│  20. SSL Certificate Management               │
│  21. Cloudflare SSL Certificate               │
│  22. IP Limit Management                      │
│  23. Firewall Management                      │
│  24. SSH Port Forwarding Management           │
│  25. PostgreSQL Management                    │
│────────────────────────────────────────────────│
│  26. Enable BBR                               │
│  27. Update Geo Files                         │
│  28. Speedtest by Ookla                       │
╚────────────────────────────────────────────────╝

Panel state: Running
Start automatically: Yes
xray state: Running

Please enter your selection [0-28]: 0
root@ip-172-31-38-106:~#
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ve evet, kullanıcı adı ve parolayı sıfırlayarak kendim yeni kullanıcı adı ve parola tanımladım! Ve web arayüzüne giriş yaptığımda beni çok güzel bir arayüz karşıladı:&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%2Fcrf7np1xrabhmvt5jkfp.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%2Fcrf7np1xrabhmvt5jkfp.png" alt="Yeni kullanıcı adı ve parola ile giriş yapılan 3X-UI panel arayüzü" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ve artık VLESS + WebSocket Inbound kurulumuna geçebiliriz!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adım 3: VLESS + WebSocket Inbound Oluşturma
&lt;/h2&gt;

&lt;p&gt;Panele girdikten sonra bağlantıları karşılayacak Inbound kuralını oluşturmamız gerekti. GUI'deki sol menüden Inbounds'u açtı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%2Fpm2obc9pn7y86kfreohi.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%2Fpm2obc9pn7y86kfreohi.png" alt="3X-UI panelinde sol menüden Inbounds sekmesinin açılması" width="800" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Add Inbound" ekranında "Stream" sekmesine geçtiğimde "Transmission" kısmı varsayılan olarak &lt;code&gt;RAW&lt;/code&gt; (TCP) geliyordu. Arayüzden bunu &lt;code&gt;ws&lt;/code&gt; (WebSocket) yapmak ve Host eklemek bazen karmaşık 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%2Fngjllzhfdzs2g0277hc6.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%2Fngjllzhfdzs2g0277hc6.png" alt="Add Inbound ekranında Stream sekmesi, Transmission alanının varsayılan RAW (TCP) değeri" width="776" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gerçek Hata ve Çözüm:&lt;/strong&gt; GUI üzerinden ayarları değiştirmeye çalıştığımda arayüz bazen değişiklikleri tam yansıtmadı. En kesin ve hatasız yöntemin "Advanced" sekmesinden JSON config'i doğrudan düzenlemek olduğuna karar verdim.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Advanced (JSON) Config:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"listen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"in-443-ws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"settings"&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="nl"&gt;"clients"&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="nl"&gt;"decryption"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"encryption"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&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;"sniffing"&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="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"destOverride"&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="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"tls"&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="nl"&gt;"streamSettings"&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="nl"&gt;"network"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"security"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"wsSettings"&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="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"headers"&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="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="s2"&gt;"hakanismail.info"&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;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;Not: &lt;code&gt;security: none&lt;/code&gt; seçmemin sebebi, sunucuda henüz SSL sertifikası olmaması. Trafik şifrelenmiş (TLS) bir port üzerinden değil, ham WebSocket (HTTP upgrade) üzerinden taşınacak.&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%2F9few6q62n5cpfxwj26hx.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%2F9few6q62n5cpfxwj26hx.png" alt="Advanced sekmesinden JSON config düzenlendikten sonra kaydedilen Inbound" width="798" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inbound'u kaydettikten sonra "Clients" kısmından bir kullanıcı oluşturdum ve sağlanan bağlantı QR'ı ile Arch Linux üzerindeki v2rayN istemcisinden bağlantı sağladım. &lt;code&gt;vless://&lt;/code&gt; linki ile bağlantı sağlanabilir fakat QR kod daha kolay 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%2Fe2nmnk1b7xc6as65l080.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%2Fe2nmnk1b7xc6as65l080.png" alt="Oluşturulan client için görüntülenen bağlantı QR kodları" width="718" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;QR kodda önemli bir detay var: iki tane QR kodu var. "Subscription Info" QR'ı bağlantı için kullanılmaz. Bağlantı için kullanmamız gereken, "Vless WS (Arch-Linux:443)" etiketli QR.&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%2Fsizwyh7pbeidm6bifzyj.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%2Fsizwyh7pbeidm6bifzyj.png" alt="Bağlantı için kullanılması gereken " width="523" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bağlantıyı ekledikten sonra alttaki anahtarı "Clear system proxy" konumundan "Set system proxy" konumuna çekiyoruz ve bağlantı sağlanı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%2Ffwxduytoo33coymcp6i3.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%2Ffwxduytoo33coymcp6i3.png" alt="v2rayN istemcisinde " width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;whatismyip.com&lt;/code&gt; üzerinden IP'nin Almanya (AWS) olduğunu teyit 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%2F10o91ouz7hk99s7icac3.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%2F10o91ouz7hk99s7icac3.png" alt="whatismyip.com sonucu, IP'nin Almanya/Frankfurt olarak görünmesi" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adım 4: Güvenlik (Panelin Dış Dünyaya Kapatılması)
&lt;/h2&gt;

&lt;p&gt;Sistem çalışır durumdaydı ama 3X-UI paneli (&lt;code&gt;80&lt;/code&gt; portu) tüm dünyaya açıktı. İnternetteki botlar IP'yi tarayıp paneli kötüye kullanmaya çalışabilir. Çözüm, AWS güvenlik duvarından 80 portunu kapatmak ve panele sadece SSH tüneli ile girmekti.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. AWS Security Group Kuralını Sildim&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AWS konsolundan EC2 → seçili sanal makine → Security sekmesi → Security Groups altındaki tek security grup → Inbound rules kısmına gittim. HTTP (Port 80) kuralını listeden sildim. Artık &lt;code&gt;http://54.93.233.182&lt;/code&gt; adresine dışarıdan kimse erişemiyor.&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%2Fytlyhkueuev9bqp5w67m.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%2Fytlyhkueuev9bqp5w67m.png" alt="Security group Inbound rules listesinden HTTP (80) kuralının silinmesi" width="799" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. SSH Tüneli (Local Port Forwarding) Kurdum&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Arch Linux terminalinden şu komutu ç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;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; aws-key.pem &lt;span class="nt"&gt;-L&lt;/span&gt; 8080:127.0.0.1:80 ubuntu@54.93.233.182
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bu komut, yerel makinenin &lt;code&gt;8080&lt;/code&gt; portunu, SSH bağlantısı üzerinden sunucunun iç ağındaki &lt;code&gt;127.0.0.1:80&lt;/code&gt; adresine gizlice yönlendirdi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Test&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SSH tüneli açıkken tarayıcıya şu adresi girdim: &lt;code&gt;http://127.0.0.1:8080/mubjbN3SXSEBOdEhtd/panel/&lt;/code&gt;. Panel sorunsuz açıldı.&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%2Frlgoidlngi67gxxfhbq4.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%2Frlgoidlngi67gxxfhbq4.png" alt="SSH tüneli üzerinden localhost:8080 adresinden açılan panel" width="799" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dış IP üzerinden denediğimde ise bağlantı zaman aşımına uğradı (Timeout). Sunucu güvenliği sağlandı.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adım 5: Cloudflare WARP Entegrasyonu
&lt;/h2&gt;

&lt;p&gt;Şu anda IP'm &lt;code&gt;54.93.233.182&lt;/code&gt; (Amazon). ChatGPT veya Netflix gibi servisler, trafiğin bir veri merkezinden geldiğini anlayıp erişimi reddedebilir. Bu, film izlerken veya agentik iş yaparken can sıkıcı olabiliyor. Bunu aşmak için AWS sunucusunun içine Cloudflare WARP kurdum. WARP, trafiği Cloudflare'in residential IP havuzundan, yani son kullanıcı IP'lerinden çıkarıyor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. WARP Kurulumu&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AWS sunucusuna SSH ile bağlanıp root oldum. Cloudflare deposunu ekledim ve paketi kurdum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://pkg.cloudflareclient.com/pubkey.gpg | &lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;--yes&lt;/span&gt; &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;--output&lt;/span&gt; /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.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="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/cloudflare-client.list
apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class="nb"&gt;install &lt;/span&gt;cloudflare-warp &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Kayıt ve Proxy Modu&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WARP'ı tüm sunucu trafiğini kesmeyecek, sadece yerel bir SOCKS5 proxy (port 40000) olarak çalışacak şekilde ayarladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;warp-cli registration new
&lt;span class="c"&gt;# (Kullanım şartları kabul edildi: y)&lt;/span&gt;

warp-cli mode proxy
&lt;span class="c"&gt;# Success&lt;/span&gt;

warp-cli connect
&lt;span class="c"&gt;# Success&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Test ve Karşılaşılan Garip Çıktı&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WARP'ın çalışıp çalışmadığını test etmek için standart trace komutunu kullandım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://www.cloudflare.com/cdn-cgi/trace/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;İlginç bir şekilde ekrana HTML olarak &lt;code&gt;404 Not Found&lt;/code&gt; düştü. Bu adresin kendisi bozuk değildi; muhtemelen cloudflare.com'un kendi sitesine özgü bir bot koruması ya da redirect davranışıydı, WARP veya AWS IP'siyle doğrudan ilgisi yoktu.&lt;/p&gt;

&lt;p&gt;Bunun yerine Cloudflare'in tam olarak bu iş için var olan tanılama adresini denedim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://1.1.1.1/cdn-cgi/trace
&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;fl=928f31
h=1.1.1.1
ip=54.93.233.182
ts=1788933479.000
visit_scheme=https
uag=curl/8.18.0
colo=FRA
sliver=050-tier1
http=http/2
loc=DE
tls=TLSv1.3
sni=off
warp=off
gateway=off
rbi=off
kex=X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;warp=off&lt;/code&gt; görünce şüphelendim, çünkü WARP zaten bağlıydı. Emin olmak için bağlantıyı kesip tekrar bağladım ve her seferinde aynı komutu tekrarladım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@ip-172-31-38-106:~# warp-cli disconnect
Success
root@ip-172-31-38-106:~# curl https://1.1.1.1/cdn-cgi/trace
...
warp=off

root@ip-172-31-38-106:~# warp-cli connect
Success
root@ip-172-31-38-106:~# warp-cli status
Status update: Connected
Network: healthy
root@ip-172-31-38-106:~# curl https://1.1.1.1/cdn-cgi/trace
...
warp=off
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;warp-cli status&lt;/code&gt; "Connected" ve "healthy" dese bile çıktı hep &lt;code&gt;warp=off&lt;/code&gt; kaldı.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Gerçek Durum:&lt;/strong&gt; WARP'ı &lt;code&gt;proxy&lt;/code&gt; moduna aldığım için varsayılan ağ yönlendirmesine hiç müdahale etmiyor. &lt;code&gt;curl&lt;/code&gt; gibi düz bir istek WARP'a hiç girmeden direkt AWS ağından çıkıyor; WARP yalnızca açıkça kendisine yönlendirilen (SOCKS5 üzerinden gelen) trafiği görüyor. Bu artık hipotez değil, connect/disconnect döngüsüyle doğrulanmış bir gözlem.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bunu kanıtlamak için, az önceki testle birebir aynı komutu bu kez WARP'ın SOCKS5 portu üzerinden ç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;curl &lt;span class="nt"&gt;-x&lt;/span&gt; socks5h://127.0.0.1:40000 https://1.1.1.1/cdn-cgi/trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not: &lt;code&gt;socks5h&lt;/code&gt; kullanmak önemli (düz &lt;code&gt;socks5&lt;/code&gt; değil), çünkü &lt;code&gt;h&lt;/code&gt; DNS çözümlemesini de proxy üzerinden yaptırıyor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fl=470f261
h=1.1.1.1
ip=104.28.197.9
ts=1788933795.000
visit_scheme=https
uag=curl/8.18.0
colo=FRA
sliver=010-tier1
http=http/2
loc=DE
tls=TLSv1.3
sni=off
warp=on
gateway=off
rbi=off
kex=X25519MLKEM768
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fark net: &lt;code&gt;ip&lt;/code&gt; artık AWS'e ait &lt;code&gt;54.93.233.182&lt;/code&gt; değil, Cloudflare'e ait &lt;code&gt;104.28.197.9&lt;/code&gt;; &lt;code&gt;warp&lt;/code&gt; alanı da &lt;code&gt;off&lt;/code&gt;'tan &lt;code&gt;on&lt;/code&gt;'a döndü. WARP'ın çalıştığı, sadece varsayılan yönlendirmeye dahil olmadığı bu şekilde kanıtlandı.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. 3X-UI Panelinden Yönlendirme (Routing)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WARP kuruldu ama V2Ray trafiği hâlâ AWS'in normal internetinden çıkıyordu. 3X-UI panelinden (SSH tüneli ile girdim), &lt;code&gt;Panel Settings → Xray Configuration&lt;/code&gt; kısmındaki JSON config'i güncelledim.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;outbounds&lt;/code&gt; dizisine WARP için bir SOCKS çıkışı ekledim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"socks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"settings"&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="nl"&gt;"servers"&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;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"port"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;40000&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;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;&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%2Fqo2gnhkk9vlsq1kfu4tz.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%2Fqo2gnhkk9vlsq1kfu4tz.png" alt="3X-UI panelinin Xray Configuration ekranında, outbounds dizisine eklenen WARP SOCKS çıkışı" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;routing&lt;/code&gt; → &lt;code&gt;rules&lt;/code&gt; kısmına ise tüm trafiği bu WARP'a yönlendirecek kuralı yazdım:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outboundTag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"warp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"network"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp,udp"&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;&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%2Ft05qh9y2do87ilrlf33c.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%2Ft05qh9y2do87ilrlf33c.png" alt="3X-UI panelinin Xray Configuration ekranında, routing kurallarına eklenen WARP yönlendirme kuralı" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ayarları kaydedip Xray'i yeniden başlattım.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Final Testi&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;v2rayN istemcisinden bağlantıyı kesip tekrar bağlandım. &lt;code&gt;whatismyip.com&lt;/code&gt; adresine girdim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Yeni IPv4: &lt;code&gt;104.28.197.14&lt;/code&gt; (Cloudflare)&lt;/li&gt;
&lt;li&gt;Yeni IPv6: &lt;code&gt;2a09:bac1:1e20:8::3a2:d&lt;/code&gt; (WARP)&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%2Ftbrgrbhdgex0wm3x9gnl.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%2Ftbrgrbhdgex0wm3x9gnl.png" alt="whatismyip.com üzerinde WARP sonrası görünen yeni IP (Cloudflare)" width="799" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merakımdan, WARP'ı devre dışı bırakıp &lt;code&gt;chat.openai.com&lt;/code&gt; adresine direkt AWS IP'si üzerinden de gittim. Beklediğimin aksine herhangi bir hata almadan, sorunsuz açıldı; yani ChatGPT bu spesifik AWS IP'sini o an engellemiyordu. Bu da datacenter IP engellerinin ne kadar tutarsız olduğunu gösteriyor: hangi IP'nin hangi serviste ne zaman engelleneceği önceden kestirilemiyor (Netflix gibi bölge kilidine çok daha sıkı yaklaşan servislerde durum farklı olabilir, ama bunu ayrıca test etmedim). WARP'ın buradaki asıl faydası "aktif bir engeli aşmak" değil, IP'nin görünümünü baştan residential seviyeye çekip bu riski azaltmaktı.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kapanış ve Gözlem
&lt;/h2&gt;

&lt;p&gt;Bir hafta sonuna sığan bu lab çalışmasında, standart bir VPS'in nasıl güvenli bir proxy sunucusuna dönüştürüleceğini test ettim. Çıkardığım en önemli dersler:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GUI bazen istenen network ayarlarını tam yansıtmayabilir; JSON config'i doğrudan düzenlemek çok daha güven verici.&lt;/li&gt;
&lt;li&gt;Bir servisi (WARP gibi) sistem geneline yaymak yerine local proxy modunda çalıştırıp ana proxy yazılımının (Xray) routing kurallarıyla yönetmek, hata ayıklamayı inanılmaz kolaylaştırıyor.&lt;/li&gt;
&lt;li&gt;Yönetim panellerini (3X-UI gibi) dış dünyaya açmamak, SSH local forwarding ile erişmek en sağlam sunucu güvenliği yöntemi.&lt;/li&gt;
&lt;li&gt;Datacenter IP engelleri servise göre çok değişken ve garantili değil; bu testte ChatGPT AWS IP'mi hiç engellemedi. WARP'ın buradaki kazancı "aktif bir engeli aşmak" değil, IP'nin görünümünü residential seviyeye çekip bu riski önceden azaltmaktı.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>v2ray</category>
      <category>3xui</category>
    </item>
    <item>
      <title>Proxmox Otomasyon Serisi Faz 3: Zabbix Agent 2 (7.0 LTS), Rsyslog (QRadar TCP ve Disk Destekli Kuyruk) ve Güvenlik Ajanları</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Thu, 10 Sep 2026 12:08:11 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/proxmox-otomasyon-serisi-faz-3-zabbix-agent-2-70-lts-rsyslog-qradar-tcp-ve-disk-destekli-52jd</link>
      <guid>https://dev.to/hakanbaban53/proxmox-otomasyon-serisi-faz-3-zabbix-agent-2-70-lts-rsyslog-qradar-tcp-ve-disk-destekli-52jd</guid>
      <description>&lt;p&gt;Bu rehber, &lt;strong&gt;Proxmox Otomasyon Serisi&lt;/strong&gt;'nin dördüncü modülüdür ve tamamlanmış bir altyapı fazının üzerine inşa edilen ilk katmandır. Faz 2; seri numaralarıyla etiketlenmiş disklerin LVM ve XFS katmanlarından geçirilip bağlanması, çalışan makinede kesintisiz disk genişletme, VM açılışında kalıcılığını kanıtlayan reboot testleri ve aygıt harfleri (&lt;code&gt;sdb&lt;/code&gt;, &lt;code&gt;sde&lt;/code&gt;...) tamamen yer değiştirdiğinde dahi sistemin ayakta kaldığını gösteren saha oturumlarıyla kapatılmıştı.&lt;/p&gt;

&lt;p&gt;Makineler mevcut, veriyi tutuyor ve reboot sonrasında sorunsuz ayağa kalkıyor. Bu noktada ana soru değişir: Artık soru &lt;em&gt;"makine ayakta mı?"&lt;/em&gt; değil, &lt;em&gt;"makinenin içinde neler oluyor?"&lt;/em&gt; sorusudur. Bu sorunun yanıtı konuk (guest) makinenin dışından verilir; bu yanıtın makine içindeki ayağı ise her zaman bir ajandır (agent).&lt;/p&gt;

&lt;p&gt;Faz 3, provizyon edilen her sanal makineye üç temel ajan rolü kazandırır:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;İzleme Ajanı (Monitoring):&lt;/strong&gt; Merkezi bir sunucunun makineyi kontrol edebilmesi için resmi 7.0 LTS deposuna sabitlenmiş &lt;strong&gt;Zabbix Agent 2&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log Yönlendirme (Logging):&lt;/strong&gt; Makinenin tüm sistem loglarını kurumsal QRadar mimarisine uygun şekilde TCP üzerinden ve disk destekli bir kuyruk mekanizmasıyla dışarı aktaran &lt;strong&gt;rsyslog&lt;/strong&gt; yapılandırması.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Güvenlik Ajanları (Security):&lt;/strong&gt; Homelab ortamında lisanslanması mümkün olmayan kurumsal güvenlik yazılımlarını (Trend Micro Deep Security ve ManageEngine) simüle eden, bir belirteç sözleşmesi (&lt;strong&gt;marker contract&lt;/strong&gt;) arkasında çalışan &lt;strong&gt;stub yükleyiciler&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Her üç bileşen de serinin felsefesine sadık kalınarak; numaralandırılmış, bağımsız, idempotent, tek bir değişken dosyasından beslenen ve yeşil recap çıktısı vermeden önce kendi yaptıklarını bizzat doğrulayan Ansible playbook'ları olarak dağıtılır.&lt;/p&gt;




&lt;h2&gt;
  
  
  Faz 3'de ne var?
&lt;/h2&gt;

&lt;p&gt;Planlama aşamasında community rolleri, bir Graylog konteyneri ve basit &lt;code&gt;echo&lt;/code&gt; komutlarıyla çalışan sahte betikler düşünülmüştü. Canlıya alınan mimarideki sapmalar birer taviz değil; saha testlerinin getirdiği teknik zorunluluklardır:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;İlk Planlanan&lt;/th&gt;
&lt;th&gt;Canlıya Alınan&lt;/th&gt;
&lt;th&gt;Teknik Gerekçe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;community.zabbix.zabbix_agent&lt;/code&gt; rolü&lt;/td&gt;
&lt;td&gt;Özel &lt;code&gt;04_zabbix_agent.yml&lt;/code&gt; playbook'u&lt;/td&gt;
&lt;td&gt;Ubuntu 26.04 için resmi 7.0 LTS deposu zorunluluğu; kontrol düğümüne koleksiyon kurmadan &lt;code&gt;ansible.builtin&lt;/code&gt; içinde kalma hedefi.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ayrı Zabbix sunucusu VM'i (Docker, 4 GB)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ctrl-01&lt;/code&gt; üzerinden &lt;code&gt;zabbix-get&lt;/code&gt; doğrulaması&lt;/td&gt;
&lt;td&gt;Bu fazın teslimatı sunucu değil ajandır. Soket sorgusu tüm yolu kanıtlar; sunucu isteğe bağlı hafif LXC'ye bırakıldı.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graylog konteyneri / tam rsyslog sunucusu&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ctrl-01&lt;/code&gt; üzerinde tek satırlık &lt;code&gt;socat&lt;/code&gt; dinleyicisi&lt;/td&gt;
&lt;td&gt;QRadar TCP desenini test eden en hafif uç nokta. Altyapıyı şişirmeden kuyruk akışını tam doğrular.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;*.* @@receiver:514&lt;/code&gt; (tek satır yönlendirme)&lt;/td&gt;
&lt;td&gt;Disk destekli kuyruğa sahip &lt;code&gt;omfwd&lt;/code&gt; aksiyonu&lt;/td&gt;
&lt;td&gt;Tek satırlık kural hedef kapandığında log düşürür. Kuyruk mekanizması hedef gelene kadar logları diske depolar.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Basit kabuk betikleri (&lt;code&gt;touch /opt/...&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Sürüm sapma alarmlı marker sözleşmesi&lt;/td&gt;
&lt;td&gt;Yükleyici iskeleti prodüksiyon standardındadır; yarın lisans geldiğinde yalnızca yükleme gövdesi güncellenir.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Dizin Ağacı ve Dosya Rolleri
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansible/
├── inventory/group_vars/
│   └── provisioned.yml             # Ajan değişkenleri ayrıştırıldı, sadece depolama şeması kaldı
├── playbooks/
│   ├── vars/
│   │   └── agent-layer.yml         # Ajan katmanının tek gerçek kaynağı (Single Source of Truth)
│   ├── tasks/
│   │   └── wait_for_apt.yml        # İlk açılış dpkg/apt kilit yarışını çözen geçit görevi
│   ├── templates/
│   │   ├── zabbix_agent2.conf.j2   # Dinamik ajan yapılandırma şablonu
│   │   ├── 50-qradar-forward.conf.j2 # Disk kuyruklu rsyslog yönlendirme şablonu
│   │   └── install.sh.j2           # Marker sözleşmesine bağlı stub yükleyici
│   ├── 04_zabbix_agent.yml         # Zabbix kurulum ve 5 adımlı doğrulama playbook'u
│   ├── 05_rsyslog_forward.yml      # Log yönlendirme ve sözdizimi doğrulama playbook'u
│   └── 06_security_agents.yml      # Güvenlik ajanları stub dağıtımı ve drift denetimi

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kapsam Sınırları
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kapsam İçi:&lt;/strong&gt; Zabbix Agent 2'nin resmi 7.0 LTS reposundan pini, disk destekli TCP rsyslog kuyruğu, lisanslı ajanlar için marker sözleşmeli stub altyapısı, &lt;code&gt;ctrl-01&lt;/code&gt; üzerinde oturum bağımsız dinleyici ve saha doğrulamaları.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kapsam Dışı:&lt;/strong&gt; Prodüksiyon QRadar / Zabbix sunucu kurulumları, TLS sertifika yönetimi, log ayrıştırma kuralları ve alarm dashboard'ları (bu katmanın tek amacı misafir makinedeki ajan omurgasını ayağa kaldırmaktır).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Zabbix Agent 2: Sürüm Sabitleme ve Doğrulama
&lt;/h2&gt;

&lt;p&gt;İzleme tarafında klasik Zabbix ajanı yerine Go ile yeniden yazılan Zabbix Agent 2 tercih edildi. Klasik ajan her metrik için yeni bir alt süreç (&lt;code&gt;fork&lt;/code&gt;) açarak kaynak tüketirken, Agent 2 eklenti mimarisi ve kalıcı tek bir TCP bağlantısı üzerinden aktif kontrolleri yürütür.&lt;/p&gt;

&lt;h3&gt;
  
  
  Neden Community Değil?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Resmi Depo Sabitlemesi:&lt;/strong&gt; Ubuntu 26.04 (&lt;code&gt;resolute&lt;/code&gt;) için kararlı paket sağlayan güncel ana dal 7.0 LTS serisidir. Üçüncü taraf bir rolün varsayılan değişkenlerine güvenmek yerine bu bağımlılık doğrudan kod içinde sabitlendi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sıfır Dış Bağımlılık:&lt;/strong&gt; Kontrol düğümüne harici Ansible Galaxy koleksiyonları eklenmedi, tüm akış &lt;code&gt;ansible.builtin&lt;/code&gt; modülleriyle çözüldü.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operasyonel Şeffaflık:&lt;/strong&gt; Arka planda onlarca task çalıştıran soyut roller yerine, her komutun ve doğrulamayı yapan assertion'ların net izlenebildiği yalın bir yapı kuruldu.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Canlı Depo Kontrolü ve Apt Seçimi (Election)
&lt;/h3&gt;

&lt;p&gt;Resmi repo doğrudan sorgulandığında 7.0 LTS paketinin erişilebilir olduğu, 8.0 paketinin ise henüz Ubuntu 26.04 için derlenmediği teyit edildi:&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="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://repo.zabbix.com/zabbix/7.0/ubuntu/dists/resolute/Release | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;
HTTP/2 200 &lt;span class="c"&gt;# 7.0 LTS paketi yayında&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://repo.zabbix.com/zabbix/8.0/ubuntu/dists/resolute/Release | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;
HTTP/2 404 &lt;span class="c"&gt;# 8.0 ana sürümü henüz bu dağıtım için yok&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Ubuntu Universe deposunda &lt;code&gt;7.0.22&lt;/code&gt; sürümü yer alırken, resmi &lt;code&gt;repo.zabbix.com&lt;/code&gt; üzerinde güncel &lt;code&gt;7.0.30&lt;/code&gt; paketi bulunur. Paket yöneticisi (&lt;code&gt;apt&lt;/code&gt;) yüksek sürüm numarasına sahip resmi depoyu seçer; ancak playbook bu varsayımla yetinmeyip &lt;code&gt;apt-cache policy zabbix-agent2&lt;/code&gt; çıktısını kontrol ederek paketin resmi repodan geldiğini ve &lt;code&gt;7.0&lt;/code&gt; ailesinde kaldığını doğrular.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kurulum Görevleri ve &lt;code&gt;lock_timeout&lt;/code&gt; Ayrımı
&lt;/h3&gt;

&lt;p&gt;İşlem sırası kritiktir: GPG anahtarı repo tanımından önce diske yazılmalıdır; aksi halde &lt;code&gt;apt_repository&lt;/code&gt; anında tetiklediği güncellemede imzasız repo hatasıyla süreci kırar.&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 the apt keyrings directory&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.file&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="s"&gt;/etc/apt/keyrings&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;directory&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0755"&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;Install the Zabbix official repo signing key&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.get_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://repo.zabbix.com/zabbix-official-repo.key&lt;/span&gt;
    &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/apt/keyrings/zabbix-official-repo.asc&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0644"&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;Wait out the first-boot apt race before touching packages&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.include_tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tasks/wait_for_apt.yml&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;Add the pinned Zabbix apt repository&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.apt_repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;repo&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;deb [signed-by=/etc/apt/keyrings/zabbix-official-repo.asc]&lt;/span&gt;
      &lt;span class="s"&gt;https://repo.zabbix.com/zabbix/{{ zabbix_agent_version }}/ubuntu&lt;/span&gt;
      &lt;span class="s"&gt;{{ ansible_facts['distribution_release'] }} main&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zabbix-official-repo&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;present&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;Install Zabbix Agent &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.apt&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;zabbix-agent2&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;present&lt;/span&gt;
    &lt;span class="na"&gt;lock_timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1800&lt;/span&gt;

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

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Saha Dersi (Bulgu #19):&lt;/strong&gt; İlk pipeline denemesinde &lt;code&gt;apt_repository&lt;/code&gt; adımına eklenen &lt;code&gt;lock_timeout: 1800&lt;/code&gt; parametresi görevi çökertti (&lt;code&gt;Unsupported parameters for apt_repository module&lt;/code&gt;). Bu parametre yalnızca &lt;code&gt;apt&lt;/code&gt; modülüne aittir. Kilit koruması &lt;code&gt;wait_for_apt.yml&lt;/code&gt; geçidiyle çözüldüğü için parametre repo görevinden kaldırıldı, sadece paket kurulum adımında bırakıldı.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Yapılandırma ve Değişken Sözleşmesi
&lt;/h3&gt;

&lt;p&gt;Yapılandırma Jinja2 şablonu üzerinden basılır:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;# &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;ansible_managed&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
PidFile=/run/zabbix/zabbix_agent2.pid
LogFile=/var/log/zabbix/zabbix_agent2.log
Server=&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;zabbix_agent_server&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
ListenPort=&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;zabbix_agent_listenport&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
ServerActive=&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;zabbix_agent_serveractive&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
Hostname=&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;zabbix_agent_hostname&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;
Include=/etc/zabbix/zabbix_agent2.d/plugins.d/*.conf

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

&lt;/div&gt;



&lt;p&gt;Bu şablonu besleyen &lt;code&gt;vars/agent-layer.yml&lt;/code&gt; dosyası:&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;# Zabbix Agent 2 Parametreleri&lt;/span&gt;
&lt;span class="na"&gt;zabbix_agent_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;7.0"&lt;/span&gt;                &lt;span class="c1"&gt;# Resmi LTS deposu sürüm sabitlemesi&lt;/span&gt;
&lt;span class="na"&gt;zabbix_agent_server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;192.168.122.10"&lt;/span&gt;      &lt;span class="c1"&gt;# Pasif kontrolleri sorgulayacak uç (ctrl-01)&lt;/span&gt;
&lt;span class="na"&gt;zabbix_agent_serveractive&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;192.168.122.10"&lt;/span&gt;&lt;span class="c1"&gt;# Aktif kontrollerin iletileceği uç&lt;/span&gt;
&lt;span class="na"&gt;zabbix_agent_listenport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10050&lt;/span&gt;             &lt;span class="c1"&gt;# Standart ajan dinleme portu&lt;/span&gt;
&lt;span class="na"&gt;zabbix_agent_hostname&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="c1"&gt;# Zabbix üzerindeki konak kimliği&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Şablon güncellendiğinde &lt;code&gt;Restart Zabbix Agent 2&lt;/code&gt; handler'ı devreye girer. Playbook içindeki &lt;code&gt;ansible.builtin.flush_handlers&lt;/code&gt; çağrısı, doğrulama testlerine geçmeden önce servisin yeniden başlatılmasını zorunlu kılar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beş Basamaklı Doğrulama ve &lt;code&gt;zabbix-get&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;04_zabbix_agent.yml&lt;/code&gt;, sunucuya ihtiyaç duymadan ajanı 5 aşamalı bir test zincirinden geçirir:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Apt Seçim Sağlaması:&lt;/strong&gt; &lt;code&gt;apt policy&lt;/code&gt; çıktısından paketin &lt;code&gt;repo.zabbix.com&lt;/code&gt; adresinden ve &lt;code&gt;7.0&lt;/code&gt; ana sürümünden geldiği denetlenir.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Servis Durumu:&lt;/strong&gt; &lt;code&gt;service_facts&lt;/code&gt; ile ajanın &lt;code&gt;running&lt;/code&gt; durumunda olduğu doğrulanır.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soket Kontrolü:&lt;/strong&gt; &lt;code&gt;wait_for&lt;/code&gt; ile &lt;code&gt;127.0.0.1:10050&lt;/code&gt; portunun açık olduğu görülür.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yerel Metrik Testi:&lt;/strong&gt; &lt;code&gt;zabbix_agent2 -t agent.version&lt;/code&gt; komutu çalıştırılarak eklentilerin yüklendiği ve ajanın dahili metrik üretebildiği teyit edilir (&lt;code&gt;rc=0&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Konfigürasyon Denetimi:&lt;/strong&gt; Dağıtılan dosya &lt;code&gt;slurp&lt;/code&gt; ile okunarak IP ve konak adı tanımları doğrulanır.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Uçtan uca son test kontrol makinesinden (&lt;code&gt;ctrl-01&lt;/code&gt;) misafir ajana doğru tetiklenir:&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 üzerinden misafir ajanı sorgula:&lt;/span&gt;
zabbix_get &lt;span class="nt"&gt;-s&lt;/span&gt; 192.168.122.50 &lt;span class="nt"&gt;-k&lt;/span&gt; agent.version
&lt;span class="c"&gt;# Çıktı: 7.0.30&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Rsyslog Yönlendirme: QRadar Deseni
&lt;/h2&gt;

&lt;p&gt;Sistem loglarının yalnızca yerel diskte tutulması felaket anında adli kanıtların yok olmasına neden olur. Ancak yaygın kullanılan &lt;code&gt;*.* @@192.168.122.10:5514&lt;/code&gt; gibi tek satırlık yönlendirme kuralları alıcı çöktüğü veya ağ kesildiği anda ya log akışını kilitler ya da veriyi sessizce düşürür.&lt;/p&gt;

&lt;p&gt;Bu riski bertaraf etmek için disk destekli bir &lt;code&gt;omfwd&lt;/code&gt; kuyruğu kurulmuştur:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;action(type="omfwd"
  target="192.168.122.10"
  port="5514"
  protocol="tcp"
  queue.type="LinkedList"
  queue.filename="qradar_fwd"
  queue.maxDiskSpace="100m"
  queue.saveOnShutdown="on"
  action.resumeRetryCount="-1")

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

&lt;/div&gt;



&lt;p&gt;Bu yapılandırmanın getirdiği davranış modeli:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loglar normal koşullarda bellekte (&lt;code&gt;LinkedList&lt;/code&gt;) işlenir.&lt;/li&gt;
&lt;li&gt;Hedefe ulaşılamazsa bellek taşmasını engellemek için &lt;code&gt;/var/spool/rsyslog&lt;/code&gt; altına geçici disk kuyruğu açılır.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;saveOnShutdown="on"&lt;/code&gt; sayesinde makine yeniden başlasa dahi iletilmemiş kuyruk silinmez.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;resumeRetryCount="-1"&lt;/code&gt; alıcı ayağa kalkana kadar iletim denemelerinin sonsuza dek sürmesini sağlar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Parametreler yine &lt;code&gt;vars/agent-layer.yml&lt;/code&gt; üzerinden yönetilir:&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;# Rsyslog Yönlendirme Parametreleri&lt;/span&gt;
&lt;span class="na"&gt;rsyslog_receiver_host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;192.168.122.10"&lt;/span&gt; &lt;span class="c1"&gt;# SIEM / Alıcı IP (Laboratuvarda ctrl-01)&lt;/span&gt;
&lt;span class="na"&gt;rsyslog_receiver_port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5514&lt;/span&gt;             &lt;span class="c1"&gt;# Root yetkisi istemeyen socat test portu (Prodüksiyonda 514)&lt;/span&gt;
&lt;span class="na"&gt;rsyslog_forward_protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp"&lt;/span&gt;         &lt;span class="c1"&gt;# Paket kaybını önleyen TCP aktarımı&lt;/span&gt;
&lt;span class="na"&gt;rsyslog_queue_maxdisk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;100m"&lt;/span&gt;           &lt;span class="c1"&gt;# Kuyruk diske taştığında ayrılacak üst sınır&lt;/span&gt;
&lt;span class="na"&gt;rsyslog_test_tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;phase3-test"&lt;/span&gt;         &lt;span class="c1"&gt;# Doğrulama aşamasında basılacak test log etiketi&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  12 Dakikalık Saha Kesinti Testi
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ctrl-01&lt;/code&gt; üzerindeki &lt;code&gt;socat&lt;/code&gt; dinleyicisi SSH oturumu kapandığı için devre dışı kaldı. Bu esnada &lt;code&gt;05_rsyslog_forward.yml&lt;/code&gt; çalıştırıldı, ardından alıcı kapalıyken test logu üretildi:&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;# 1. Alıcı kapalı, port dinlenmiyor:&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ss &lt;span class="nt"&gt;-tlnp&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;5514
&lt;span class="c"&gt;# (çıktı yok)&lt;/span&gt;

&lt;span class="c"&gt;# 2. Misafir makinede log üretildi ve rsyslog servisi restart edilerek saveOnShutdown test edildi:&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ssh ubuntu@192.168.122.50 &lt;span class="s1"&gt;'sudo systemctl restart rsyslog &amp;amp;&amp;amp; ls -la /var/spool/rsyslog/'&lt;/span&gt;
&lt;span class="nt"&gt;-rw-------&lt;/span&gt; 1 syslog syslog 193147 Aug 28 09:45 qradar_fwd.00000001
&lt;span class="nt"&gt;-rw-------&lt;/span&gt; 1 syslog syslog    567 Aug 28 09:45 qradar_fwd.qi

&lt;span class="c"&gt;# 3. Alıcı 12 dakika sonra arka planda ayağa kaldırıldı:&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;nohup &lt;/span&gt;socat &lt;span class="nt"&gt;-u&lt;/span&gt; TCP-LISTEN:5514,reuseaddr,fork OPEN:/tmp/qradar-stub.log,creat,append &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;

&lt;span class="c"&gt;# 4. Yaklaşık 30 saniye sonra biriken tüm kuyruk hedefe ulaştı:&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; /tmp/qradar-stub.log
942 /tmp/qradar-stub.log

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep &lt;/span&gt;kuyruk /tmp/qradar-stub.log
&amp;lt;13&amp;gt;Aug 28 09:34:21 vm-test-01 phase3-test: kuyruk testi: alici kapaliyken gonderildi

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

&lt;/div&gt;



&lt;p&gt;Log satırındaki &lt;code&gt;09:34:21&lt;/code&gt; zaman damgası mimarinin başarısını kanıtlar: Mesaj alıcı kapalıyken üretilmiş, iletim 12 dakika sonra gerçekleştiği halde satır &lt;strong&gt;orijinal üretim zamanıyla&lt;/strong&gt; hedefe ulaşmıştır.&lt;/p&gt;




&lt;h2&gt;
  
  
  Stub Yükleyici Deseni ve Marker Sözleşmesi
&lt;/h2&gt;

&lt;p&gt;Homelab ortamında Trend Micro Deep Security veya ManageEngine gibi lisanslı yazılımların ikili paketleri bulunmaz; ancak bu ajanları kuracak dağıtım hattının kendisi gerçektir. Bu ayrımı yönetmek için &lt;strong&gt;Marker Sözleşmesi (Marker Contract)&lt;/strong&gt; kurgulanmıştır.&lt;/p&gt;

&lt;p&gt;Ansible doğrudan ikili dosyanın içeriğiyle değil, kurulum tamamlandığında dosya sistemine bırakılan &lt;code&gt;.installed&lt;/code&gt; belirteciyle el sıkışı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="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-eu&lt;/span&gt;
&lt;span class="nv"&gt;INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ item.install_dir }}"&lt;/span&gt;
&lt;span class="nv"&gt;MARKER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{ item.install_dir }}/.installed"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[{{ item.name }}] yukleyici basliyor: surum {{ item.version }}..."&lt;/span&gt;

&lt;span class="c"&gt;# -------------------------------------------------------------&lt;/span&gt;
&lt;span class="c"&gt;# YUKLEME BLOKU (STUB)&lt;/span&gt;
&lt;span class="c"&gt;# Lisans geldiginde YALNIZCA bu blok degistirilecek&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[{{ item.name }}] stub modu: ikili dosya yok, lisans kullanilmadi."&lt;/span&gt;
&lt;span class="c"&gt;# -------------------------------------------------------------&lt;/span&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$INSTALL_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"agent={{ item.name }}"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"version={{ item.version }}"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"mode={{ item.mode }}"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"installed_at=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-Is&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"host=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$MARKER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"[{{ item.name }}] marker yazildi: &lt;/span&gt;&lt;span class="nv"&gt;$MARKER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Belirteç dosyası içindeki her alan belirli bir amaca hizmet eder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;agent&lt;/code&gt; ve &lt;code&gt;version&lt;/code&gt;: &lt;code&gt;vars/agent-layer.yml&lt;/code&gt; içindeki tanımla eşleşmek zorundadır. Uyuşmazlık durumunda Ansible &lt;strong&gt;drift alarmı&lt;/strong&gt; üretir.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mode&lt;/code&gt;: Şu an &lt;code&gt;stub&lt;/code&gt; değerine kilitlidir; prodüksiyona geçildiğinde &lt;code&gt;real&lt;/code&gt; moduna çevrilir.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;installed_at&lt;/code&gt;: Adli bilişim açısından kurulum zamanını kanıtlar.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;host&lt;/code&gt;: Belirtecin başka bir sanal makineden kopyalanmadığını belgeler.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drift Alarmı ve Lisans Geçişi
&lt;/h3&gt;

&lt;p&gt;Kurulum adımı &lt;code&gt;creates: "{{ item.install_dir }}/.installed"&lt;/code&gt; korumasıyla çalışır. Bu sayede belirteç mevcutsa görev işletilmez ve temiz ikinci çalıştırmada özet &lt;code&gt;changed=0&lt;/code&gt; döner.&lt;/p&gt;

&lt;p&gt;Eğer değişken dosyasında sürüm &lt;code&gt;1.0.0-stub&lt;/code&gt; iken &lt;code&gt;1.1.0-stub&lt;/code&gt; yapılırsa:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Yükleyici betik şablonu yeni sürümle güncellenir.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;creates&lt;/code&gt; koruması nedeniyle betik tekrar çalıştırılmaz, diskteki marker eski kalır.&lt;/li&gt;
&lt;li&gt;Sonraki adımda marker içeriği okunup assertion çalıştırıldığında playbook &lt;strong&gt;hata verir ve süreci durdurur&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bu yapı kontrolsüz güncellemeyi engelleyen bir güvenlik kilididir. Yeniden kurulum için marker'ın bilinçli olarak silinmesi gerekir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible provisioned &lt;span class="nt"&gt;-m&lt;/span&gt; file &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"path=/opt/TrendMicro/.installed state=absent"&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt;
ansible-playbook playbooks/06_security_agents.yml

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

&lt;/div&gt;



&lt;p&gt;Lisanslar temin edildiğinde &lt;code&gt;install.sh.j2&lt;/code&gt; dosyasındaki indirme/kurulum bloğu güncellenecek, &lt;code&gt;vars/agent-layer.yml&lt;/code&gt; içinde &lt;code&gt;mode: real&lt;/code&gt; değerine geçilecek ve dağıtım hattı mimarisi bozulmadan gerçek ajanlar devreye alınacaktır.&lt;/p&gt;




&lt;h2&gt;
  
  
  Saha Doğrulama Adımları ve Terminal Sonuçları
&lt;/h2&gt;

&lt;p&gt;Ajan katmanı sahada önce bağımsız adımlarla, ardından Semaphore UI dağıtım hattı üzerinden iki aşamada doğrulandı.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Zabbix Agent 2 Kurulumu (&lt;code&gt;04_zabbix_agent.yml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Ubuntu 26.04 cloud imajı &lt;code&gt;/etc/apt/keyrings&lt;/code&gt; diziniyle geldiği ve &lt;code&gt;apt install&lt;/code&gt; sonrası servis paket tetikleyicisi tarafından otomatik başlatıldığı için ilk çalıştırmada 5 değişiklik gerçekleş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="nv"&gt;$ &lt;/span&gt;ansible-playbook playbooks/04_zabbix_agent.yml
&lt;span class="c"&gt;# ...&lt;/span&gt;
TASK &lt;span class="o"&gt;[&lt;/span&gt;Receipt - agent on duty] &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;"zabbix-agent2 (repo 7.0) listening on port 10050; passive checks accepted from 192.168.122.10, active checks sent to 192.168.122.10 as host &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;vm-test-01&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;. Self-test: agent.version [s|7.0.30]"&lt;/span&gt;
&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;19 &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;Aynı komut tekrar çalıştırıldığında handler tetiklenmedi ve idempotency kanıtlandı: &lt;code&gt;ok=18 changed=0&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Rsyslog İletimi (&lt;code&gt;05_rsyslog_forward.yml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Paket sistemde kurulu geldiği için paket adımı &lt;code&gt;ok&lt;/code&gt; döndü; spool dizin izin düzeltmesi, şablon kopyalama ve servis restart adımları değişimi oluşturdu:&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="nv"&gt;$ &lt;/span&gt;ansible-playbook playbooks/05_rsyslog_forward.yml
&lt;span class="c"&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;13 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &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;İkinci çalıştırmada sistem tam kararlılığa ulaştı: &lt;code&gt;ok=12 changed=0&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Güvenlik Ajanları Dağıtımı (&lt;code&gt;06_security_agents.yml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;İki stub ajan sisteme dağıtıldı, marker dosyaları oluşturuldu ve doğrulandı:&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="nv"&gt;$ &lt;/span&gt;ansible-playbook playbooks/06_security_agents.yml
&lt;span class="c"&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;8 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &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;# Sanal makinedeki marker çıktısı:&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ssh ubuntu@192.168.122.50 &lt;span class="s1"&gt;'cat /opt/TrendMicro/.installed /opt/ManageEngine/.installed'&lt;/span&gt;
&lt;span class="nv"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;trendmicro
&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0.0-stub
&lt;span class="nv"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;stub
&lt;span class="nv"&gt;installed_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2026-08-28T09:12:01+00:00
&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vm-test-01
&lt;span class="nv"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;manageengine
&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.0.0-stub
&lt;span class="nv"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;stub
&lt;span class="nv"&gt;installed_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2026-08-28T09:12:02+00:00
&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;vm-test-01

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

&lt;/div&gt;



&lt;p&gt;Tekrarlanan çalıştırmada &lt;code&gt;creates&lt;/code&gt; muhafazası devreye girdi: &lt;code&gt;ok=8 changed=0&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dağıtım Hattı Entegrasyonu (Pipeline)
&lt;/h2&gt;

&lt;p&gt;Faz 4 kapsamında Semaphore UI üzerinden provizyon edilen &lt;code&gt;vm-faz4-01&lt;/code&gt; makinesinde tüm süreç otomatik tetiklendi. Süreç sırasında iki temel entegrasyon bulgusu çözüldü:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bulgu #18 (Run #31):&lt;/strong&gt; Semaphore dinamik envanter kullandığından reponun &lt;code&gt;group_vars&lt;/code&gt; tanımlarını doğrudan görmedi ve değişkenler tanımsız kaldı. Çözüm olarak tüm ajan yapılandırması &lt;code&gt;vars/agent-layer.yml&lt;/code&gt; dosyasına toplandı ve playbook'lara &lt;code&gt;vars_files&lt;/code&gt; ile bağlandı.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bulgu #19 (Run #36):&lt;/strong&gt; &lt;code&gt;apt_repository&lt;/code&gt; adımına verilen &lt;code&gt;lock_timeout&lt;/code&gt; parametresi görevi çökertti. Hatalı parametre kaldırılarak dpkg kilitleri &lt;code&gt;tasks/wait_for_apt.yml&lt;/code&gt; geçidine devredildi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tam Başarı (Run #37):&lt;/strong&gt; Hataların ardından pipeline baştan sona eksiksiz çalıştı:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run #37 pipeline özeti (vm-faz4-01)&lt;/span&gt;
PLAY RECAP &lt;span class="k"&gt;*********************************************************************&lt;/span&gt;
localhost  : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;16 &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;2 &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
vm-faz4-01 : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;88 &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;11 &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;Makine üzerindeki &lt;code&gt;changed=11&lt;/code&gt; değeri, bağımsız çalıştırmalardaki değişimlerin toplamıdır ($5 + 3 + 3$). Otomasyonun terminalden manuel işletilmesi ile pipeline üzerinden tetiklenmesi arasında hiçbir davranış sapması yaşanmamıştır.&lt;/p&gt;

&lt;h3&gt;
  
  
  İlk Açılış Apt Kilitlenmesinin Çözümü (&lt;code&gt;tasks/wait_for_apt.yml&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Yeni klonlanan bir sanal makine ilk açıldığında cloud-init paket güncellemelerini çalıştırırken &lt;code&gt;unattended-upgrades&lt;/code&gt; de devreye girer. Bu aralıkta tetiklenen apt görevleri &lt;code&gt;dpkg lock&lt;/code&gt; hatasıyla çöker.&lt;/p&gt;

&lt;p&gt;Süreç adlarını (&lt;code&gt;pgrep unattended-upgr&lt;/code&gt;) izlemek kalıcı servisler nedeniyle sonsuz döngüye yol açtığından, nihai çözüm doğrudan kilit dosyalarını izlemek oldu:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;cloud-init status --wait&lt;/code&gt; komutuyla bulut başlatması beklenir.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/var/lib/dpkg/lock-frontend&lt;/code&gt; ve &lt;code&gt;/var/lib/apt/lists/lock&lt;/code&gt; kilit dosyalarının boşa çıkması dinlenir.&lt;/li&gt;
&lt;li&gt;Paket görevlerinde &lt;code&gt;lock_timeout: 1800&lt;/code&gt; kullanılarak yarış koşulu tamamen engellenir.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Faz 3 Kapanışı ve Sıradaki Adım
&lt;/h2&gt;

&lt;p&gt;Ajan katmanı; harici koleksiyon bağımlılığı olmadan kurulan Zabbix Agent 2 omurgası, kesintiye dayanıklı disk destekli rsyslog kuyruğu ve lisans geçişine hazır drift korumalı marker mimarisiyle tamamlandı.&lt;/p&gt;

&lt;p&gt;Süreç geride iki aktif mekanizma bıraktı:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Makine içindeki logları merkezi kuyrukla toplayan oturum bağımsız dinleyici,&lt;/li&gt;
&lt;li&gt;Hem yerel hem de uzaktan tetiklenebilen 5 basamaklı servis sağlık denetimi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Faz 3 tamamen kapanmıştır. Sıradaki çalışma &lt;strong&gt;Faz 4: Semaphore UI ile Uçtan Uca Otomatik Dağıtım&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Form üzerinden parametrik VM provizyonu,&lt;/li&gt;
&lt;li&gt;Disklerin, LVM katmanının ve ajanların tek tıkla canlıya alınması,&lt;/li&gt;
&lt;li&gt;Dağıtım kapısı (&lt;strong&gt;Delivery Gate&lt;/strong&gt;) ile provizyon doğrulama testleri.&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.google.com/search?q=https://github.com/Hakanbaban53/proxmox-automation" rel="noopener noreferrer"&gt;GitHub Deposu&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>proxmox</category>
      <category>zabbix</category>
      <category>devops</category>
    </item>
    <item>
      <title>Proxmox Otomasyonu Faz 2.5: Depolamayı Güçlendirme, Doğrulama, fstab Kalıcılığı ve 5. Disk</title>
      <dc:creator>Hakan İSMAİL</dc:creator>
      <pubDate>Mon, 07 Sep 2026 12:26:44 +0000</pubDate>
      <link>https://dev.to/hakanbaban53/proxmox-otomasyonu-faz-25-depolamayi-guclendirme-dogrulama-fstab-kaliciligi-ve-5-disk-21b0</link>
      <guid>https://dev.to/hakanbaban53/proxmox-otomasyonu-faz-25-depolamayi-guclendirme-dogrulama-fstab-kaliciligi-ve-5-disk-21b0</guid>
      <description>&lt;p&gt;Bu rehber, Proxmox Otomasyon Serisi'nin üçüncü modülüdür. Faz 2 saha oturumu, depolama mimarisinin canlı ortamda kanıtlanmasıyla noktalanmıştı: Terraform üzerinde seri numaralarıyla (&lt;code&gt;serial&lt;/code&gt;) tanımlanan dört disk, idempotent bir Ansible playbook aracılığıyla LVM ve XFS katmanlarından geçirilip &lt;code&gt;/srv/*&lt;/code&gt; altına bağlanmış, çalışan sanal makinede (VM) disk boyutu 20 GB'den 30 GB'ye kesintisiz büyütülmüş ve her iddianın arkasına somut terminal çıktıları konmuştu.&lt;/p&gt;

&lt;p&gt;Bu sağlam bir zemin olsa da Faz 2 tamamlandığında arkasında henüz test edilmemiş iki büyük varsayım ve bir mimari açık bırakmıştı:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reboot Kalıcılık Testi:&lt;/strong&gt; Dosya sistemlerinin reboot sonrasında geri geleceği varsayılıyordu. &lt;code&gt;fstab&lt;/code&gt; satırları yazılmış ve LVM'in açılışta volume group'ları otomatik etkinleştirmesi bekleniyordu; fakat birisi makineyi gerçekten yeniden başlatıp kontrol edene kadar bu bir kanıt değil, bir temenniden ibarettir. Üretim ortamlarındaki veritabanı sunucularında &lt;em&gt;"makine reboot oldu ve veri diskleri geri gelmedi"&lt;/em&gt; durumu klasik bir kriz senaryosudur ve neredeyse her zaman tek satırlık bir hatadan kaynaklanır: &lt;code&gt;fstab&lt;/code&gt;'da bir yazım yanlışı, aktivasyon kapsamı dışında kalan bir VG veya açılış sürecinin bağlamayı reddettiği bir dosya sistemi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yeni Disk İhtiyacı:&lt;/strong&gt; Faz 2'deki büyüme senaryosu mevcut bir diski büyütmeyi kapsıyordu. Oysa sahada depolama büyümesi sıklıkla ortama yeni bir diskin eklenmesi şeklinde gelir: yeni bir iş yükü için depolama ekibinden gelen taze bir LUN.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Yapılandırma Kayması Riski (Configuration Drift):&lt;/strong&gt; Depolama düzeni &lt;code&gt;02_storage.yml&lt;/code&gt; playbook'unun içindeki &lt;code&gt;vars:&lt;/code&gt; bloğunda tanımlanmıştı. Tek bir playbook varken bu durum sorunsuzdu; ancak aynı listeyi doğrulayacak ikinci bir playbook geldiği anda iki dosya arasında kopyala-yapıştır yapmak kaçınılmaz bir drift riskine davetiye çıkaracaktı.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bu sağlamlaştırma adımı, çalışan parçaları bozmadan bu üç açığı kapatıyor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disk düzeni tek gerçek kaynak (&lt;strong&gt;Single Source of Truth&lt;/strong&gt;) olarak &lt;code&gt;group_vars/provisioned.yml&lt;/code&gt; dosyasına taşınıyor.&lt;/li&gt;
&lt;li&gt;Yeni yazılan &lt;code&gt;03_storage_verify.yml&lt;/code&gt; playbook'u makineyi yeniden başlatarak reboot sonrası kalıcılığını doğrulama token'ları, güncel fact'ler ve assertion'lar ile kanıtlıyor.&lt;/li&gt;
&lt;li&gt;Opsiyonel bir beşinci disk ise uçtan uca yeni disk ekleme iş akışını sınıyor.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dosya&lt;/th&gt;
&lt;th&gt;Değişiklik&lt;/th&gt;
&lt;th&gt;Amaç&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ansible/inventory/group_vars/provisioned.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yeni&lt;/td&gt;
&lt;td&gt;Depolama düzenini tek bir liste olarak tanımlar: &lt;code&gt;serial&lt;/code&gt;, &lt;code&gt;vg&lt;/code&gt;, &lt;code&gt;lv&lt;/code&gt;, &lt;code&gt;mount&lt;/code&gt;. Hem kurulum hem doğrulama playbook'ları buradan okur.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ansible/playbooks/02_storage.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Güncellendi (v3)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;data_disks&lt;/code&gt; listesi &lt;code&gt;group_vars&lt;/code&gt;'a taşındı; dosya eksikse açık bir mesajla süreci durduran koruyucu &lt;code&gt;assert&lt;/code&gt; eklendi. Görevler v2 ile aynı kaldı.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ansible/playbooks/03_storage_verify.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yeni (v1.1)&lt;/td&gt;
&lt;td&gt;Reboot sonrası kalıcılık doğrulaması: doğrulama token'ları, reboot, taze fact'ler, assertion'lar ve doğrulama logları. İlk saha testinde tespit edilen &lt;code&gt;follow: true&lt;/code&gt; düzeltmesini içerir.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terraform/variables.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Güncellendi&lt;/td&gt;
&lt;td&gt;Yeni değişken: &lt;code&gt;scratch_disk_size_gb&lt;/code&gt; (varsayılan: &lt;code&gt;0&lt;/code&gt; = 5. disk kapalı).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terraform/vm.tf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Güncellendi&lt;/td&gt;
&lt;td&gt;Değişken sıfırdan büyük olduğunda &lt;code&gt;scsi5&lt;/code&gt; arayüzünde &lt;code&gt;scratch01&lt;/code&gt; serial'li diski üreten dinamik blok (&lt;code&gt;dynamic "disk"&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terraform/terraform.tfvars.example&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Güncellendi&lt;/td&gt;
&lt;td&gt;5. diskin büyüme iş akışıyla birlikte belgelenen yeni parametresi.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Kapsam sınırları yine bilinçli olarak dar tutuldu:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Kapsam Dahilinde&lt;/th&gt;
&lt;th&gt;Kapsam Dışında&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kurulum ve doğrulama playbook'larının paylaştığı tek &lt;code&gt;group_vars&lt;/code&gt; listesi&lt;/td&gt;
&lt;td&gt;Terraform state'ten beslenen dinamik envanter (Faz 4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Senaryolaştırılmış reboot ile boot kalıcılığının kanıtlanması&lt;/td&gt;
&lt;td&gt;Dosya sistemi kullanımının sürekli izlenmesi (Zabbix Faz 3'te geliyor)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;tfvars&lt;/code&gt; parametresiyle kontrol edilen opsiyonel beşinci disk&lt;/td&gt;
&lt;td&gt;Disk silme veya küçültme&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02, 03 ve büyüme çalıştırmalarının gerçek saha logları (&lt;code&gt;ok=15 changed=1&lt;/code&gt;, &lt;code&gt;ok=28 changed=2 failed=0&lt;/code&gt;, büyümede &lt;code&gt;ok=15 changed=5&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Rebootsuz hızlı test modunun logları (&lt;code&gt;verify_reboot=false&lt;/code&gt; belgelendi, henüz sahada loglanmadı)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Depolama Düzeni İçin Tek Gerçek Kaynak
&lt;/h2&gt;

&lt;p&gt;Faz 2 playbook'u disk listesini play başındaki bir &lt;code&gt;vars:&lt;/code&gt; bloğunda tanımlamıştı. İkinci bir playbook aynı bilgiye ihtiyaç duyduğu anda sorun başlar: doğrulama playbook'unun da aynı serial'lere, aynı VG/LV adlarına ve aynı bağlama noktalarına ihtiyacı vardır; çünkü altyapıyı kanıtlamak, kurulum playbook'unun kurduğunu iddia ettiği şeyi birebir denetlemek demektir. İki dosyada tek bir listenin kopyasını tutmak drift'in doğduğu yerdir: beşinci bir disk eklersiniz, bir playbook'u günceller, diğerini unutursunuz ve doğrulama adımı fark ettirmeden o diski denetlemeyi bırakır.&lt;/p&gt;

&lt;p&gt;Çözüm standart Ansible yöntemidir: grup değişkenleri (&lt;code&gt;group_vars&lt;/code&gt;). Envanter zaten &lt;code&gt;provisioned&lt;/code&gt; adında bir grup tanımlıyor; bu nedenle &lt;code&gt;inventory/group_vars/provisioned.yml&lt;/code&gt; konumundaki bir dosya, hiçbir playbook kodu çalışmadan önce o gruptaki her host için otomatik olarak yüklenir. İki playbook da artık doğrudan &lt;code&gt;data_disks&lt;/code&gt; değişkenini okur ve mimari bir garanti elde edilir: depoda tek bir liste vardır.&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/inventory/group_vars/provisioned.yml&lt;/span&gt;
&lt;span class="c1"&gt;# Faz 2 depolama düzeni için tek gerçek kaynak (Single Source of Truth).&lt;/span&gt;
&lt;span class="c1"&gt;# playbooks/02_storage.yml (kurulum) ve&lt;/span&gt;
&lt;span class="c1"&gt;# playbooks/03_storage_verify.yml (reboot kalıcılığı kanıtı) tarafından okunur.&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;span class="c1"&gt;# 03_storage_verify.yml varsayılan olarak makineyi reboot eder.&lt;/span&gt;
&lt;span class="c1"&gt;# Kesintisiz hızlı kontrol (smoke test):&lt;/span&gt;
&lt;span class="c1"&gt;# ansible-playbook playbooks/03_storage_verify.yml -e verify_reboot=false&lt;/span&gt;
&lt;span class="na"&gt;verify_reboot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Bu dosyadaki yorum satırları SCSI arayüzünü ve &lt;code&gt;tfvars&lt;/code&gt; değişkenini her serial'in yanında tutar; çünkü bu dosya Terraform tarafı ile Ansible tarafı arasındaki bir sözleşmedir. &lt;code&gt;verify_reboot&lt;/code&gt; değişkeni de playbook'un derinliklerine gömülmek yerine buraya kondu; böylece operatör ayarları aradığı yerde bulur.&lt;/p&gt;

&lt;p&gt;Listeyi playbook dışına taşımak dosya bulunamadığında ne olacağını değiştirir; bu yüzden her iki playbook da en başta bir koruyucu &lt;code&gt;assert&lt;/code&gt; ile açılır. Yanlış dizinden ya da bu grubu içermeyen bir envanterle çalıştırma durumunda süreç ortalarda tanımsız değişken hatasıyla patlamak yerine, henüz hiçbir şeye dokunmadan neden durduğunu açıkça bildirir:&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;Require the storage layout (group_vars/provisioned.yml)&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;data_disks is defined and data_disks | length &amp;gt; &lt;/span&gt;&lt;span class="m"&gt;0&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;data_disks tanımlanmamış. Depolama düzeni&lt;/span&gt;
      &lt;span class="s"&gt;ansible/inventory/group_vars/provisioned.yml dosyasında yaşar;&lt;/span&gt;
      &lt;span class="s"&gt;bu dosyanın var olduğunu ve playbook'un reponun kendi ansible.cfg'siyle,&lt;/span&gt;
      &lt;span class="s"&gt;provisioned grubuna karşı çalıştırıldığını kontrol edin.&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Ansible öncelik sıralaması (precedence) burada kritik bir tasarım kararı içerir:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Öncelik (Düşükten Yükseğe)&lt;/th&gt;
&lt;th&gt;Bu Tasarımdaki Anlamı&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;group_vars/provisioned.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tek gerçek kaynak; her iki playbook da olduğu gibi okur.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Playbook içindeki &lt;code&gt;vars:&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;group_vars&lt;/code&gt;'ı override eder; &lt;code&gt;02_storage.yml&lt;/code&gt; içinden özellikle kaldırıldı ki dosyadaki listeyle yarışamasın.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Komut satırındaki &lt;code&gt;--extra-vars&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Her şeyi override eder; tek seferlik geçici denemeler için belgelenmiş kaçış kapısı (&lt;code&gt;-e verify_reboot=false&lt;/code&gt;).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Reboot Testi: &lt;code&gt;03_storage_verify.yml&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Faz 2 saha oturumu depolama katmanını bırakıldığı anki haliyle doğrulamıştı: bağlı, boyutlandırılmış ve &lt;code&gt;df&lt;/code&gt; üzerinden okunabilir durumda. Ancak makinenin bir reboot sonrasında ayağa kalkıp kalkmayacağı test edilmemişti.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fstab&lt;/code&gt; girdileri yalnızca açılışta okunur. Açılıştaki LVM aktivasyonu, kurulum playbook'unun tetiklediği açık çalıştırmadan tamamen farklı bir mekanizmadır. Elle &lt;code&gt;mount&lt;/code&gt; komutu çalıştırıldığı için ayakta duran bir dosya sistemi ile kalıcı olan bir dosya sistemi, ilk yeniden başlatmaya kadar birbirinden ayırt edilemez.&lt;/p&gt;

&lt;p&gt;Doğrulama playbook'u, dikkatli bir sistem mühendisinin elle yapacağı adımları tekrarlanabilir çıktılara döker.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reboot Öncesi Belirteçler (Token &amp;amp; Marker)
&lt;/h3&gt;

&lt;p&gt;Kalıcılığı dizin adıyla değil içerikle denetlemek gerekir; çünkü yeni formatlanmış boş bir disk de aynı mount point'e bağlanabilir ama içindeki veriyi kaybetmiştir. Playbook, reboot öncesinde her dosya sistemine benzersiz bir token yazar:&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;Mint a one-run verification token&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;verify_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;phase2-{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ansible_facts.date_time.epoch&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;100000&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;random&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;Write a marker file into every data filesystem&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.copy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;content&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="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;verify_token&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;dest&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;}}/phase2-verify.txt"&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0644"&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;Token, her çalıştırmanın yalnızca kendi yazdığını doğrulaması için üretilir. Sabit bir string'e karşı kontrol yapmak önceki çalıştırmadan kalan bayat bir dosyada bile geçer; oysa reboot'tan saniyeler önce üretilen bir token'ı aramak, okunan verinin tam o oturumda diske yazıldığını garantiler. Dosya içeriği mount yolu ile token'ın birleşimidir; yani yanlışlıkla başka diske yazılan bir belirteç de doğrulamadan geçemez.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reboot ve Fact Yenileme Mantığı
&lt;/h3&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;Reboot the VM (the moment of truth for fstab and LVM)&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.reboot&lt;/span&gt;&lt;span class="pi"&gt;:&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;Phase&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;verification&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reboot:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;proving&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;fstab&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;LVM&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;boot&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;persistence"&lt;/span&gt;
    &lt;span class="na"&gt;pre_reboot_delay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
    &lt;span class="na"&gt;post_reboot_delay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="na"&gt;reboot_timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600&lt;/span&gt;
    &lt;span class="na"&gt;test_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uptime"&lt;/span&gt;
  &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;verify_reboot | default(true) | bool&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;Refresh facts after the reboot (pre-reboot facts are stale)&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.setup&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;verify_reboot | default(true) | bool&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Bu iki görevde iki hayati teknik detay bulunur:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;ansible.builtin.setup&lt;/code&gt; görevi gereksiz görünür ama zorunludur. &lt;code&gt;gather_facts&lt;/code&gt; play'in en başında tek bir kez çalışır; dolayısıyla reboot sonrasında &lt;code&gt;ansible_facts.mounts&lt;/code&gt; listesi hâlâ makinenin açılış öncesi dünyasını tarif eder. Reboot sonrası &lt;code&gt;setup&lt;/code&gt; modülünü çağırmak, mount kontrollerinin güncel gerçeği okumasını sağlar.&lt;/li&gt;
&lt;li&gt;Koşulda yer alan &lt;code&gt;| bool&lt;/code&gt; filtresi zorunludur. Komut satırından &lt;code&gt;--extra-vars&lt;/code&gt; ile geçilen değerler Ansible'a string olarak ulaşır. Jinja motorunda &lt;code&gt;"false"&lt;/code&gt; string'i truthy (doğru kabul edilen) bir değerdir; bu filtre konmazsa &lt;code&gt;-e verify_reboot=false&lt;/code&gt; parametresi verildiğinde playbook tam da reboot etmemesini istediğiniz anda makineyi yeniden başlatır.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  LVM Kontrolü: Neden &lt;code&gt;lv_attr&lt;/code&gt; Karakterleri Değil?
&lt;/h3&gt;

&lt;p&gt;LVM, volüm durumunu &lt;code&gt;lv_attr&lt;/code&gt; öznitelik dizgisinin 5. karakterinde kodlar (&lt;code&gt;a&lt;/code&gt; = active). Ancak pozisyona dayalı karakter okumak, araçlar raporlama düzenini değiştirdiğinde sessizce patlayan kırılgan bir yöntemdir.&lt;/p&gt;

&lt;p&gt;Playbook bunun yerine &lt;code&gt;lvs&lt;/code&gt; komutundan JSON raporu alarak volüm sayısını doğrular, ardından sistemin doğrudan kendisine sorar: aktif bir mantıksal volüm aygıt düğümünü &lt;code&gt;/dev/vg/lv&lt;/code&gt; altında sunar, aktif olmayan bir volümün düğümü oluşmaz. Bu yüzden her volüm için &lt;code&gt;stat&lt;/code&gt; çalıştırmak hem daha sade hem daha güvenilir bir testtir.&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 LVM logical volume report (JSON)&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;lvs --reportformat json --noheadings -o vg_name,lv_name,lv_attr&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;lvs_state&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;Parse the LVM report&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;lv_rows&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;(lvs_state.stdout&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;from_json).report[0].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;Exactly the expected logical volumes must exist&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;lv_rows | length == data_disks | length&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;Check every logical volume's device node&lt;/span&gt;
  &lt;span class="na"&gt;ansible.builtin.stat&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;/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;follow&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;# /dev/vg/lv -&amp;gt; /dev/dm-X symlink'ini takip etmek şart&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="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lv_nodes&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 logical volume must be active after the reboot&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="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;lv_nodes.results[idx].stat.exists&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;lv_nodes.results[idx].stat.isblk&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;The volume group {{ item.vg }} was not activated after the reboot.&lt;/span&gt;
      &lt;span class="s"&gt;Diagnose inside the VM with: systemctl status lvm2-activation.service,&lt;/span&gt;
      &lt;span class="s"&gt;then check vgchange -ay.&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="na"&gt;loop_control&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;index_var&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;idx&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;İlk saha oturumunun öğrettiği &lt;code&gt;follow: true&lt;/code&gt; dersi tam buraya aittir. &lt;code&gt;/dev/vg/lv&lt;/code&gt; bir blok aygıtı değil, udev tarafından yönetilen bir sembolik bağdır (&lt;code&gt;symlink&lt;/code&gt;). &lt;code&gt;stat&lt;/code&gt; modülüne symlink'i takip etmesi söylenmediğinde bağın kendisini inceler; sonuç olarak &lt;code&gt;islnk: true&lt;/code&gt; dönerken &lt;code&gt;isblk: false&lt;/code&gt; kalır ve çalışan sistemde sahte bir alarm (false positive) üretir.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fstab&lt;/code&gt; kontrolü ise mount modülünün yazdığı satırı doğrudan denetler: &lt;code&gt;/dev/mapper&lt;/code&gt; alias'ı yerine verilen tam aygıt yolu (&lt;code&gt;/dev/vg_data/lv_data&lt;/code&gt;) ve bağlama noktası. Hem aygıtı hem hedefi aramak iki arıza modunu birden yakalar: satırın hiç olmaması veya olup yanlış yere işaret etmesi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kesintisiz Hızlı Kontrol Modu (&lt;code&gt;verify_reboot=false&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Reboot istenmeyen anlarda playbook &lt;code&gt;-e verify_reboot=false&lt;/code&gt; ile çalıştırılarak kesintisiz bir denetim aracına (smoke test) dönüşür. Bu modda hangi kontrolün neyi kanıtladığı net biçimde bilinmelidir:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Denetim&lt;/th&gt;
&lt;th&gt;Reboot İle (Varsayılan)&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;verify_reboot=false&lt;/code&gt; İle (Smoke Test)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Belirteç dosyaları (byte-to-byte)&lt;/td&gt;
&lt;td&gt;Veri açılışı atlattı&lt;/td&gt;
&lt;td&gt;Yalnızca oturum içi doğrulama&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mount durumu (&lt;code&gt;fstype: xfs&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;fstab&lt;/code&gt; açılış aktivasyonu çalıştı&lt;/td&gt;
&lt;td&gt;Mevcut bağlı durum doğru&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LV aygıt düğümleri mevcut&lt;/td&gt;
&lt;td&gt;Açılış zamanı LVM aktivasyonu çalıştı&lt;/td&gt;
&lt;td&gt;LV'ler şu anda aktif&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;fstab&lt;/code&gt; satırları mevcut&lt;/td&gt;
&lt;td&gt;Kalıcılık beyan edilmiş, sadece canlıda kalmamış&lt;/td&gt;
&lt;td&gt;Aynı&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serial'ler tek diske çözülüyor&lt;/td&gt;
&lt;td&gt;Kimlik şeması açılışı atlattı&lt;/td&gt;
&lt;td&gt;Kimlik şeması şu an geçerli&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Dört Diskten Fazlası: &lt;code&gt;scratch01&lt;/code&gt; Genişletme İş Akışı
&lt;/h2&gt;

&lt;p&gt;Faz 2'deki büyütme senaryosu en yaygın talebi yanıtlamıştı: aynı diski büyütmek. İkinci yaygın talep ise yeni bir iş yükü için yeni bir disk eklemektir.&lt;/p&gt;

&lt;p&gt;Manuel dünyada bu işlem hipervizörde ayrı, guest içinde ayrı konsol adımları demektir ve aygıt harfi tahmin oyununun en çok can sıktığı yerdir; çünkü yeni bir disk kendisinden sonraki disklerin sıralamasını kaydırabilir.&lt;/p&gt;

&lt;p&gt;Terraform tarafı bunu dinamik bir blokla çözer. HCL blok seviyesinde doğrudan &lt;code&gt;if&lt;/code&gt; anahtarı sunmaz; bu yüzden parametre verildiğinde tek elemanlı, verilmediğinde boş liste dönen bir &lt;code&gt;dynamic "disk"&lt;/code&gt; bloğu kullanılır. Varsayılan sıfırken plan içinde &lt;code&gt;scsi5&lt;/code&gt; diski hiç yer almaz:&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="c1"&gt;# terraform/vm.tf (Opsiyonel 5. veri diski)&lt;/span&gt;
&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"scratch_disk_size_gb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Opsiyonel 5. veri diski (serial: scratch01), GB. 0 = kapali."&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;number&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# proxmox_virtual_environment_vm.test_vm kaynagi icinde:&lt;/span&gt;
&lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="s2"&gt;"disk"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&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;scratch_disk_size_gb&lt;/span&gt; &lt;span class="err"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="err"&gt;?&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;scratch_disk_size_gb&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="nx"&gt;content&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;"scsi5"&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;disk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&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;"scratch01"&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="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Ansible tarafında yeni kod yazılmaz, sadece sözleşmeye yeni bir satır eklenir. Sorumluluk dağılımı bellidir:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Taraf&lt;/th&gt;
&lt;th&gt;Sorumluluk Alanı&lt;/th&gt;
&lt;th&gt;Tanımlandığı Yer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Terraform&lt;/td&gt;
&lt;td&gt;Hangi disklerin var olduğu, arayüzler, boyutlar, serial'ler&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;terraform/vm.tf&lt;/code&gt; + &lt;code&gt;tfvars&lt;/code&gt; ayarları&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ansible&lt;/td&gt;
&lt;td&gt;Her serial'in guest içinde neye dönüştüğü: &lt;code&gt;vg&lt;/code&gt;, &lt;code&gt;lv&lt;/code&gt;, mount noktası&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inventory/group_vars/provisioned.yml&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kernel&lt;/td&gt;
&lt;td&gt;Her serial'in o anda hangi disk harfi olduğu&lt;/td&gt;
&lt;td&gt;Her çalıştırmada sıfırdan çözülür, asla kalıcı yazılmaz&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Büyütme (Resize) ile Yeni Disk Ekleme (Attach) Arasındaki Asimetri
&lt;/h3&gt;

&lt;p&gt;Saha oturumu bu iki eylem arasındaki farkı netleştirdi:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operasyon&lt;/th&gt;
&lt;th&gt;VM Durumu&lt;/th&gt;
&lt;th&gt;Serial Guest'te Görünür mü?&lt;/th&gt;
&lt;th&gt;Görünmezse Yapılacak Eylem&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mevcut diski büyütmek (&lt;code&gt;data&lt;/code&gt; 20 -&amp;gt; 30 GB)&lt;/td&gt;
&lt;td&gt;Çalışıyor (Online)&lt;/td&gt;
&lt;td&gt;Anında (Kernel görünümü anında yenilenir)&lt;/td&gt;
&lt;td&gt;Gerek yok; sahada kanıtlanmış online işlem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Yeni disk takmak (&lt;code&gt;scsi5&lt;/code&gt; &lt;code&gt;scratch01&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Çalışıyor (Online)&lt;/td&gt;
&lt;td&gt;Tam bir VM başlatması gerektirebilir (saha oturumunda: anında görüldü)&lt;/td&gt;
&lt;td&gt;PVE host üzerinde: &lt;code&gt;qm shutdown 200 &amp;amp;&amp;amp; qm start 200&lt;/code&gt;, sonra 02'yi tekrar çalıştır&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tam bir VM başlatmasından sonraki durum&lt;/td&gt;
&lt;td&gt;Taze başladı&lt;/td&gt;
&lt;td&gt;Her zaman (konfigürasyon ve QEMU hemfikir)&lt;/td&gt;
&lt;td&gt;Teşhis: `qm config 200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Büyütme online, yeni takma da (genellikle) online:&lt;/strong&gt;&lt;br&gt;
Mevcut diski büyütmek tamamen kesintisiz kalır. Yeni disk takmak da saha oturumunda makine çalışırken online tamamlandı; ancak serial'in konfigürasyonun gerisinde kaldığı durumlar için belgelenmiş tam kapat-aç adımı el altında beklemelidir.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uçtan uca büyüme iş akışı:&lt;br&gt;
{% raw %}&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;# 1. ctrl-01'de: diski aktif et (terraform/terraform.tfvars)&lt;/span&gt;
scratch_disk_size_gb &lt;span class="o"&gt;=&lt;/span&gt; 5

&lt;span class="c"&gt;# 2. apply: disk makine calisirken takilir&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/proxmox-automation/terraform &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; terraform apply

&lt;span class="c"&gt;# 3. duzen girdisini group_vars/provisioned.yml dosyasina ekle&lt;/span&gt;
&lt;span class="c"&gt;# - serial: scratch01&lt;/span&gt;
&lt;span class="c"&gt;#   vg: vg_scratch&lt;/span&gt;
&lt;span class="c"&gt;#   lv: lv_scratch&lt;/span&gt;
&lt;span class="c"&gt;#   mount: /srv/scratch&lt;/span&gt;

&lt;span class="c"&gt;# 4. baglamayi insa et (ayni playbook, fazladan bir dongu iterasyonu)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../ansible &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ansible-playbook playbooks/02_storage.yml

&lt;span class="c"&gt;# 5. Eger 4. adim scratch01 NOT FOUND derse: PVE node'unda tam durdur/baslat&lt;/span&gt;
&lt;span class="c"&gt;# qm shutdown 200 &amp;amp;&amp;amp; qm start 200&lt;/span&gt;
&lt;span class="c"&gt;# ardindan 4. adimi tekrar calistir&lt;/span&gt;

&lt;span class="c"&gt;# 6. reboot dahil kanitla&lt;/span&gt;
ansible-playbook playbooks/03_storage_verify.yml
ssh ubuntu@192.168.122.50 &lt;span class="s1"&gt;'df -h /srv/scratch'&lt;/span&gt;

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

&lt;/div&gt;

&lt;h3&gt;
  
  
  Upstream İmaj Yenilenmesi Durumu
&lt;/h3&gt;

&lt;p&gt;Beşinci diski takarken çalıştırılan apply, plan çıktısında beklenmedik bir satır getirdi: &lt;code&gt;Plan: 1 to add, 2 to change, 1 to destroy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Yok edilen nesne VM değildi; &lt;code&gt;proxmox_download_file.ubuntu_image&lt;/code&gt; kaynağıydı. Canonical, Ubuntu cloud imajını upstream depoda güncellemiş, dosya boyutu 861.837.824 bayttan 864.818.688 bayta çıkmıştı. Provider boyut uyuşmazlığını görünce eski dosyayı silip yenisini indirdi. Apply süresi bu indirme nedeniyle 5 dakika sürdü; fakat VM yerinde güncellendi, kesinti yaşanmadı. Bu tazelik yerine tam tekrarlanabilirlik isteyenler &lt;code&gt;template.tf&lt;/code&gt; içinde &lt;code&gt;overwrite = false&lt;/code&gt; parametresini kullanabilir.&lt;/p&gt;


&lt;h2&gt;
  
  
  Saha Oturumu ve Terminal Çıktıları
&lt;/h2&gt;

&lt;p&gt;Aşağıdaki runbook tablosu Faz 2 Addendum'un sahadaki tam icra sırasıdır:&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;Komut&lt;/th&gt;
&lt;th&gt;Geri Alınan Çıktı&lt;/th&gt;
&lt;th&gt;Durum&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctrl-01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd ~/proxmox-automation &amp;amp;&amp;amp; unzip -o proxmox-automation.zip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dosyalar güncellendi&lt;/td&gt;
&lt;td&gt;Tamamlandı&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctrl-01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cd ansible &amp;amp;&amp;amp; ansible-playbook playbooks/02_storage.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PLAY RECAP&lt;/td&gt;
&lt;td&gt;Saha: &lt;code&gt;ok=15 changed=1&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctrl-01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ansible-playbook playbooks/03_storage_verify.yml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Debug satırları, assert satırları, PLAY RECAP&lt;/td&gt;
&lt;td&gt;Saha: &lt;code&gt;ok=28 changed=2 failed=0&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctrl-01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ansible-playbook playbooks/03_storage_verify.yml -e verify_reboot=false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rebootsuz mod recap çıktısı&lt;/td&gt;
&lt;td&gt;Opsiyonel, henüz çalıştırılmadı&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctrl-01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;tfvars düzenle: &lt;code&gt;scratch_disk_size_gb = 5&lt;/code&gt;, sonra &lt;code&gt;terraform apply&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Apply çıktısı (imaj tazeleme + scsi5, VM yerinde)&lt;/td&gt;
&lt;td&gt;Saha: tamamlandı (5 dk: imaj indirme)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctrl-01&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scratch01&lt;/code&gt;'i group_vars'a ekle, &lt;code&gt;02_storage.yml&lt;/code&gt; tekrar çalıştır&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;scratch01&lt;/code&gt; mapping satırı, PLAY RECAP&lt;/td&gt;
&lt;td&gt;Saha: &lt;code&gt;ok=15 changed=5&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;ok=14&lt;/code&gt;'ten &lt;code&gt;ok=15&lt;/code&gt;'e Geçişin Mantığı
&lt;/h3&gt;

&lt;p&gt;Faz 2 rehberinde &lt;code&gt;02_storage.yml&lt;/code&gt; için recap &lt;code&gt;ok=14 changed=1&lt;/code&gt; olarak kaydedilmişti. v3 refactor'ünde liste &lt;code&gt;group_vars&lt;/code&gt;'a taşındı ve play başına koruyucu assert görevi eklendi. Geçen bir assertion recap'te fazladan bir &lt;code&gt;ok&lt;/code&gt; demektir: 14 görev artı koruyucu assert eşittir 15. Depolama işinin kendisinde hiçbir şey değişmedi; recap'ler arasındaki bir görevlik fark, &lt;code&gt;group_vars&lt;/code&gt; hamlesinin sisteme gizli bir yük bindirmediğinin somut kanıtıdı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/ansible# ansible-playbook playbooks/02_storage.yml
&lt;span class="c"&gt;# ... eslestirme ve kontroller gecti ...&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;
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 gecisi&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;15 &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;h3&gt;
  
  
  İlk Doğrulama Denemesi ve Düzeltme Adımı
&lt;/h3&gt;

&lt;p&gt;İlk doğrulama denemesi reboot'a kadar yeşil aktı: token'lar yazıldı, eşleşme alındı, makine yeniden başladı, token'lar byte'ı byte'ına geri okundu. Ancak mantıksal volüm kontrolünde sistem sahte bir alarmla (false positive) durdu:&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/03_storage_verify.yml
TASK &lt;span class="o"&gt;[&lt;/span&gt;Every logical volume must be active after the reboot] &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;vg_var/lv_var&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;"assertion"&lt;/span&gt;: &lt;span class="s2"&gt;"lv_nodes.results[0].stat.isblk"&lt;/span&gt;,
    &lt;span class="s2"&gt;"evaluated_to"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
    &lt;span class="s2"&gt;"msg"&lt;/span&gt;: &lt;span class="s2"&gt;"The volume group vg_var was not activated after the reboot ..."&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# ... (vg_log, vg_data, vg_backup: dördü birden ayni anda basarisiz)&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;18 &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;1

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;follow: true&lt;/code&gt; eklenip düzeltme doğrulandıktan sonra ikinci deneme başarıyla sonuçlandı:&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# &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"follow:"&lt;/span&gt; playbooks/03_storage_verify.yml
    follow: &lt;span class="nb"&gt;true&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-playbook playbooks/03_storage_verify.yml
TASK &lt;span class="o"&gt;[&lt;/span&gt;Show the mapping before the reboot] &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 = /dev/sde"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# ... (log01 = /dev/sdd, data01 = /dev/sdc, backup01 = /dev/sdb)&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Reboot the VM &lt;span class="o"&gt;(&lt;/span&gt;the moment of truth ...&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]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Every logical volume must be active after the reboot] &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;vg_var/lv_var&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="c"&gt;# ... (vg_log/lv_log, vg_data/lv_data, vg_backup/lv_backup)&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Show the mapping before vs after ...] &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: /dev/sde before -&amp;gt; /dev/sde after (vg_var/lv_var on /srv/var)"&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: /dev/sdb before -&amp;gt; /dev/sdb after (vg_backup/lv_backup on /srv/backup)"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# ... (log01, data01)&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;28 &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;p&gt;Buradaki sayılar net bir hesaba dayanır:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;changed=2&lt;/code&gt;: Doğrulama çalıştırması için beklenen minimumdur; token dosyaları her çalıştırmada taze yazılır ve &lt;code&gt;reboot&lt;/code&gt; modülü gerçek bir eylemdir.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ok=28&lt;/code&gt;: İlk denemedeki &lt;code&gt;ok=18&lt;/code&gt;'in üzerine 10 yeni kontrol eklenmedi; ilk deneme assert'te durduğu için çalışamayan boot sonrası eşleşme, &lt;code&gt;fstab&lt;/code&gt; çıktıları, &lt;code&gt;findmnt&lt;/code&gt;, &lt;code&gt;lsblk&lt;/code&gt; ve &lt;code&gt;df&lt;/code&gt; görevleri nihayet çalışabildi.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bu ikinci denemede harfler de değişmedi (&lt;code&gt;var01&lt;/code&gt; hem öncesinde hem sonrasında &lt;code&gt;sde&lt;/code&gt;); ama bu bir garanti değil, o boot'a özgü bir şans. Şema harflerin sabit kalmasına değil, sadece serial'lerin sabit kalmasına güveniyor; birkaç bölüm sonraki büyüme çalıştırması, harfler gerçekten döndüğünde de aynı yeşil sonucu veriyor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Genişletme Çalıştırması: Aygıt Harflerinin Kayması Testi
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;scratch_disk_size_gb = 5&lt;/code&gt; ile disk eklendikten sonra &lt;code&gt;02_storage.yml&lt;/code&gt; çalıştırıldı:&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;Show the serial to device mapping ...] &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;scratch01&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;"scratch01 (vg_scratch/lv_scratch -&amp;gt; /srv/scratch) = /dev/sdf"&lt;/span&gt; &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_scratch&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;# (vg_var, vg_log, vg_data, vg_backup: ok, dokunulmadi)&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;15 &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;&lt;code&gt;changed=5&lt;/code&gt; tam olarak yeni bir diskin ilk çalıştırma işini yapan beş görevdir: PV görevi (&lt;code&gt;pvresize&lt;/code&gt; geçişi), VG, LV, XFS ve mount. Mevcut dört disk hiçbir değişiklik bildirmedi; VG, LV, XFS ve mount maddeleri &lt;code&gt;ok&lt;/code&gt; olarak döndü.&lt;/p&gt;

&lt;p&gt;Ardından çalıştırılan doğrulama playbook'u, bu tasarımın en büyük sınavını verdi. Beşinci disk takıldıktan sonra yapılan reboot sırasında kernel aygıt harflerini tamamen döndürdü:&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/03_storage_verify.yml
TASK &lt;span class="o"&gt;[&lt;/span&gt;Show the mapping before vs after ...] &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: /dev/sde before -&amp;gt; /dev/sdf after (vg_var/lv_var on /srv/var)"&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;scratch01&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;"scratch01: /dev/sdf before -&amp;gt; /dev/sdb after (vg_scratch/lv_scratch on /srv/scratch)"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;# (log01: sdd -&amp;gt; sde, data01: sdc -&amp;gt; sdd, backup01: sdb -&amp;gt; sdc)&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;28 &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;p&gt;Açılışta &lt;code&gt;var01&lt;/code&gt; diski &lt;code&gt;sde&lt;/code&gt;'den &lt;code&gt;sdf&lt;/code&gt;'ye kaydı; yeni eklenen &lt;code&gt;scratch01&lt;/code&gt; ise &lt;code&gt;sdf&lt;/code&gt; iken açılışta &lt;code&gt;sdb&lt;/code&gt; oldu. Diğer tüm komşular birer koltuk ötelendi.&lt;/p&gt;

&lt;p&gt;Buna rağmen çalıştırma tamamen yeşil kaldı; çünkü yığındaki hiçbir şey bir harfi adreslemiyor: &lt;code&gt;fstab&lt;/code&gt; &lt;code&gt;/dev/vg/lv&lt;/code&gt; yollarını arıyor, LVM disklerin üzerindeki meta veriyi okuyor ve playbook'lar her çalıştırmada haritalamayı kernel görüşünden taze kuruyor. Recap yine &lt;code&gt;ok=28 changed=2&lt;/code&gt; kaldı; çünkü listeye beşinci bir girdi eklemek görev sayısını değil, döngü iterasyonlarını artırır: playbook makineyle birlikte büyüyor, hareketli parça sayısı ise hiç artmıyor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Operasyonel Not:&lt;/strong&gt; Kontrol düğümünde &lt;code&gt;df -h /srv/scratch&lt;/code&gt; çalıştırmak "No such file or directory" der; çünkü mount kontrol düğümünde değil, misafir makinededir. Doğrulama çıktısı SSH üzerinden misafirden okunmalıdır:&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:~# ssh ubuntu@192.168.122.50 &lt;span class="s1"&gt;'df -h /srv/scratch'&lt;/span&gt;
Filesystem                         Size  Used Avail Use% Mounted on
/dev/mapper/vg_scratch-lv_scratch  5.0G  130M  4.9G   3% /srv/scratch

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Depolama Katmanı Kapandı: Sırada Ne Var?
&lt;/h2&gt;

&lt;p&gt;Depolama katmanı serinin taahhüt ettiği her iki boyutta da tamamlandı: golden template ve dört serial ile deklaratif olarak inşa edildi, tek bir &lt;code&gt;tfvars&lt;/code&gt; düzenlemesiyle online büyütüldü ve bu addendum ile birlikte tek bir komutla reboot sınavından geçirildi.&lt;/p&gt;

&lt;p&gt;Tek gerçek kaynaklı &lt;code&gt;group_vars&lt;/code&gt; mimarisi, doğrulama playbook'u ve büyüme iş akışı sahada bizzat çalıştı. Alınan dersler; &lt;code&gt;stat&lt;/code&gt;'ın sembolik bağları yalnızca açıkça istendiğinde takip ettiği, serial hotplug'ın şanslı bir günde online tamamlandığı ve upstream bir imajın pipeline ortasında kendini yenileyebileceği, gelecekteki çalıştırmaların bulacağı yerlere not edildi.&lt;/p&gt;

&lt;p&gt;Her depolama değişikliğinden (büyütme ya da yeni disk ekleme) sonra operasyonel alışkanlık aynıdır:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Önce kurulum playbook'unu çalıştır (&lt;code&gt;02_storage.yml&lt;/code&gt;),&lt;/li&gt;
&lt;li&gt;Ardından doğrulama playbook'unu çalıştır (&lt;code&gt;03_storage_verify.yml&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;İlki durumu yakınsar; ikincisi makinenin gece saat 3'te tek başına ayağa kalkabileceğini somut terminal çıktılarıyla kanıtlar.&lt;/p&gt;

&lt;p&gt;Faz 2 tamamen kapandı. Sıradaki durak Faz 3:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Template içindeki eski &lt;code&gt;/install&lt;/code&gt; dizinini gerçek Ansible rollerine dönüştürmek,&lt;/li&gt;
&lt;li&gt;Mount noktalarına anlık denetim yerine kalıcı bir gözlemci atayacak &lt;strong&gt;Zabbix Agent 2&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;Merkezi güvenlik ajanları ve log diskini salt bir depolama alanından pipeline parçasına dönüştürecek &lt;strong&gt;QRadar rsyslog&lt;/strong&gt; yönlendirme kuralları.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://github.com/Hakanbaban53/proxmox-automation" rel="noopener noreferrer"&gt;GitHub Deposu&lt;/a&gt;&lt;/p&gt;

</description>
      <category>proxmox</category>
      <category>terraform</category>
      <category>ansible</category>
      <category>devops</category>
    </item>
    <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>
  </channel>
</rss>
