Kubernetes Volume 15/20

Merhaba sevgili okurlarım bu yazımda sizlere Kubernetes’de Volume ve bu volume’ler içerisinde veriler nasıl tutulur, oluşturulur bunları anlatacağım. Bu yazının sonunda;

  • Persistent (kalıcı) Volume’lerin ne olduğunu anlayıp, oluşturabilecek,
  • Persistent volume claimleri yapılandırabilecek,
  • Volume erişim modlarını yönetebilecek,
  • Kalıcı bir depolamaya sahip olan uygulamalar geliştirebilecek,
  • Dinamik depolama ile ilgili işlemler yapmayı öğrenecek ve
  • Secrets ile ConfigMaps’i yapılandırabileceksiniz.

Pod spec içerisinde bir veya daha fazla volume’ü ve bunların nerede bulunduğunu tanımlayabiliriz. Her bir volume bir name, type ve mount noktası istemektedir. Aynı volume bir pod içerisindeki birçok container tarafından, container-to-container iletişimi olarak kullanılabilir. Pod’lara verilen erişim modları ile birlikte pod’larda kendi aralarında aynı volume’ü kullanabilir. Yalnız burada eşzamanlılık denetimi olmadığı için veri bozulması muhtemel anlamına gelmektedir.

Üç tane erişim modu mevcuttur.

RWO (ReadWriteOnce): tek bir node tarafından okuma-yazma imkanı sağlar.

ROX (ReadOnlyMany): birçok node tarafından okuma imkanı sağlar.

RWX (ReadWriteMany): birçok node tarafından okuma-yazma imkanı sağlar.

Volume Spec

Kullanılan bir çok depolama türü mevcuttur. Bu depolama türlerini buradan Kubernetes Docs sayfasından bakabilirsiniz. Bunlardan bir tanesi emptyDir’dir. Bu türü kullanırsanız kubelet dizini container içerisinde oluşturur ancak herhangi bir depolama birimine mount etmez. Oluşturulan veriler container’ın paylaşılan alanına yazılır. Sonuç olarak, persistent depolama olmaz. Pod yıkıldığı zaman dizin container’dan silinir.

Örnek bir emptyDir türünün kullanımını ve volume oluşturup mount etme YAML formatını aşağıda görebilirsiniz.

apiVersion: v1
kind: Pod
metadata:
    name: busybox
spec:
    containers:
    - image: busybox
      name: busy
      command:
        - sleep
        - "3600"
      volumeMounts:
      - mountPath: /gecici
        name: test-volume
    volumes:
    - name: test-volume
      emptyDir: {}

Yukarıdaki YAML dosyası, pod içerisinde gecici-volume ismine sahip /gecici alanını oluşturacaktır.

Volume Tipleri

Volume’leri tanımlamak için artıları ve eksileri olan birkaç tür vardır. Bazıları local’de çalışırken bazıları ağ tabanlı çalışır.

GCE veya AWS içerisinde GCEpersistentDisk veya awsElasticBlockStore türlerini pod’larınıza mount edeceğiniz olanaklarda mevcuttur.

emptyDir ve hostPath volume’lerinin kullanımları kolaydır. Daha önce belirttiğim gibi emptyDir, pod yıkıldığında silinen ancak container yeniden başlatıldığında yeniden oluşturulan boş bir dizindir. hostPath volume’ü host node dosya sisteminden bir kaynağı bağlar. Kaynak bir dizin, bir dısya soketi, karakter veya blok olabilir. Bu kaynaklar kullanılacak host’da zaten mevcut olmalıdır. Host’daki kaynakları oluşturan iki tür vardır: DirectoryOrCreate ve FileOrCreate.

NFS (Network File System) ve iSCSI (Internet Small Computer System Interface) birden fazla okuyucu senaryosu ile basit seçeneklerdir.

Kubernetes Cluster’ınız içerisinde varsa GlusterFS veya CephFS, rbd için bir seçenek olabilir.

Bu volume türlerinin yanı sıra pek çok türde seçenekte olmak üzere volume türleri vardır. azureDisk, azureFile, csi, fc, floker, gitRepo, local, quobyte, secret, persistentVolumeClaim, storageos, vsphereVolume vb gibi.

Aşağıdaki YAML dosyası her ikiside paylaşılan volume’e erişimi olan iki container’lı pod’u oluşturur.

....
  volumes:
  - name: shared-data
    emptyDir: {}

 containers:
  - name: nginx-container
    image: nginx
    volumeMounts:
    - name: shared-data
      mountPath: /usr/share/nginx/html

  - name: debian-container
    image: debian
    volumeMounts:
    - name: shared-data
      mountPath: /pod-data
    command: ["/bin/sh"]
    args: ["-c", "echo debian container icerisinden merhaba > /pod-data/index.html"]

Yukarıdaki pod örneğnde pod içerisinde iki tane container oluşuyor ve bu container’lar aynı volume’ü kullanıyorlar. debian-container isimli container’da bir dosya oluşturulduğu zaman nginx-container isimli container volume içerisindeki dosyayı görebilecek şekilde yapılandırılmıştır. Bunun sebebi aynı volume’ün iki container’ada mount edilmesidir.

emptyDir veya hostPath’i kolayca kullanabilirsiniz, çünkü bu türler ek kurulum gerektirmez ve Kubernetes Cluster içerisinde çalışır.

Bir container’ın yazdığına diğer container’ın erişebildiğini unutmayalım. Container’ların birisinin diğerinini üzerine yazmasını engelleyecek hiçbir durum yoktur. Bu işlemler için önlemler alınmalıdır.

Persistent Volume ve Claim

Persistent volume (pv), pod yıkıldıktan sonrada kullanılan soyutlanmış bir depolama çözümüdür. Pod’lar çeşitli boyut ve parametrelere bağlı persistentVolumeClaim(pvc) tipinde bir volume tanımlar. Cluster daha sonra persistentVolume’e ekleme yapar.

Kubernetes, depolama türlerinden bağımsız olarak herhangi bir backend depolama taleplerine izin verecek şekilde mevcut claim’leri dinamik olarak kullanacaktır.

Persistent Storage oluşturmanın birkaç aşaması vardır:

Ön hazırlıkta, cluster yöneticisi tarafından önceden oluşturulmuş PV’ler kullanılabilir veya cloud sağlayıcısı gibi dinamik bir kaynaktan istenilebilir.

Bir kontrol noktası, depolamaya erişim talebi ve isteğe bağlı olarak belirli bir StorageClass içeren PVC’yi fark ettiğinde meydana gelir. Burada eşleşen bir PV bulunur veya StorageClass sağlayıcısının bir tane oluşturması beklenir. PV en azından istenen depolama miktarıyla eşleşmeli veya daha fazla miktarı sağlayabilmelidir.

Kullanım aşamasında, bağlanmış volume, pod’un kullanması için mount edildiğinde başlar. Artık pod mount edilmiş volume’ü kullanabilir.

Pod yıkıldığı zaman, bağlı olduğu volume’e bir API isteği gönderilerek PVC silinir. Yeni bir claim oluşturma talebi gelene kadar volume beklemede durur. Persistent veriler persistentVolumeReclaimPolicy’e bağlı olarak kalır.

Yenileme (reclaim) evresinde üç seçenek vardır:

Retain: Verileri eksiksiz tutan, yöneticinin verileri depolamasına ve kullanmasına izin verir.

Delete: Volume eklentisine API nesnesini ve depolamayı silmesini söyler.

Recycle: rm -rf /mountpoint komutunu çalıştırır ve sonra yeni bir claim talebinde bulunur. Dinamik hazırlama kararlılığı bir sonraki versiyonda recycle seçeneğinin kaldırılmasını planlamaktadır.

Persistent volume(PV) ve Persistent volume claim(PVC)’leri listelemek için aşağıdaki komutlar kullanılır.

$ kubectl get pv
$ kubectl get pvc

Aşağıdaki örnek, hostPath türünü kullanan bir PersistentVolume öğesine ilişkin komutları içermektedir.

apiVersion: v1
kind: PersistentVolume
metadata:
    name: pv10Gi
    labels:
         type: local
spec:
    capacity:
        storage: 10Gi
    accessModes:
        - ReadWriteOnce
    hostPath:
        path: "/path/data01"

Her türün kendi yapılandırma ayarları vardır. Örneğin, önceden oluşturulmuş Ceph veya GCE Persistent Disk’in yapılandırılması gerekmez, ancak sağlayıcıdan talep edilir.

Cluster içerisinde oluşturulmuş persistentVolume kullanılarak claim talebinde bulunabilir ve bunu pod içerisinde kullanabilirsiniz.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: ornek-claim
spec:
    accessModes:
        - ReadWriteOnce
    resources:
        requests:
                storage: 2GI

Pod içerisinde, oluşturulan PersistentVolumeClaim şu şekilde kullanılmaktadır.

....
spec:
    containers:
....
    volumes:
        - name: test-volume
          persistentVolumeClaim:
                claimName: ornek-claim

Pod yapılandırmaları bazen karmaşık yapılara sahip olabilir. Aşağıda bunun bir örneği verilmiştir.

....
volumeMounts:
      - name: kompleks-volume
        mountPath: /data/rbd
  volumes:
    - name: rbdpd
      rbd:
        monitors:
        - '10.19.14.22:6789'
        - '10.19.14.23:6789'
        - '10.19.14.24:6789'
        pool: k8s
        image: client
        fsType: ext4
        readOnly: true
        user: admin
        keyring: /etc/ceph/keyring
        imageformat: "2"
        imagefeatures: "layering" 

Secret

Pod’lar volume’leri kullanarak local verilere erişebilirler fakat verilerin bazı zamanlarda direk okunmamasını isteyebilirsiniz. Örneğin şifreleriniz buna örnek olabilir. Secret API kaynaklarını kullanarak şifrelerinizi encode veya encrpyt edebilirsiniz.

Aşağıdaki temel komutları kullanarak secret’ları listeleyebilir, silebilir veya oluşturabilirsiniz.

$ kubectl get secrets
$ kubectl create secret generic mysql --from-literal=sifre=root

Secret API kaynakları hakkında daha fazla bilgi almak için aşağıdaki komutu çalıştırabilirsiniz.

$ kubectl create secret generic --help

Secret varsayılan olarak encrypt edilmez, yalnızca base64 olarak encode edilir. Uygun bir kimliğe sahip EncrptionConfiguration oluşturmalısınız. Ardından kube-apiserver –encrpytion-provider-config parametresine sahip bir yapılandırma ister. Örnek olarak bu değere aescbc veya ksm atanabilir. Bu parametre etkinleştirildiğinde yazarken encrypt edilmiş her secret’i yeniden oluşturmanız gerekir

Birden fazla key kullanabilirsiniz. Bir sağlayıcı her key için şifre çözme işlemi (decrpytion) yapar.

kubectl komutunu kullanarak secret içerisindeki encrpyt edilmiş dizeleri görebilirsiniz. Secret çözüleceği zaman bir dosyaya kayıt edilerek sunulacaktır. Dosya, bir volume’ü sunumuna benzer şekilde, bir environment olarak veya yeni bir dizi olarak kullanılabilir.

Bir secret manuel olarak yapılandırıalbilir ve ardından bir YAML dosyasına eklenebilir.

$ echo UmitDemirtas | base64
VW1pdERlbWlydGFzCg==

$ vim secret.yaml
apiVersion:v1
kind: Secret
metadata:
  name: Umit-secret
data:
  password: VW1pdERlbWlydGFzCg==

Bir secret, bir pod içerisinde environment değişkeni olarak kullanılabilir. Aşağıdaki örnekte yapılandırılmış bir tane görebilirsiniz.

....
spec:
  containers:
  - image: mysql:5.5
    env:
    - name: MYSQL_PASSWORD
      valueFrom: 
        secretKeyRef: 
          name: mysql
          key: password
        name: mysql

Kullanılan secret sayısında bir sınır yoktur, ancak boyutlarıan göre 1MB sınrı vardır. Her bir secret, diğer API nesneleriyle birlikte hafızayı kaplar, böylece çok fazla sayıda secret bir host’ta hafızayı tüketebilir.

Host node’unda tmpfs deposunda depolanırlar ve yalnızca pod çalıştıran host’a gönderilirler. Bir pod tarafından istenen tüm volume’ler pod içerisinde container’lar başlatılmadan önce mount edilmelidir. Bu yüzden talep edilmeden önce bir secret bulunmalıdır.

Ayrıca bir pod manifestinde bir volume tanımını kullanarak secret’ları dosya olarak da mount edebilirsiniz.

....
spec:
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    volumeMounts:
    - mountPath: /mysqlpassword
      name: mysql
    name: busy
  volumes:
  - name: mysql
      secret:
        secretName: mysql    

Pod çalıştıktan sonra secret’ın container içerisinde gerçekten erişilebilir olduğunu doğrulayabilirsiniz.

$ kubectl exec -ti busybox --cat /mysqlpassword/password
UmitDemirtas

ConfigMap Kullanımı

Secret’lar gibi ConfigMap’i environment olarak veya bir volume bağlaması olarakta kullanabilirsiniz. İsteğe bağlı olarak işaretlenmediği sürece bir pod tarafından kullanımladan önce var olmaları gerekmektedir. Ayrıca belirli bir namespace alanında bulunurlar.

Environment değişkenleri durumunda pod manifestiniz değerleri okumak için valueFrom anahtarını ve configMapKeyRef değerini kullanır.

Örneğin:

env:
- name: ornek-data
  valueFrom:
    configMapKeyRef:
      name: ornek-config
      key: deneme

Volume ile birlikte configMap türüne sahip bir volume tanımlayabilirsiniz.

volumes:
  - name: ornek-volume
    configMap:
      name: ornek-config

ConfigMap ile Taşınabilir Verileri Yönetme

Verilerin şifrelenmemesi dışında secret’a benzer bir API kaynağıda ConfigMap’tir. Herhangi bir formattaki verileri key-value çiftleri veya düz yapılandırma dosyası olarak depolar. Veriler bir dosya koleksiyonundan veya bir dizindeki tüm dosyalardan gelebilir. Aynı zamanda bir değişken olarak depolanabilir.

Bir ConfigMap birkaç farklı yolla kullanılabilir. Bir pod verileri bir veya daha fazla kaynaktan gelen environment değişkenleri olarak kullanılabilir. İçerdiği değerleri, container içerisindeki komutlara iletilebilir. Farklı adlar ve özel erişim modları dahil olmak üzere bir volume veya bir volume’da bir dosya olarak oluşturulabilir. Ek olarak, controller gibi cluster bileşenleri verileri kullanabilir.

Dosya sisteminizde config.js adlı bir dosyanız olduğunu varsayalım. Bu dosyayı içeren bir ConfigMap oluşturabilirsiniz. ConfigMap nesnesi dosyanın içeriğini içeren bir veri bölümüne sahip olacaktır.

$ kubectl get configmap deneme -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: deneme
data:
  config.js: |
    {
....

Yazımızın bu satırlarında Kubernetes Volume yazımızı tamamlıyoruz. Bir sonraki yazımda burada anlatılan teorilerin laboratuvarı yapılacaktır. Buradan laboratuvara ulaşabilirsiniz, görüşmek üzere !!

Umarım bu yazı sizin için bilgilendirici olmuştur. Yazıyla ilgili bir sorunuz, görüşünüz veya isteğiniz varsa alt kısımda bulunan yorumlardan veya mail adresimden iletişime geçebilirsiniz. Bu yazının başkaları içinde bilgilendirici olduğunu düşünüyorsanız sosyal olun ve sosyal medyada paylaşın! Okuduğunuz için teşekkürler !!!!

1 thought on “Kubernetes Volume 15/20

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir