İçeriğe geç
KubeAtlas
Kubernetes SRE DevOps Troubleshooting

Kubernetes'te Yedek Almak, Kurtarabilmek Demek Değil

Onur Ömer Tunç 6 dk okuma

Velero ya da benzeri bir araç her gece Completed yazıyor ve ekip rahat uyuyor. O yeşil durum yalnızca yedekleme işleminin bittiğini söyler; bir felakette uygulamanın verisiyle birlikte geri geleceğini söylemez. CNCF blogunda 10 Eylül’de yayımlanan lab çalışması bu farkı tekrarlanabilir üç arıza senaryosuyla gösteriyor.

Üç senaryonun ortak noktası hiçbir şeyin hata vermemesi

Üç senaryoda da bileşenlerin hepsi başarı raporluyor; sorunu ancak verinin kendisine bakan bir kontrol yakalıyor:

SenaryoYeşil görünenGerçekte olanNeyle yakalanır
Yedeğin içeriğiBackup CompletedVolume verisi yedeğe girmemiş olabilirTaşınan byte miktarı
GitOps ile geri dönüşSync Synced, pod ReadyVeritabanı boşBilinen kayıtları sorgulamak
Çok volume’lu uygulamaHer snapshot ReadyToUseVolume’lar farklı anlara aitUygulamanın kendi tutarlılık kuralı

Yedeğin “Completed” demesi verinin yedeğe girdiğini kanıtlamaz

Kubernetes’te bir yedek iki ayrı şeyi taşır: kaynak tanımları (YAML) ve persistent volume verisi. Tanımlar küçüktür ve neredeyse her zaman yedeğe girer. Volume verisi ise ayrı bir mekanizmayla korunur: sağlayıcının ya da CSI’ın snapshot’ı, dosya sistemi yedeği ya da verinin harici bir depoya taşınması. Bu mekanizma yanlış yapılandırılmışsa yedek yine Completed olabilir, ama içinde en değerli kısım, yani volume verisi bulunmaz.

Velero’nun veri taşıma (data mover) özelliğini kullanıyorsanız, her CSI snapshot’ı için bir DataUpload nesnesi oluşur ve ilerlemesi byte cinsinden görünür:

kubectl -n velero get datauploads -l velero.io/backup-name=$BACKUP

Çıktıdaki BYTES DONE sütunu, volume verisinin cluster’dan gerçekten çıktığını gösterir. CNCF’nin lab çalışmasında bu kontrol, 47.989.888 byte’lık volume verisinin harici depoya taşındığını ortaya koydu. Yedeklediğiniz bir PVC için kayıt görmüyorsanız ya da sayı beklediğinizden çok küçükse, o PVC’nin verisinin yedekte olduğunu varsaymayın.

CNCF lab’ında sonraki adım geri yüklemeydi: namespace PVC’leriyle birlikte silindi ve aynı yedekten yaklaşık iki dakikada, aynı dört kayıtla geri geldi. Yine de verinin yedekte olması, veritabanının uygulama tutarlı (application consistent) bir anda yedeklendiğini göstermez. Veritabanınızın yazma işlemlerini diske boşaltması gerekiyorsa, bunu yedeklemeden önce çalışan hook’larla ayrıca yapılandırmanız gerekir.

Başarılı bir geri yükleme kapsam hakkında da bir şey söylemez. Yedekleme araçları kaynakları zaten var olan bir cluster’a geri yükler. Cluster’ı, node’ları, ağı, load balancer’ları ya da DNS’i oluşturmazlar; o katmanı altyapı kodu (IaC) ya da Cluster API geri getirir. “Yedeği geri yükle” diye başlayan bir kurtarma planı, yedeğin hangi cluster’a yükleneceğini de yazmak zorundadır. Farklı bir altyapıya dönüşte storage class eşlemesi gibi dönüşümler de gerekebilir ve bunların çalıştığını ancak denediğinizde bilirsiniz.

GitOps senkronizasyonu yeşil yanar ama veritabanı boş kalabilir

Production cluster kapatıldığında, önceden hazırlanmış kurtarma cluster’ındaki GitOps controller Git’ten senkronize olur. Senkronizasyon Synced der, StatefulSet ayağa kalkar, pod Running ve Ready olur. CNCF lab’ında veritabanına atılan ilk sorgu ise şunu döndürdü:

ERROR: relation "attendees" does not exist

Kubernetes kendisine verileni uyguladı: StatefulSet’i, Service’i ve PVC için sıfırdan boş bir volume’u oluşturdu. Git yalnızca deklarasyonları taşıdığı için veri hiç geri gelmedi. Uygulamanın tanımı Git’ten gelebilir, verisi ise ancak yedekten.

Doğru sıra şöyle: önce senkronizasyonun oluşturduğu boş uygulamayı kaldırırsınız, sonra uygulamayı volume’larıyla birlikte yedek deposundan geri yüklersiniz, en son da veriyi beklenen içerikle doğrularsınız. CNCF’nin ölçümüne göre production’ın kapatılmasından doğrulanmış veriye kadar geçen süre canlı denemede dört dakika, prova edilmiş tekrarda iki dakikanın biraz altındaydı.

Bu rakamları kendi RTO (Recovery Time Objective, hizmetin en geç ne kadar sürede geri gelmesi gerektiği) hedefinizle karıştırmayın. RTO geri yükleme süresine ek olarak arızanın fark edilmesini, kurtarma kararını, trafiğin yeni cluster’a yönlendirilmesini ve sonradan asıl ortama dönüşü de kapsar. Kronometreyi de veri geri gelip doğrulandığında durdurun, çünkü bu senaryoda göstergeler yeşile döndüğünde veritabanı hâlâ boştu.

Çok volume’lu uygulamalarda snapshot’lar birbirini tutmayabilir

Gerçek stateful uygulamalar çoğu zaman birden fazla volume’a yayılır: veritabanı verisi ve WAL, message broker partition’ları, birden çok replika. CNCF lab’ındaki örnek uygulama sürekli olarak eşleşen kayıt çiftleri yazıyor: bir PVC’ye sipariş, diğerine ödeme. Tek kuralı da basit: her ödemenin bir siparişi olmalı.

İki volume’un snapshot’ı beş saniye arayla ayrı ayrı alındığında, ikisi de tek başına ReadyToUse ve kusursuz görünüyordu. Geri yükleyip son kayıt numaralarını karşılaştırınca şu çıktı:

last order committed   : 108352
last payment committed : 108377
[FAIL] 25 payments have NO matching order.

İki volume beş saniye arayla dondurulduğu için geri yüklenen veri, gerçekte hiç yaşanmamış bir anı gösteriyor. Beş saniye gerçekçi bir aralık: onlarca PVC’yi sırayla gezen bir yedekleme işi, volume’lar arasında bundan uzun farklar yaratabilir. Bu tür bir hatayı durum göstergeleri değil, geri yüklenen veride çalıştırılan tutarlılık kuralı yakalar.

VolumeGroupSnapshot neyi çözer, neyi çözmez

Kubernetes’in bu soruna API düzeyindeki cevabı VolumeGroupSnapshot. Özellik 1.27’de alfa olarak geldi ve 1.36 sürümüyle genel kullanıma (GA) geçti. Tek bir nesne PVC’leri etiketle seçer ve CSI driver’dan hepsi için aynı ana ait, çökme tutarlı (crash consistent) tek bir kurtarma noktası ister. CNCF lab’ında test amaçlı hostpath driver’ıyla kullanılan nesne şöyle:

apiVersion: groupsnapshot.storage.k8s.io/v1
kind: VolumeGroupSnapshot
metadata:
  name: ledger-group-snap
spec:
  volumeGroupSnapshotClassName: csi-hostpath-groupsnapclass
  source:
    selector:
      matchLabels:
        group: ledger

Geri yükleme, gruptaki tek tek VolumeSnapshot’lardan yeni PVC’ler oluşturularak yapılır. CNCF lab’ında aynı doğrulama bu kez temiz geçti:

last order committed   : 109169
last payment committed : 109169
[OK] Every payment has a matching order. Restore is consistent.

VolumeGroupSnapshot’ı kurtarma planınıza yazmadan önce driver’ınıza bakın. VolumeSnapshot destekleyen bir driver grup snapshot’ını da desteklemek zorunda değildir, çünkü bu ayrı bir CSI servisi ve ayrı çağrılar demektir. CNCF’nin lab için kontrol ettiği büyük bulut driver’larının çoğu henüz desteklemiyordu. Driver destekliyor olsa bile cluster’ınızdaki snapshot CRD’leri v1 API’sini sunacak kadar güncel olmalı; CNCF yazısına göre CRD’lerin kurulması, snapshot controller ile CSI sidecar üzerindeki feature gate’lerin de açılması gerekiyor.

Grup snapshot volume’lar arasındaki zaman farkını kaldırır, veritabanını diske boşaltmaz. Çökme tutarlı bir kurtarma noktası uygulama tutarlı olmadığı için yukarıdaki hook’lar yine gerekir.

Snapshot’ların gerçekten aynı ana ait olmasını da storage backend’iniz sağlar. Test driver’ında gördüğünüz sonucu production’da kullandığınız driver ile ayrıca doğrulamanız gerekir.

Kurtarmayı nasıl kanıtlarsınız

Bir pod’u silip geri gelişini izlemek yalnızca Kubernetes’in kendini onarma döngüsünü test eder. Kurtarma testi üç şey yapar:

  1. Uygulamayı daha önce hiç çalıştırmamış temiz bir cluster’a, volume’larıyla birlikte eksiksiz geri yükler.
  2. Başarıyı kaynakların durumuyla değil, beklenen içerikle ölçer: bilinen kayıtlar yerinde mi, kullanıcı akışı çalışıyor mu, uygulamanın kendi tutarlılık kuralı geçiyor mu.
  3. Arızadan doğrulanmış veriye kadar geçen süreyi kronometreyle ölçer ve RTO hedefinizle karşılaştırır.

Bu provayı takvime bağlayın ve sonucunu yedekleme başarısı kadar görünür bir yerde izleyin. CNCF yazısının saydığı ekosistem boşluklarından biri de bu: yedeklemenin tamamlanması yaygın şekilde izleniyor, geri yükleme provalarının sonuçları ise neredeyse hiç izlenmiyor. Aynı yazıya göre veri, workload, cluster, trafik ve kimlik katmanları arasında ortak bir failover sözleşmesi de yok; bir uygulamanın birlikte kurtarılması gereken parçalarını tanımlayan standart bir “kurtarma birimi” de. Bu sınırları şimdilik kendi planınızda tanımlamanız gerekiyor.

Veri doğrulamasını, GitOps ile geri dönüşü ve çok volume’lu tutarlılığı henüz kendi cluster’ınızda prova etmediyseniz, 30 dakikalık ücretsiz teknik değerlendirme için bize yazın.

Kaynaklar

Etiketler Kubernetes SRE DevOps Troubleshooting