Kubernetes Volume Nedir?

Kubernetes Volume, Pod içindeki container'ların verilerini saklamak için kullandığı depolama mekanizmasıdır. Volume, Pod'lar arasında veri paylaşımı, kalıcı depolama veya farklı kaynaklara erişim gibi farklı senaryolarda kullanılabilir.

Kubernetes Volume, Pod'ların bir bileşenidir ve bu nedenle, Container gibi, Pod manifest dosyasında tanımlanır. Standalone bir Kubernetes nesnesi değildirler ve kendi başlarına oluşturulamaz veya silinemezler. Bu nedenle kubectl get volume gibi bir komutla görüntülenemezler.

Bir volume, bir Pod'a dahil edildiğinde, o Pod içindeki tüm Container'lar için kullanılabilir hale gelirler. Fakat Container'ların erişebilmesi için ilgili Volume'ları mount etmelri gerekir.

1. Volume'lara Neden Gerek Var?

Pod'ların, içlerinde çalışan processlerin CPU, RAM, network interface'leri ortak kullandığı logical hostlara benzer olduğunu söylemiştik. Bu processlerin aynı zamanda dosya sistemini de paylaşması beklenebilir, ancak dosya sistemi processler için ortak değildir. Bu nedenler ortak veya kalıcı dosya sistemleri oluşturmak için Volume'lara ihtiyacımız vardır.

Kubernetes Volume kullanarak, Pod içindeki container'ların verilerini saklamak, paylaşmak, taşımak ve korumak daha kolay ve güvenilir hale gelir. Bu nedenle, Kubernetes Volume kullanımı, Kubernetes platformunda önemli bir konudur.

Kubernetes Volume kullanmanın bazı temel nedenleri şunlardır:

  1. Verilerin korunması: Pod'lar birden fazla container'a sahip olabilir ve bu container'lar birbirleriyle etkileşimde bulunabilir. Ancak, bu container'lar arasında veri paylaşımı yapılmazsa, container'lar arasındaki bağlantı zayıflayabilir. Bu nedenle, pod'da paylaşılan bir Volume, container'lar arasındaki veri paylaşımını kolaylaştırır.
  2. Verilerin yedeklenmesi: Kubernetes Volume, verilerin yedeklenmesini kolaylaştırır. Bir Volume'da saklanan veriler, Pod'un farklı bir Node'a taşınması veya Pod'un kapatılması durumunda bile korunur.
  3. Verilerin taşınması: Kubernetes Volume, verilerin Pod'lar arasında taşınmasını kolaylaştırır. Bir Volume'da saklanan veriler, başka bir Pod'da kullanılabilir veya farklı bir Pod'a taşınabilir.
  4. Depolama kaynaklarının kullanımı: Kubernetes Volume, Pod'da birden fazla container'ın kullanabileceği ortak bir depolama kaynağı sağlar. Bu nedenle, aynı depolama kaynağına sahip birden fazla container için Volume kullanmak, depolama kaynaklarının daha verimli kullanılmasını sağlar.

2. Volume Kullanım Senaryosu

Volume konusunu rahat anlayabilmek için basit bir senaryo üzerinden nasıl kullanabileceğine birlikte bakalım.

Örneğin bir Pod içinde çalışan 3 adet Container olsun. Herbirini şu şekilde özetleyelim:

  1. /var/htdocs altındaki HTML dosyalarını çalıştırıp loglarını /var/logs altına koyan bir Webserver container
  2. Webserver container'ın çalıştıracağı HTML dosyalarını oluşturup /var/htdocs dizinine koyacak bir ContentAgent container
  3. /var/logs altındaki log dosyalarını alarak rotate, analyze gibi işlemler gerçekleştiren bir LogRotator container

Eğer Volume kullanmazsanız, container'lar, diğer container'ların dosyalarının farkına varamazlar. Örneğin Webserver container'ın oluşturduğu logları LogRotator container'ı göremeyecek. Çünkü her container kendi disk alanındaki dizinlere bakıyor olacaktır.

Fakat eğer log ve HTML dosyaları için iki ayrı Volume oluşturur ve container'ların ilgili dizinlerine mount edersek, tüm container'lar aynı dosyalar üzerinde çalışmış olacak ve ortak bir disk alanı oluşturmuş oluruz.

3. Volume Tipleri

Kubernetes Volume, farklı depolama kaynaklarını kullanarak Pod'lar içinde veri saklamak için tasarlanmış bir mekanizmadır. Kubernetes Volume, birçok farklı tipi destekler ve her biri farklı bir kullanım senaryosuna sahiptir. İşte bazı yaygın Kubernetes Volume tipleri şunlardır:

  1. emptyDir: Pod'da geçici ve boş bir depolama alanı sağlar. Pod'un yaşam döngüsü boyunca verileri saklayabilir. Ancak Pod silindiğinde veriler de silinir.
  2. gitRepo: emptyDir olarak başlatılan bir volume, belirtilen bir Git reposuna clone ederek volume'un son halini oluşturur.
  3. hostPath: Pod'un çalıştığı Node üzerinde bulunan dosya sistemine erişmek için kullanılır. Bu, yalnızca tek bir Node üzerinde çalışan Pod'lar için uygundur.
  4. nfs: NFS erişimi sağlar. Pod'un farklı Node'lar arasında taşınması durumunda bile verilerin korunmasını sağlar.
  5. gcePersistentDisk, awsElasticBlockStore, azureDisk ve diğerleri: İlgili cloud providerlar üzerindeki storage çözümlerini Volume olarak kullanabilmenizi sağlar. Fakat hepsi deprecated olmuştur ve yerlerine CSI veya plugin kullanmanız gerekir.
  6. persistentVolumeClaim (PVC): Kubernetes Cluster'ındaki bir depolama alanı için bir talep oluşturur. Pod'un kapatılması veya başka bir Node'a taşınması durumunda bile verilerin korunmasını sağlar.
  7. configMap: Pod'lar için yapılandırma verileri sağlar. Pod'ların çalışma zamanı yapılandırmasını ayarlamak için kullanılır.
  8. secret: Pod'lar için hassas verileri sağlar. Örneğin, kullanıcı adları ve şifreler gibi verileri saklayabilir.
  9. downwardAPI: Pod'da çalışan container'ların environment variabler'larını, CPU ve bellek limitlerini ve diğer verileri sağlar.

Bu, yalnızca yaygın kullanılan bazı Kubernetes Volume tiplerinin bir listesidir. Her biri farklı bir kullanım senaryosuna sahiptir ve Kubernetes platformunda depolama için farklı seçenekler sunar.

3.1. emptyDir Volume Tipi

emptyDir, Kubernetes Volume'lerinden biridir ve Pod'un yaşam döngüsü boyunca geçici bir depolama alanı sağlar. emptyDir, Pod'un Node'una bağlı bir diskte oluşturulur ve Pod kapatıldığında veya silindiğinde hem Volume hem de içindeki veriler silinir.

Bir emptyDir oluşturmak için, aşağıdaki gibi bir YAML dosyası örneğini kullanabilirsiniz:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: my-image
    volumeMounts:
    - name: my-volume
      mountPath: /data
  volumes:
  - name: my-volume
    emptyDir: {}

Manifest dosyası hazır olduktan sonra kubectl create veya kubectl apply komutlarından birisi ile pod'u oluşturabilirsiniz.

 kubectl create -f pod-with-emptydir-volume.yaml

emptyDir, Pod'unuzu barındıran node'un üzerindeki fiziksel diskte oluşturulduğu için dosya okuma ve yazma performansı node'un bu fiziksel diskine bağlıdır. Ancak Kubernetes'e emptyDir'i bir tmpfs dosya sisteminde (disk yerine bellekte) oluşturmasını söyleyebilirsiniz. Bunu yapmak için emptyDir ortamını şu şekilde Memory olarak ayarlamalısınız:

volumes:
 - name: my-volume
   emptyDir:
     medium: Memory

Böylece dosya okuma yazma gözle görülür şekilde artacaktır. Fakat depolayacağınız dosyalar için RAM boyutuna dikkate almalısınız.

💡
emptyDir volume tipini, geçici dosyalar tutacağanız işler için kullanmalısınız. Çünkü veri kaybı ihtimali oldukça yüksek bir volume tipidir. 

3.2. gitRepo Volume Tipi

gitRepo, public Git reposundan kaynak kodu otomatik olarak kopyalayan bir emptyDir volume tipidir. Private repolar için yapılandırma seçenekleri içermez.

🚧
gitRepo volume oluşturulduktan sonra Git repo ile senkronize edilmez. Eğer Git reposuna ek commitler gönderirseniz volume içindeki dosyalar güncellenmeyecektir. Fakat, eğer bir ReplicationController veya ReplicaSet kullanıyorsanız, Pod'un silinmesi yeni bir Pod ve volume oluşturulmasıyla sonuçlanacaktır. Böylece yeni Pod'un yeni Volume'u en son commitleri içerecektir.

Bir gitRepo oluşturmak için aşağıdaki gibi bir YAML dosyası örneği kullanabilirsiniz:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: my-image
    volumeMounts:
    - name: my-volume
      mountPath: /app
  volumes:
  - name: my-volume
    gitRepo:
      repository: https://github.com/my-repo/my-app.git
      revision: master
      directory: .

Manifest dosyası hazır olduktan sonra kubectl create veya kubectl apply komutlarından birisi ile pod'u oluşturabilirsiniz.

 kubectl create -f pod-with-gitrepo-volume.yaml

Eğer directory isimli parametreyi kullanmazsanız ilgili repo /app dizini altında my-app isimli alt dizine clone edilir.

🛑
gitRepo Volume tipi deprecated edilmiştir. Git clone işlemini bir emptyDir volume ve initContainer tanımlayarak yapabilirsiniz.

3.3. hostPath Volume Tipi

hostPath, Kubernetes Volume'lerinden biridir ve Pod'un üzerinde çalıştığı node'un dosya veya dizinlere erişimini sağlar.

Eğer bir Pod üzerinde çalıştığı node'un dosya sistemini kullanırken sonlanır ve yeni oluşan node farklı bir node üzerinde çalışmaya başlarsa aynı dizini kullansa bile aynı dosyaları göremez. Bu nedenle hostPath volume kalıcı depolama çözümü olarak kullanılmamalıdır.

Bir hostPath oluşturmak için aşağıdaki gibi bir YAML dosyası örneği kullanabilirsiniz:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: my-image
    volumeMounts:
    - name: my-volume
      mountPath: /data
  volumes:
  - name: my-volume
    hostPath:
      path: /var/log

Manifest dosyası hazır olduktan sonra kubectl create veya kubectl apply komutlarından birisi ile pod'u oluşturabilirsiniz.

 kubectl create -f pod-with-hostpath-volume.yaml
💡
Yalnızca node'un sistem dosyalarını okumanız veya yazmanız gerektiğinde hostPath volume kullanmanız önerilir. Verileri container'lar arasında kalıcı kılmak için asla kullanmayınız.

3.4. gcePersistentDisk,  awsElasticBlockStore, azureDisk ve CloudProviderVolume Tipi

Birçok cloud provider, kalıcı depolama alanı sunabilmek için, kendi bünyelerinde bulunan disk çözümlerini Volume bileşeni olarak sunarlar. Cloud provider'lar üzerinden ilgili disk servislerini oluşturduktan sonra Pod'larınız ile Volume olarak kullanmaya başlayabilirsiniz.

Cloud provider Volume tiplerinden herhangi birini kullandığınızda, node'larınız çökse, Pod'larınız silinip yeniden oluşturulsa bile yeni Pod'lar mount ettikleri dizindeki eski verilere ulaşabilirler. Çünkü tüm dosyalar, bu providerların cloud üzerindeki depolama çözümleri içinde saklanır.

Örnek olarak Google Cloud Engine (GCE) üzerinde çalışan cluster'ımızda GCE persistent disk objesini Volume olarak kullanabileceğimiz bir database YAML örneğini görelim.

apiVersion: v1
kind: Pod
metadata:
  name: mongodb
spec:
  containers:
  - name: mongodb
    image: mongo
    volumeMounts:
    - name: mongodb-data
      mountPath: /data/db
  volumes:
  - name: mongodb-data
    gcePersistentDisk:
      pdName: my-disk
      fsType: ext4

Manifest dosyası hazır olduktan sonra kubectl create veya kubectl apply komutlarından birisi ile pod'u oluşturabilirsiniz.

 kubectl create -f pod-with-gcepersistentdisk-volume.yaml

Bu örnekte Pod'umuz tek bir container ve GCP üzerinde oluşturduğunuz GCE persistence disk'e depolama yapan bir volume içerir.

Aynı örneği AWS EBS kullanacak şekilde yapılandıracak olursakta tek yapacağımız şey volume tipini ve değerlerini değiştirmek olacaktır.

spec:
  volumes:
  - name: mongodb-data
    awsElasticBlockStore:
      volumeId: my-volume
	  fsType: ext4
🛑
gcePersistentDisk, awsElasticBlockStore, azureDisk ve daha birçok cloud provider Volume tipi deprecated edilmiştir. Bu tip cloud provider volume tiplerini kullanabilmek için Container Storage Interface (CSI) kullanmanız gerekir. Detaylar için ilgili Volume tipinin migration açıklamasına bakabilirsiniz: https://kubernetes.io/docs/concepts/storage/volumes

3.5. NFS Volume Tipi

Eğer Kuberntes cluster'ınız cloud providerlar yerine kendi sunucularınızda çalışıyorsa, Volume içine harici depolamayı mount etmek için desteklenen çok sayıda başka seçeneğiniz vardır. Örneğin, basit bir NFS paylaşımına bağlanmak için, aşağıdaki gösterildiği gibi yalnızca NFS sunucusunu ve sunucu tarafından dışa aktarılan pathi belirtmeniz gerekir.

volumes:
 - name: mongodb-data
   nfs:
     server: 1.2.3.4
     path: /some/path

3.6. PersistentVolume ve PersistentVolumeClaim Volume Tipi

PersistentVolume ve PersistentVolumeClaim oldukça önemli ve detaylı bir içeriğe sahip olduğu için ayrı bir yazıda inceledik. İlgili yazıya aşağıdaki bağlantı ile gidebilirsiniz.

Kubernetes PersistentVolume, PersistentVolumeClaim ve StorageClass Nedir?
Kubernetes PersistentVolume, PersistentVolumeClaim ve StorageClass, kalıcı veri depolama ve talepleri yönetmek için kullanılan önemli kavramlardır.

3.7. configMap ve Secret Volume Tipi

configMap ve Secret oldukça önemli ve detaylı bir içeriğe sahip olduğu için ayrı bir yazıda inceledik. İlgili yazıya aşağıdaki bağlantı ile gidebilirsiniz.

4. Volume Yaşam Döngüleri

Bir önceki altında birçok farklı Volume tipi gördük. Hangisini kullanacağınızı seçerken düşünmeniz gereken bir önemli konuda ilgili Volume tiplerinin life cycle'larıdır. Şimdi bu tiplerin herbirine hızlıca bakalım:

  • İlk olarak emptyDir ile başlayalım. Pod sonlandırıldığında emptyDir volume'larda sonlandırılır ve içindeki veri silinir.
  • hostPath tipindeki Volume'ler ise Pod'lar sonlandırıldığında etkilenmez. Fakat node hata verir ve çökerse hostPath volume'lerde erişelemez hale gelir.
  • NFS, cloud provider disk sistemleri, PersistentVolume ve PersistentVolumeClaim Volume tipleri ise kendileri direkt olarak sonlandırılana kadar node ve pod nesnelerinin durumlarından bağımsız olarak kalıcı bir volume sistemi sunarlar.

Sıradaki yazı ile eğitim serisine devam edebilirsiniz.

Kubernetes PersistentVolume, PersistentVolumeClaim ve StorageClass Nedir?
Kubernetes PersistentVolume, PersistentVolumeClaim ve StorageClass, kalıcı veri depolama ve talepleri yönetmek için kullanılan önemli kavramlardır.