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: mongoReplicaSet
- 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:latestDeployment
- 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: 6379StatefulSet
- 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-ssdDaemonSet
- 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/containersJob
- 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: 4CronJob
- 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: OnFailureConfigMap
- 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-nameRancher 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: 30007LoadBalancer 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.127Kaynaklar:
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.