Proxmox Otomasyonu Faz 2: Serial ile Kimliklendirilmiş Depolama, Kesintisiz LVM + XFS

Bir önceki fazda pipeline’ın temelini attık: tek bir terraform apply 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: /var, log, data, backup ayrı LUN’larda, her biri kendi büyüme takvimiyle.

Ş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.

Hedef: dört disk, kalıcı kimlik

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.

Bileşen Sürüm/Not
Proxmox VE 9.2
Terraform 1.15.x
bpg/proxmox provider 0.111.1
ansible-core 2.20
Yeni bağımlılık community.general, ansible.posix
Dosya sistemi XFS

Kapsam, Faz 1’deki gibi bilinçli olarak dar tutuluyor; her hareketli parça tek başına doğrulanabilsin diye:

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

Problem: disk tahmini ve elle büyütme

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: /var, log, data, backup, her biri kendi LUN’unda, kendi büyüme takviminde. Bir müşteri /data‘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.

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 /dev/sdb 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 scsi3‘ün, yapılandırdığınız üçüncü disk olduğuna dair hiçbir söz yok.

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.

Doğru disk bulunduktan sonra ritüelin kendisi beş komutluk bir silsileden ibaretti: partition’ı genişletmek için growpart ya da fdisk, LVM’e yeni boyutu öğretmek için pvresize, mantıksal volümü büyütmek için lvextend, dosya sistemini büyütmek için xfs_growfs. 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.

Tasarım: kimlik serial’da

Disk harfi, kernel’in diski nerede bulduğudur. Serial, diskin ne olduğudur. Diskleri ne olduklarıyla adresle.

Bu tasarımdaki her disk, Terraform’da set edilen, Proxmox konfigürasyonundan geçen, QEMU tarafından guest’e sunulan ve kernel tarafından lsblk‘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.

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

Katman Değer
terraform.tfvars data_disk_size_gb = 20
terraform (vm.tf) disk { interface = "scsi3" serial = "data01" size = 20 }
pve-a (qm config 200) scsi3: nfs-shared:vm-200-disk-2,size=20,serial=data01
pve-a (qm showcmd 200) scsi-hd aygıt satırında serial=data01
guest (lsblk -o SERIAL) sdc disk 20G data01 ← kernel’in gördüğü
ansible (02_storage.yml) dev: "https://dev.to/dev/sdc" (lsblk’den taze çözülmüş)
sonuç vg_data/lv_data, /srv/data‘ya bağlı

Ders, son iki halkada yatıyor. Bu playbook’un ilk sürümü serial’leri klasik udev yolu /dev/disk/by-id üzerinden çözüyordu; bu yığında o dizin serial-adlı girdileri hiç oluşturmadı. Kernel lsblk‘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 /dev/vg/lv 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.

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

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

Bu garantilerin üstüne beş yerleşim kararı geliyor:

Karar Gerekçe
Disk başına bir VG ve bir LV 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
LV, VG’nin yüzde yüzü LV her zaman diskine eşit; VG büyüyünce lvol onu otomatik uzatıyor, hiçbir şey değişmediğinde no-op olarak boş dönüyor
XFS, ext4 değil Hedef ortamdaki DB-sunucu pratiği; xfs_growfs‘le online büyüyor; küçültülememesi provider’ın sadece-büyüme kuralıyla zaten örtüşüyor
Lab, /srv/* altına bağlanıyor Canlı /var‘ı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
Boyutlar tfvars parametresi 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

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 lvol‘ü shrink: false 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öç.

Terraform: dört diski tanımlamak

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.

disk {
  datastore_id = var.storage_id
  interface    = "scsi1"
  size         = var.var_disk_size_gb
  serial       = "var01"
  ssd          = true
  discard      = "on"
}
disk {
  datastore_id = var.storage_id
  interface    = "scsi2"
  size         = var.log_disk_size_gb
  serial       = "log01"
  ssd          = true
  discard      = "on"
}
disk {
  datastore_id = var.storage_id
  interface    = "scsi3"
  size         = var.data_disk_size_gb
  serial       = "data01"
  ssd          = true
  discard      = "on"
}
disk {
  datastore_id = var.storage_id
  interface    = "scsi4"
  size         = var.backup_disk_size_gb
  serial       = "backup01"
  ssd          = true
  discard      = "on"
}

ssd ve discard 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, discard on 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.

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.

# terraform.tfvars.example (Faz 2 eki)
var_disk_size_gb    = 10  # scsi1 serial=var01    -> /srv/var
log_disk_size_gb    = 10  # scsi2 serial=log01    -> /srv/log
data_disk_size_gb   = 20  # scsi3 serial=data01   -> /srv/data (büyütme demosu)
backup_disk_size_gb = 15  # scsi4 serial=backup01 -> /srv/backup

Değişken Varsayılan Serial Bağlama noktası
var_disk_size_gb 10 var01 /srv/var
log_disk_size_gb 10 log01 /srv/log
data_disk_size_gb 20 (demoda 30’a çıkıyor) data01 /srv/data
backup_disk_size_gb 15 backup01 /srv/backup

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.

~ resource "proxmox_virtual_environment_vm" "test_vm" {
    ~ agent { enabled = true }
    ~ disk {
        ~ serial = "data01" -> (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.

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 yes 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.

Apply: disk, VM çalışırken beliriyor

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.

root@ctrl-01:~/proxmox-automation/terraform# terraform apply
proxmox_virtual_environment_vm.test_vm: Modifying... [id=200]
proxmox_virtual_environment_vm.test_vm: Modifications complete after 12s

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

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, qm config 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: qm shutdown 200 && qm start 200. 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.

İki taraftan doğrulama

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.

WebUI Üzerinden Görünümü

# pve-a'da: saklanan konfigürasyon serial'leri taşıyor...
root@pve-a:~# qm config 200 | grep -E "scsi[1-4]:"
scsi1: nfs-shared:vm-200-disk-0,size=10,serial=var01,ssd=1,discard=on
scsi2: nfs-shared:vm-200-disk-1,size=10,serial=log01,ssd=1,discard=on
scsi3: nfs-shared:vm-200-disk-2,size=20,serial=data01,ssd=1,discard=on
scsi4: nfs-shared:vm-200-disk-3,size=15,serial=backup01,ssd=1,discard=on

# ...çalışan QEMU süreci de öyle:
root@pve-a:~# qm showcmd 200 --pretty | grep -o "serial=[a-z0-9]*"
serial=var01
serial=log01
serial=data01
serial=backup01

# guest içinde: kernel her serial'i kendi görüşünde raporluyor
ubuntu@vm-test-01:~$ lsblk -o NAME,SIZE,TYPE,SERIAL
NAME SIZE TYPE SERIAL
sda  10G  disk drive-scsi0   <- OS diski: QEMU'nun varsayılan kimliği, serial yok
sdb  15G  disk backup01
sdc  20G  disk data01
sdd  10G  disk log01
sde  10G  disk var01

Bu çıktıda üç ayrıntı dikkati hak ediyor. OS diski drive-scsi0 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 vm-200-disk-0.qcow2 iken dört ham veri diski vm-200-disk-0‘dan vm-200-disk-3‘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 /dev/disk/by-id‘nin lsblk çı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.

Rebuild dolambacı: önce başarısız olan apply

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ı, terraform init 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.

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't convert a template to a template ...
╵
# apply #1 burada durdu; template kaynağı state'te kaldı, tainted işaretlendi

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, ErrorContains("already exists") etrafındaki WithAlreadyDoneCheck). 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.

root@ctrl-01:~/proxmox-automation/terraform# terraform apply
Note: Objects have changed outside of Terraform since the last
"terraform apply" ... the following changes ... has been deleted
- ...
proxmox_virtual_environment_vm.ubuntu_template: Creating...
proxmox_virtual_environment_vm.ubuntu_template: Creation complete after 10s
proxmox_virtual_environment_vm.test_vm: Creating...
proxmox_virtual_environment_vm.test_vm: Creation complete after 5s

Apply complete! Resources: 2 added ...
# template: ~10 sn; test_vm: ~5 sn; ikinci denemede ikisi de temiz kuruldu

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 qm destroy 9000 onu kaldırıyor. Ve bir apply geride kalmış bir şeye çarpıp düşerse, hatayı oku, sonra terraform state komutlarına uzanmadan önce tekrar apply et; provider’ın okuma yolu tam bu durumu yakınsatmak için inşa edilmiş.

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:

root@ctrl-01:~# ssh ubuntu@192.168.122.50
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
...
root@ctrl-01:~# ssh-keygen -f ~/.ssh/known_hosts -R 192.168.122.50
# Host 192.168.122.50 found: line 2
192.168.122.50 Host key removed.
root@ctrl-01:~# ssh ubuntu@192.168.122.50  # yeni anahtarı kabul et

Faz 1’i yazarken bu sahneye “bunu sonradan öğrendim” diye not düşmüştüm; söz burada tutuldu.

Ansible storage playbook’u

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:

# ansible/requirements.yml
collections:
  - name: community.general
    source: https://galaxy.ansible.com
  - name: ansible.posix
    source: https://galaxy.ansible.com
root@ctrl-01:~/proxmox-automation/ansible# ansible-galaxy collection install -r requirements.yml

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.

# playbooks/02_storage.yml (data_disks sözleşmesi)
vars:
  data_disks:
    - serial: var01 # scsi1, boyut: var_disk_size_gb
      vg: vg_var
      lv: lv_var
      mount: /srv/var
    - serial: log01 # scsi2, boyut: log_disk_size_gb
      vg: vg_log
      lv: lv_log
      mount: /srv/log
    - serial: data01 # scsi3, boyut: data_disk_size_gb
      vg: vg_data
      lv: lv_data
      mount: /srv/data
    - serial: backup01 # scsi4, boyut: backup_disk_size_gb
      vg: vg_backup
      lv: lv_backup
      mount: /srv/backup

Çö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 find görevi ile /dev/disk/by-id‘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 lsblk -J çağrısı her blok aygıt için NAME, TYPE ve SERIAL’i yakalıyor, bir set_fact 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.

- name: Read the kernel serial view of all disks
  ansible.builtin.command:
    cmd: lsblk -J -o NAME,TYPE,SERIAL
  register: lsblk_serials
  changed_when: false

- name: Map every serial to its disk(s) (kernel view)
  ansible.builtin.set_fact:
    serial_map: >-
      {{ serial_map | default({}) | combine({
        item: (lsblk_serials.stdout | from_json).blockdevices
          | selectattr('type', 'equalto', 'disk')
          | selectattr('serial', 'equalto', item)
          | map(attribute='name') | list
      }) }}
  loop: "{{ data_disks | map(attribute='serial') | list }}"

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

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.

root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
TASK [Every serial must resolve to exactly one disk] **************
fatal: [vm-test-01]: FAILED! => (item=var01) => {
    "msg": "Expected exactly one disk with serial var01, found 0. ..."
}
... (log01, data01, backup01: aynı şekil, found 0)

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

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ı. fstype: lvm ile filesystem modülü oluşturmayı pvcreate‘e, büyütmeyi pvresize‘a eşliyor; lvg modülü gerekirse pvcreate‘i kendisi çalıştırıp volume group’u kuruyor; size: 100%VG ile lvol modülü LV hedefini VG’nin tamamı olarak hesaplıyor, ilk çalıştırmada LV’yi kuruyor, VG her büyüdüğünde lvextend --resizefs çağırıyor; bu da XFS için online xfs_growfs‘i tetikliyor. shrink bayrağı sadece-büyüme mantığıyla eşleşsin diye false.

- name: Create/resize physical volumes
  community.general.filesystem:
    fstype: lvm
    dev: "{{ disk_map[item.serial] }}"
    resizefs: true # ilk çalıştırmada pvcreate, her çalıştırmada pvresize

- name: Create volume groups (one per disk)
  community.general.lvg:
    vg: "{{ item.vg }}"
    pvs: "{{ disk_map[item.serial] }}"

- name: Create/extend logical volumes at 100 percent of their VG
  community.general.lvol:
    vg: "{{ item.vg }}"
    lv: "{{ item.lv }}"
    size: 100%VG # LV her zaman VG'sine eşit
    resizefs: true # lvextend --resizefs -> xfs_growfs
    shrink: false # sadece büyüme, tasarım gereği

- name: Create XFS filesystems
  community.general.filesystem:
    fstype: xfs
    dev: "/dev/{{ item.vg }}/{{ item.lv }}"

- name: Mount filesystems and persist in fstab
  ansible.posix.mount:
    path: "{{ item.mount }}"
    src: "/dev/{{ item.vg }}/{{ item.lv }}"
    fstype: xfs
    opts: defaults,noatime
    state: mounted # hem şimdi bağla HEM fstab'a yaz

Bu zincirde iki ayrıntı dikkati hak ediyor. Mount görevi state: mounted 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 growpart adımını tamamen kaldırıyor. Genişletilecek bir partition yok, çünkü partition yok.

Son olarak, pre_tasks bloğu her şeyden önce lvm2 ve xfsprogs‘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 pvcreate‘i bulamadığı kafa karıştırıcı bir erken hatayla sonuçlanıyor; pre_task bağımlılığı açık ve idempotent hale getiriyor.

İlk çalıştırma ve doğrulama

Sıfırıncı adım: taze VM’de guest agent yok

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 01_first_contact.yml‘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.

root@pve-a:~# qm shutdown 200
warning: QEMU Guest Agent is not running
# kapatma yine de başarılı; agent olmadan guest-farkında değil, düz bir ACPI kapatma

root@pve-a:~# qm start 200

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 ok okuyor), yönetilen damga yazılıyor (changed). Aynı sayılar, yeni makine:

root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/01_first_contact.yml
TASK [Install QEMU guest agent] *********************************
changed: [vm-test-01]

TASK [Enable and start the guest agent] *************************
ok: [vm-test-01]

TASK [Mark the VM as managed by this pipeline] *******************
changed: [vm-test-01]

PLAY RECAP ******************************************************
vm-test-01 : ok=5 changed=2 unreachable=0 failed=0
# taze klon doğrulandı: Ubuntu 26.04, kernel 7.0.0-30-generic

İlk çalıştırma

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’ı ok‘a indi çünkü daha önce yarım kalmış bir deneme lvm2 ve xfsprogs‘u zaten kurmuştu; bakir bir VM’de o görev de değişiyor.

root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
PLAY [Storage - LVM and XFS on serial-tagged data disks] **********

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

TASK [Every serial must resolve to exactly one disk] **************
ok: [vm-test-01] => (item=var01) => { "msg": "All assertions passed" }
... (3 tane daha, hepsi geçti) ...

TASK [Create/resize physical volumes] ****************************
changed: [vm-test-01] => (item=var01) ... (3 tane daha)

TASK [Create volume groups (one per disk)] ***********************
changed: [vm-test-01] => (item=vg_var) ... (3 tane daha)

TASK [Create/extend logical volumes at 100 percent of their VG] ***
changed: [vm-test-01] => (item=vg_var/lv_var) ... (3 tane daha)

TASK [Create XFS filesystems] ************************************
changed: [vm-test-01] => (item=/dev/vg_var/lv_var) ... (3 tane daha)

TASK [Mount filesystems and persist in fstab] ********************
changed: [vm-test-01] => (item=/srv/var) ... (3 tane daha)

PLAY RECAP ******************************************************
vm-test-01 : ok=14 changed=5 unreachable=0 failed=0

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.

Playbook, çalıştırma log’unun bir iddia değil kanıtla bitmesi için iki doğrulama çıktısıyla kapanıyor:

TASK [Show block devices with serials and mounts] *************
NAME                   SIZE TYPE SERIAL      MOUNTPOINT
sda                    10G disk              / <- 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

İdempotans: tekrar çalıştırma

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 ok'a iniyor: PV görevi saha testinde yine changed raporladı, çünkü resizefs: true ile community.general'in filesystem modülü her çağrıda pvresize'ı ç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.

root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
TASK [Create/resize physical volumes] ****************************
changed: [vm-test-01] => (item=var01)
changed: [vm-test-01] => (item=log01)
changed: [vm-test-01] => (item=data01)
changed: [vm-test-01] => (item=backup01)   # pvresize geçişi
# diğer her görev: ok

PLAY RECAP ******************************************************
vm-test-01 : ok=14 changed=1 unreachable=0 failed=0

Tek hayatta kalan değişiklik pvresize geçişi: resizefs: true 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ı.

Büyütme denemesi: tek düzenleme, sıfır kesinti

Senaryo: /srv/data, 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.

# ctrl-01'de: data_disk_size_gb 20 -> 30, sonra apply
root@ctrl-01:~/proxmox-automation/terraform# terraform apply
~ resource "proxmox_virtual_environment_vm" "test_vm" {
    ~ disk {
        ~ size = 20 -> 30   # yalnızca scsi3 değişiyor
      }
  }

Plan: 0 to add, 2 to change, 0 to destroy.   # 2. değişiklik: template VM
...
proxmox_virtual_environment_vm.test_vm: Modifications complete after 1s

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

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.

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

root@ctrl-01:~/proxmox-automation/ansible# ansible-playbook playbooks/02_storage.yml
TASK [Create/resize physical volumes] ****************************
changed: [vm-test-01] => (item=data01)   # pvresize büyümeyi gördü
# (+ diğerlerinde her çalıştırmada olan rutin kontrol)

TASK [Create/extend logical volumes at 100 percent of their VG] ***
changed: [vm-test-01] => (item=vg_data/lv_data)   # lvextend --resizefs

PLAY RECAP ******************************************************
vm-test-01 : ok=14 changed=2 unreachable=0 failed=0

root@ctrl-01:~# ssh ubuntu@192.168.122.50 'df -h /srv/data'
Filesystem                     Size  Used Avail Use% Mounted on
/dev/mapper/vg_data-lv_data    30G  620M   30G   3% /srv/data

İ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: lvol, VG'yi LV'den büyük görünce lvextend'i --resizefs ile çağırdı, bu da dosya sistemi bağlıyken online xfs_growfs'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ü.

Ters yönü denemek de öğretici, çünkü biri er ya da geç bir diski bu yolla küçültmeyi deneyecek. data_disk_size_gb'yi 20'ye geri çekip apply etmek, planı provider'ın kendi sözleriyle duvara çarptırıyor: Cannot shrink, it is not supported. 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öç.

Hızlı başvuru: belirti, neden, çözüm

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

Sırada ne var?

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 /install dizinini gerçek Ansible rollerine çeviriyor, ajan başına bir tane, her biri idempotent ve konfigürasyon güdümlü: sunucu adresi zabbix_agent2.conf'a template'lenmiş Zabbix Agent 2, kontrollü kaynaklardan kurulan Trend Micro ve ManageEngine, QRadar'a işaret eden rsyslog forward kuralları.

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, terraform apply'ı 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.

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.

Companion repo, seri boyunca her fazda biraz daha büyüyor:

📌 Link: GitHub repo; fazlarla eşleşen dizin yapısı, playbook'lar ve Terraform dosyaları

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.

Total
0
Shares
Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

The sameness problem behind those unappetizing AI-generated menus

Related Posts