Kubernetes Konseptleri | Kubernetes Dersleri 2

Selamlar, önceki dersimizde Kubernetes’in ne olduğunu ve Kubernetes mimarisini öğrendik. Şimdi ise Kubernetes Konseptlerini öğreneceğiz.

İlk olarak Kubernetes Konseptlerinden en çok kullanılanları tek resimde görelim.

Yukarıdaki resmi inceleyelim:

Nodelar k8s cluster’ının kurulu olduğu makinelerdir.

Cluster içerisinde 2 adet namespace bulunmaktadır. Namespace sanal clusterlar olarak adlandırılabiliriz. Ayrı uygulamalar için ayrı namespaceler kullanabiliriz. Mesela Mongo deploy edeceğiz Mongo için ayrı namespace tanımlayabiliriz. Bu ona diğer namespaceden bağlanamayacağımız anlamına gelmez.

Namespace içerisinde ise deploy ettiğimiz uygulamalar, joblar, configmapler, volumeler(PVC) ve Servisler bulunmaktadır

Bu kavramları tek tek inceleyelim.

POD

  • Kubernetes ‘in en küçük birimidir.
  • Container üzerine bir soyutlama katmanıdır.
  • Pod’u bir linux içerisinde container veya containerlar çalıştırmış olarak düşünülebiliriz.
  • Genellikle 1 uygulama içerirler. 1’den çoğu önerilmemektedir.
  • Her Pod bir IP’ye sahiptir. IP’ler Unique’dir.
  • Pod oluşturulur, çalışır, hata aldığında ise ölür. Yerine yeni IP ile yenisi oluşur.
apiVersion: v1
kind: Pod
metadata:
  name: mongo
spec:
  containers:
  - name: mongo
    image: mongo

ReplicaSet

  • Pod’dan kaç adet oluşturulması gerektiğini belirtmemize olanak sağlar.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: frontend
spec:
  replicas: 3 # replica sayisinin verildigi kisim
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
      - name: vue
        image: frontend:latest

Deployment

  • Pod üzerine bir soyutlama katmanıdır. Replica atamamızı sağlar.
  • Birden fazla Pod oluşturabilir.
  • Stateless uygulamalar için kullanılır. (Stateless veri depolamayan uygulamadır.)
  • Replica verilebilir. Uygulamanın kaç tane çalışması gerektiğini belirtir.
  • Deployment ile versiyon yönetimi yapabiliriz. Versiyon değişiminde önceki versiyon ile yeni versiyon aynı anda çalışabilecek şekilde ayarlanabilir. Yeni versiyonda çıkan bir hata sonucunda önceki versiyona döndürülebilir.
# SOURCE: https://cloud.google.com/kubernetes-engine/docs/tutorials/guestbook
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-follower
  labels:
    app: redis
    role: follower
    tier: backend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
        role: follower
        tier: backend
    spec:
      containers:
      - name: follower
        image: gcr.io/google_samples/gb-redis-follower:v2
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 6379

StatefulSet

  • Stateful uygulamalar için kullanılır. (Veritabanlari ve bilgi tutan uygulamalar.)
  • Veritabanı bilgilerini kaybetmemek için Persistent Volume kullanırız. Persistence edilen veri node’u ile pod’un ayağa kalktığı node farklı olduğunda veriye erişemeyeceğinden dolayı Statefulset kullanılmaktadır. (Longhorn, rook vb. kullanılarak bu sorun aşılabilir.)
  • Statefulset podları sıralı bir şekilde ayağa kaldırıp sıralı bir şekilde öldürür. (a-0, a-1, a-2)
# SOURCE https://kubernetes.io/docs/tutorials/stateful-application/cassandra/
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cassandra
  labels:
    app: cassandra
spec:
  serviceName: cassandra
  replicas: 3
  selector:
    matchLabels:
      app: cassandra
  template:
    metadata:
      labels:
        app: cassandra
    spec:
      terminationGracePeriodSeconds: 1800
      containers:
      - name: cassandra
        image: gcr.io/google-samples/cassandra:v13
        imagePullPolicy: Always
        ports:
        - containerPort: 7000
          name: intra-node
        - containerPort: 7001
          name: tls-intra-node
        - containerPort: 7199
          name: jmx
        - containerPort: 9042
          name: cql
        resources:
          limits:
            cpu: "500m"
            memory: 1Gi
          requests:
            cpu: "500m"
            memory: 1Gi
        securityContext:
          capabilities:
            add:
              - IPC_LOCK
        lifecycle:
          preStop:
            exec:
              command: 
              - /bin/sh
              - -c
              - nodetool drain
        env:
          - name: MAX_HEAP_SIZE
            value: 512M
          - name: HEAP_NEWSIZE
            value: 100M
          - name: CASSANDRA_SEEDS
            value: "cassandra-0.cassandra.default.svc.cluster.local"
          - name: CASSANDRA_CLUSTER_NAME
            value: "K8Demo"
          - name: CASSANDRA_DC
            value: "DC1-K8Demo"
          - name: CASSANDRA_RACK
            value: "Rack1-K8Demo"
          - name: POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        readinessProbe:
          exec:
            command:
            - /bin/bash
            - -c
            - /ready-probe.sh
          initialDelaySeconds: 15
          timeoutSeconds: 5
        # These volume mounts are persistent. They are like inline claims,
        # but not exactly because the names need to match exactly one of
        # the stateful pod volumes.
        volumeMounts:
        - name: cassandra-data
          mountPath: /cassandra_data
  # These are converted to volume claims by the controller
  # and mounted at the paths mentioned above.
  # do not use these in production until ssd GCEPersistentDisk or other ssd pd
  volumeClaimTemplates:
  - metadata:
      name: cassandra-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: fast
      resources:
        requests:
          storage: 1Gi
---
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: fast
provisioner: k8s.io/minikube-hostpath
parameters:
  type: pd-ssd

DaemonSet

  • Her Node’da olmasını istediğimiz podlar için kullanılır.
  • Node cluster’a eklendiğinde otomatikmen Pod yeni eklenen node’a eklenir.
  • Genellikle Log toplama, Node monitoring(metrikleri izleme), cluster storage ve benzeri durumlarda kullanılır.
# source ==> https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

Job

  • Bir veya birden fazla Pod oluşturabilir.
  • Belirtilen success sayısına ulaşana kadar çalışır.
  • Eğer belirtilen success sayısına ulaşırsa Job Completed(Tamamlandı) denir.
  • Job silindiğinde veya durdurulduğunda oluşturulan podlar silinir. Eğer devam ettirirlerse podlar tekrar oluşturulur
# source => https://kubernetes.io/docs/concepts/workloads/controllers/job/
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never # pod oldugunde kaldirma  diger secenekler Always ve OnFailure
  backoffLimit: 4

CronJob

  • Bir Job’in belli aralıklarla tekrarlamasını sağlar.
  • Özellikleri Job ile aynıdır.
  • schedule parametresi eklenerek job’ın hangi aralıklarla tekrarlanacağı belirtilir.

schedule parametresini kolayca ayarlayabilmek için kaynak => https://crontab.guru/

# source ==> https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *" #  job'in hangi aralıklarla tekrarlanacağı belirtilir.
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            imagePullPolicy: IfNotPresent
            command:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

ConfigMap

  • Key value seklinde bilgilerin tutulduğu dosyalardır.
  • Gizli bilgiler içermez. İçermesi önerilmemektedir.
  • Gizli bilgiler icin Secrets adli konsept bulunmaktadır.
  • Podlar ConfigMap ‘teki verileri ortam değişkeni olarak kullanabilirler. (ConfigMap ve Secrets örneği aşağıdadır.)
# source => https://kubernetes.io/docs/concepts/configuration/configmap/
apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # property-like keys; each key maps to a simple value
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # file-like keys
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true    

Secrets

  • Key value seklinde gizli bilgilerin tutulduğu dosya.
  • Value kısmi base64 seklinde yazılmaktadır.
apiVersion: v1
kind: Secret
metadata:
  name: mosquitto-secret-file
type: Opaque
data:
  secret.file: |
    c29tZXN1cGVyc2VjcmV0IGZpbGUgY29udGVudHMgbm9ib2R5IHNob3VsZCBzZWU=

ConfigMap ve Secrets Örneği

# ConfigMap ornegi
apiVersion: v1
kind: ConfigMap
metadata:
  name: mongodb-configmap
data:
  db_host: 
 

# secret ornegi
apiVersion: v1
kind: Secret
metadata:
  name: mongodb-secret
type: Opaque
data:
  username: ZnVya2FuIG96a2F5YQ==
  password: ZnVya2Fub3prYXlhLmNvbQ==


# Deployment ornegi
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:latest
        ports:
        - containerPort: 8080
        env:
        - name: MONGODB_SERVER
          valueFrom: 
            configMapKeyRef:
              name: mongodb-configmap
              key: db_host
        - name: MONGO_ROOT_USERNAME
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: username
        - name: MONGO_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-secret
              key: password

Volumes

K8s’de data

  • Pod’un yasam döngüsüne bağlı olmamalı.
  • Data tüm Node’lardan erişebilir olmalı.
  • K8s çöktüğünde dahi erişebilir olmalı.

Persistence Volume ve Persistence Volume Claim

Persistence Volume PV

Cluster düzeyinde olan ve sizin için istediğiniz kadar yer ayıran birimdir. Namespace bağımsız olduğundan her yerden erişilebilir.

Persistent Volume Claim PVC

Pod tarafından istenilen depolama alanına erişimi sağlayan yapıdır. İstenilen miktarda ve özelliklerde Persistence volume bulup onu pod’a bağlar.

Persistent volume ise pod’u gerçek depolama alanına bağlar.

Yukarıdaki resimde görüldüğü gibi Pod PVC ve PV üzerinden depolama servislerine bağlanmıştır.

Local Depolama sorunu

Servis yerine lokal depolama kullandigimizi düşünelim. Bu durumda PV gidip bizim makinemizde bir alan oluşturacak ve bilgilerimizi oraya yazacaktı. Peki Pod öldüğünde ve başka makinede ayağa kalktığında neler olur ?

Pod başka bir makinede ayağa kalktığında datalara erişemeyecek. Yeni bir alan oluşturacak. Bu yüzden Best practice olarak servis sağlayıcı kullanmak önerilmektedir.

Lokalde data tutmanın bir yolu yok mu ? diye soruyorsanız eğer. Tabi ki var… Rancher Storage Class çözümü Longhorn’u önerebilirim. Yazının devamında bahsedeceğim 🙂

Persistent Volume ve Persistent Volume Claim Yaml file Örnekleri

# source => https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/kubernetes-volumes/persistent-volumes.yaml
# Persistent Volume ornekleri
# ayri bir nfs server ile
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-name
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: slow
  mountOptions:
    - hard
    - nfsvers=4.0
  nfs:
    path: /dir/path/on/nfs/server
    server: nfs-server-ip-address

---
# google veya aws gibi servisler ile
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-volume
  labels:
    failure-domain.beta.kubernetes.io/zone: us-central1-a__us-central1-b
spec:
  capacity:
    storage: 400Gi
  accessModes:
  - ReadWriteOnce
  gcePersistentDisk:
    pdName: my-data-disk
    fsType: ext4

---
# local depolama
apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - example-node
# PersistentVolumeClaim ornegi
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-name
spec:
  storageClassName: manual
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

StorageClass

  • Storage Class Persistence Volume oluşturmayı otomatikleştirir.
  • İstenilen özelliklerde Persistent Volume olusturup PVC’ye bağlar.
  • PVC tarafından her istenilen depolama alanında yeni bir PV oluşturur.
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: storage-class-name
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "10"
  fsType: ext4
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
     name: mypvc
spec:
     accessModes:
     - ReadWriteOnce
     resources:
       requests:
         storage: 100Gi
     storageClassName: storage-class-name

Rancher StorageClass Çözümü Longhorn

Services

Her podun bir ip adresi vardır ama podlar ölüp tekrar ayağa kalktığında yeni IP adresi atanır. Direkt Ip adresi kullanarak pod’a ulaşamayacağımızdan dolayı Servisler kullanılır.

  • ClusterIP Service (default type)
  • NodePort Service
  • LoadBalancer Service
  • HeadLess Service

Servisler ayni zamanda loadbalancer olarak da çalışır.

ClusterIP Service

Cluster içerisinde erişimi açan servis tipi.

Headless Service

ClusterIp servisi loadbalancing yaptığı icin bir pod’a direk olarak bağlanmak istediğimizde Headless Servis kullanabiliriz. ClusterIp: None atadığımızda HeadLess servis elde etmiş oluruz.

DNS normalde ClusterIp dönerken Headless servis için Pod ip’ sini döner.

NodePort Service

Uygulamamızı belirli ip aralığında (30000-32767) dışarıya atiğimiz servis tipidir. Production için önerilmez. Bunun yerine LoadBalancer önerilir.

LoadBalancer Service

NodePort ve ClusterIp otomatik olarak oluşturulur. Servis sağlayıcının loadbalancer çözümü kullanılarak dışarıya açılır. Her servis sağlayıcısının kendi LoadBalancer çözümleri mevcuttur.(AWS, Google vb.)

NodePort Servis Örneği

# NodePort source => https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: MyApp
  ports:
      # By default and for convenience, the `targetPort` is set to the same value as the `port` field.
    - port: 80
      targetPort: 80
      # Optional field
      # By default and for convenience, the Kubernetes control plane will allocate a port from a range (default: 30000-32767)
      nodePort: 30007

LoadBalancer Servis Örneği

# LoadBalancer source ==> https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  clusterIP: 10.0.171.239
  type: LoadBalancer
# asagidaki kisim otomatik olarak servis saglayican gelir
status:
  loadBalancer:
    ingress:
    - ip: 192.0.2.127

Kaynaklar:

https://www.youtube.com/c/TechWorldwithNana

https://kubernetes.io/docs/concepts/

Bu yazımda en çok kullanılan kubernetes konseptlerinden bahsettim.

Bir sonraki kubernetes yazımda Yaml dosyası nasıl yazılır? Kolay Yolu Nedir ? gibi sorulara cevap vereceğim.

Add a Comment

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir