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
- Longhorn Worker node’larda ki depolama alanlarını birleştirir.
- Blok depolama adı verilen bu sistem ile podlariniz lokalde depolanan dataya Longhorn sayesinde erişir.
- Longhorn hakkında daha fazla bilgi için tıklayınız. 🙂
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.