Kubernates Notlarım
Kubernetes Nesneleri *
K8 üzerinde çalıştırılan, koşturulan, yüklenen şeylere nesneler diyoruz.
Kubernetes nesneleri, Kubernetes sistemindeki kalıcı varlıklardır. Kubernetes, kümenizin durumunu temsil etmek için bu varlıkları kullanır. Bu nesneler aşağıdaki bilgileri bize sunar:
- Hangi uygulamalar konteyner olarak hangi node üstünde çalışıyor
- Bu uygulamalar için mevcut kaynaklar verilmiş (pv, pvc, vol)
- Yeniden başlatma ilkeleri, yükseltmeler ve hataya dayanıklılık (fault-tolerance) gibi bu uygulamaların nasıl davrandığına ilişkin ilkeler
apiVersion: v1
kind: Pod
metadata:
name: pod-adi
labels:
isim: pod-etiketi-isim
soyisim: pod-etiketi-soyisim
spec:
# Bir POD içinde bir konteyner arzu edilir ama
# n tane konteyner de yaratılabilir
containers:
- name: my-nginx
image: nginx:alpine
resources:
limits:
memory: "128Mi"
cpu: "200m"
ports:
- containerPort: 80
- name: my-busy
image: busybox:latest
resources:
limits:
memory: "128Mi"
cpu: "200m"
restartPolicy: Never
Komutlarımız:
Deployment, replica, service, pod'ların hepsini bir arada görürüz:
$ k get all POD yaratıp içinde tanımlı konteynerleri oluşturuyoruz:
$ k create --filename .\nginx.pod.yamlPOD ve diğer nesneler için ayrıntılı bilgi almak için:
$ k describe [pods|deployments|replicas..] <nesne-adi>
kube-scheduler
POD için uygun bir node bulup POD’u bu node’a atıyor:
kubelet
Bu kez POD’un içinde tanımlı konteyner için yansıyı varsa bulur yoksa indirir ve çalıştırır:
Günlük Kayıtlarını Görüntülemek
docker logs
ile günlük kayıtlarıyla ne yapılabiliyorsa k8 üstünde de aynı parametrelerle yapılabiliyor.
$ docker run --name ng -d nginx:latest
$ docker logs --follow --timestamps --tail 4 --since 10m ng
docker logs
ile kubectl logs
aynı şekilde çalışıyor.
docker logs <konteyner-adi>
ile oluşan tüm günlük kayıtlarını görüp terminal sonlanıyordu. Ancak docker logs --follow <konteyner-adi>
ile oluşan tüm günlük kayıtlarını canlı olarak görüp yeni eklenenleri de terminalimizde anında görecektik.
-f
Kısaltması--follow
ile aynı anlamdadır
Kubernetes üstünde de aynı parametre geçerlidir:
Tıpkı docker’da olduğu gibi günlüklerin zaman damgalarını (--timestamps
) ve sondan n satırı (--tail n
) görebiliyoruz kubernetes üstünde de.
Başlatılıp Çıkan POD
alpine
Yansısından bir pod ve içine konteyner oluşturulup, yapacak bir şey olmadığı için hata vermeden kapanınca Completed
durumuna getirilip sonrasında CrashLoopBackOff
durumunda ayaklandırmaya çalıştığını görüyoruz.
$ k get pods -w
$ k run pod1 --image=alpine
Pod’u Silince Durum Bilgisi
Silme komutu gelince durum bilgisi Terminating
oluyor ve default
isim uzayındaki (namespace
) pod hakkın rahmetine kavuşuyor.
$ k delete pod pod1
Deployment İle POD Oluşturmak
k create deployment
ile POD sayısı (replicas) belirlenebilir, ancak yansıdank run …
veya dosyadank create -f ./pod.json
ile POD oluşturduğumuzda aynı anda oluşturulacak POD sayısını veremeyiz.- Deployment ile oluşan podları
k scale <dep-adı>…
ile değiştirebilir ancak doğrudan POD oluşturduğumuzda bunu yapamayız.
POD oluşturmak için run komutu yeterli olur ancak POD’un aynılarından kopya (replica) yaratılmasını da istiyorsak kubectl run
komutu yetersiz kalacaktır. Bu yüzdem kubectl create deployment <adı> --replicas=3 ...
şeklinde komut kullanarak deployment
oluşturmamız gerekiyor.
kubectl create deploment …
ile replicas anahtarının çalıştığı ve 2 kopya POD ürettiği görülürOluşan iki podu silmeye kalkarsak arka planda yeniden pod sayısını ikiye tamamlamak için k8 harekete geçecektir.
Hem
Replicaset
Aynı anda canlı tutulması gereken POD sayısını ayaklandırmaya çalışır ve eski sürümü replica controller
dır (halen mevcut ama tercih edilmez).
kubectl run
ile yaratılan POD’lar için replicaset oluşturulmaz yani oluşan POD’ları ölçekleyemeyiz.
- ReplicaSet türünde (
kind: ReplicaSet
) bir yaml ile oluşturduğumuz POD’lar için yaml dosyasında yapılan değişikliklerkubectl apply
komutuyla faal POD’lara uygulanmaz! Bu yüzden türü deployment (kind: Deployment
) olan yaml dosyalarından POD üretmek gerekir. - ReplicaSet türündeki dosyalar
Sadece deployment ile oluşturduğumuz POD’lar bir replicaset nesnesi üstünden yaratılır. Eğer deployment içinde bir değişim yaşanacaksa (örn. yansıyı değiştirdiğimizde) yeni replicaset nesnesi oluşturulup yeni yansıyla POD’lar ayaklandırır ve ardından eski replicasetin podları kaldırılır ancak replicaset kaldırılmaz.
# deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Biz deployment üstünden yaratmak istediğimizde önce replicaset oluştu ve podlar peşi sıra geldi. Şimdi podların yansısını değiştirmek isteyelim ve yeni oluşan replicaset’i ve önceki replicasetinin silinmemesini görelim:
İlk replicaset nginx-deployment-546bcd4698
idi ve yansıyı nginx’ten httpd’ye çevirdiğimizde yeni replicaset nginx-deployment-8447dc9f74
olarak ikinci replicaset üretildi önceki silinmeden bekliyor.
ROLLOUT
Geriye sarmak için kullanıyoruz
Basit bir deployment yaratalım ve describe ile yansının adını alalım:
$ k create deployment cem --image=nginx
$ k describe pod cem | grep Image:
Image: nginx
İlk yaratıldığında bir deployment geriye sarılacak bir şey yoktur.
$ k rollout undo deployments cem
error: no rollout history found for deployment "cem"
Şimdi yansıyı değiştirip tekrar değişim sırası ve sonundaki yansıyı görelim:
$ k set image deployment.apps/cem nginx=httpd
deployment.apps/cem image updated
$ k describe pod cem | grep Image:
Image: nginx
Image: httpd
$ k describe pod cem | grep Image:
Image: httpd
Geri saralım ve yansıyı görelim ve yine geri sarıp tekrar ileri gittiğimizi görelim:
$ k rollout undo deployments cem
deployment.apps/cem rolled back
$ k describe pod cem | grep Image:
Image: nginx
Image: httpd
$ k describe pod cem | grep Image:
Image: nginx
$ k rollout undo deployments cem
deployment.apps/cem rolled back
$ k describe pod cem | grep Image:
Image: httpd
Komutlar
$ kubectl create -f <yml dosyanızın yolu> [--save-config]# --save-config ile yaml içindeki bilgileri oluşan pod'a yazıyoruz
Kubernates ile bir pod $ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready master 5s v1.17.3
$
$ kubectl run http --image=katacoda/docker-http-server:latest --replicas=1
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/http created
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
http 1/1 1 1 33s
$ kubectl describe deployment http
Name: http
Namespace: default
CreationTimestamp: Fri, 04 Dec 2020 09:38:44 +0000
Labels: run=http
Annotations: deployment.kubernetes.io/revision: 1
Selector: run=http
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: run=http
Containers:
http:
Image: katacoda/docker-http-server:latest
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: http-774bb756bb (1/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 41s deployment-controller Scaled up replica set http-774bb756bb to 1
$ kubectl expose deployment http --external-ip="172.17.0.75" --port=8000 --target-port=80
service/http exposed
$ curl http://172.17.0.75:8000
<h1>This request was processed by host: http-774bb756bb-7782b</h1>
$
command ve args
Kapsayıcı şu komutla başlasın ***:
Disk işlemleri
Kubernetes üstünde çeşitli disk bağlantıları sağlanıyor. Azure, AWS, Ceph, nfs, vsphereVolume vs tonla bulut üstünde veya ağ üstündeki disk hizmetlerinden ve hatta tmpfs
ile bellek üstünde bulunan (bellek kadar büyük, eğer node
tekrar başlarsa her şeyin gidebileceği hızlı ama güvensiz) alanlardan da faydalanabiliyoruz. Disk hizmetlerine plugin kullanarak erilebileceğiz, örneğin gcePersistentDisk
aslında Google Cloud Platform üstündeki diske erişebilmemiz için bir eklentidir.
ps
: Persistent Storage
pv
: Persistent Volme
pvc
: Persistent Volume Claim
Pod
içinde bir konteyner var ve 50GB alanı yaml
dosyasında volumes
alanında ps-pvc
adında bir züpürttegeden istiyor. ps-pvc
İse bu alanı ulu orta isteyecek ve ona cevap verecek ps
ise ps-pv
adındaki kabartakinde olacak.
Şimdi podu oluşturalım
Pod hayat çevrimi (life cycle)
PENDING State
yaml Dosyasını kubectl komutuyla k8 API ye göndeririz ve API gelen YAML dosyasındaki bilgileri kendinden bilgiler ekleyerek (eşsiz bir ID değeri vs.) etcd ye (k8'in veritabanına) kaydeder.
CREATING State
k8'in scheduler Bileşeni API üstünden etcd’de bekleyen (pending durumdaki) POD’ları çeker ve ihtiyaç duyduğu kaynağa uygun bir k8 düğümünü (k8 kümesinin içindeki bir düğüm) araştırır bulursa node: nodeAdi
olacak şekilde POD’u CREATING durumuna günceller.
Eğer POD’un ihtiyaç duyduğu kaynağa sahip bir node bulamazsa PENDING durumunda beklemeye devam eder.
RUNNING State
3 Numaralı düğümdeki kubelet devreye girer ve POD’un ihtiyaç duyduğu yansıları varsa kendi üstünden, yoksa erişebildiği buluttan çekerek (Örn. Azure Cloud Repository) konteynerde çalışması gereken uygulama başlatılarak POD’un durumunu RUNNING olarak işaretler.
ImagePullBackOff State
Eğer konteynerin ihtiyaç duyduğu yansı bulunamazsa POD’un durumu ImagePullBackOff olarak ayarlanır. Yansı gerçekten ilgili yansı havuzlarında yok, ya da bu havuzlara kullanıcı girişi yapamadığımız için sorgulayamıyorsak veyahut kalıp adı hatalı yazılmışsa bu duruma düşülür.
SUCCEDED State
- POD oluşturulurken k8 API’sine yeniden başlatma ilkesi olarak
--restart=[OnFailure|Never]
girilmişse. Yani, hata olduğunda yeniden başlat veya asla yeniden başlatMA seçilmişse, - konteyner düzgün çalışıyorken ve konteynerin içindeki uygulama işini bitirip hata vermeden çıkış yapmışsa
POD, SUCCEDED yani COMPLETED olarak işaretlenir.
FAILED State
- POD oluşturulurken k8 API’sine yeniden başlatma ilkesi olarak
--restart=[OnFailure|Never]
girilmişse. Yani, hata olduğunda yeniden başlat veya asla yeniden başlatMA seçilmişse, - konteynerin içindeki uygulama hata üretip çıkış yapmışsa
POD’un durumu FAILED olarak işaretlenir.
CrashLoopBack State
Running 0, 1, 2, 3 … diye devam edecek çünkü her defasında kapanıp tekrar başlatılacak.
Eğer tekrar başlatma ilkesi daima olarak ayarlanmışsa --restart=Always
ve konteyner
- hata üretip çıkmışsa konteyner tekrar başlatılacağı için running durumunda devam eder ancak CrashLoopBack olarak da konteynerin durumunu belirler.
- hata üretmeden, normal bir çıkış ile konteyner sonlanmışsa tekrar başlatma ilkesi always olduğu için konteyner yeniden başlatılır ve running durumuyla birlikte CrashLoopBack durumuna getirilir.
Her yeni başlatıldığında tekrar başlatma sayısı 1 arttırılar:
- Ancak çöken veya kapanan konteyner 10 saniye bekletilir tekrar başlatılır,
- Yine çöker veya düzgün kapanırsa 20 sn daha bekletilir ve tekrar ayaklandırılır,
- Yine çöker veya kapanırsa 40 saniye sonra tekrar ayaklandırılır,
- …
- Yine çöker veya kapanırsa 5 dakikada bir tekrar ayaklandırılır
ancak durumu bir daha çökmeyinceye kadar running ve CrashLoopBack olarak ayarlanır.
Eğer bir şekilde tekrar kapanmaz veya çökmezse konteyner durumunu sadece RUNNING olarak işaretler.
Bu durumlarda kubectl describe pods
ile events kısmına bakarak sebebi anlamaya çalışabiliriz.
Eğer webhook’lar ile konteyner oluşturulduktan hemen sonraya (/postStart
) veya durdurulmadan hemen önceye (/preStop
) eklemlenmek veya konteynerin sağlığını (/health
) veya hazır olduğu anı (/ready
) yakalamak istiyorsak bu olaylara eklemlenebiliriz.
Ayrıca init konteyneri sayesinde sorunlu durumları elemine edebiliriz.
PODa Bağlı Ağ Kartı Çiftinin Ev Sahibi Bilgisayardaki (host) Eşini Bulmak
Önce podları listeleyelim:
root@CINAR-Test-CNF:/# kubectl get ns
NAME STATUS AGE
5gcn-k8s-deployment-2410080810-1645 Active 13h
default Active 35d
kube-flannel Active 35d
kube-node-lease Active 35d
kube-public Active 35d
kube-system Active 35d
kubernetes-dashboard Active 7d14h
Şimdi namespace içindeki podları listeleyelim
root@CINAR-Test-CNF:/# kubectl get pods -n 5gcn-k8s-deployment-2410080810-1645
NAME READY STATUS RESTARTS AGE
amf-deployment-0 2/2 Running 0 63m
ausf-deployment-0 1/1 Running 0 11h
Eğer label üzerinden podlarımızı bulmak isteseydik:
kubectl get pods -n 5gcn-k8s-deployment-2410080810-1645 -l "appType=nf,nf in (amf, ausf)"
Şimdi crictl ile podun konteynerlerini listeleyelim
root@CINAR-Test-CNF:/# crictl ps --pod=`crictl pods | grep amf-deployment-0 | awk '{print $1}'`
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
0238bd04f3bcf af2b0e86db9c3 About an hour ago Running promtail 0 b0756046031cb amf-deployment-0
c070fc8c72fdc 626f774352512 About an hour ago Running amf-ctr 0 b0756046031cb amf-deployment-0
Bu pod iki konteynere sahip ve ikisinin de aynı “pause container
” üzerinden ağ bağlantıları kuracağını biliyoruz. O halde hangi konteynere bakarsak bakalım aynı path içinde değerinde (/proc/xxxx/net/ns
) aradığımız cevabı bulacağız.
root@CINAR-Test-CNF:/# crictl pods | grep amf-deployment-0
517019637abbf 2 minutes ago Ready amf-deployment-0 5gcn-k8s-deployment-2410082202-1647 0 (default)
root@CINAR-Test-CNF:/#
root@CINAR-Test-CNF:/# crictl ps --pod=`crictl pods | grep amf-deployment-0 | awk '{print $1}'`
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
33e1f3355c1fd af2b0e86db9c3 52 seconds ago Running promtail 0 517019637abbf amf-deployment-0
5eebb291ad918 626f774352512 55 seconds ago Running amf-ctr 0 517019637abbf amf-deployment-0
root@CINAR-Test-CNF:/#
root@CINAR-Test-CNF:/# crictl inspect 33e1f3355c1fd 5eebb291ad918 | grep /ns/net
"path": "/proc/2897641/ns/net"
"path": "/proc/2897641/ns/net"
İki konteynerin de aynı netns
sürecine yani pause container
‘ine (2897641) bağlı olduğunu gördük. Yukarıdaki anlatımımda da söylediğim gibi bu gayet normal.
Şimdi amf-deployment-0
podunun netns sürecini bulduğumuza göre pause konteynerinin türü net
olan netns’leri listeleyip içinde 2897641 olan satırı bulacağız.
root@CINAR-Test-CNF:/# ps axo user,pid,ppid,pcpu,pmem,vsz,rss,tname,stat,start,time,args | grep 2897641
65535 2897641 2897442 0.0 0.0 996 4 ? Ss 22:04:45 00:00:00 /pause
root 2938592 1766328 0.0 0.0 7008 2172 pts/5 S+ 22:11:24 00:00:00 grep --color=auto 2897641
root@CINAR-Test-CNF:/# lsns -t net | grep 2897641
4026532513 net 17 2897641 65535 4 /run/netns/cni-bd0f9d41-c57f-3427-fc16-3e5106cf6b44 /pause
Artık ev sahibi bilgisayarda sanal ağ kartlarını ip link
ile listeleyip podun ağ işlemlerini yapan konteynerin sanal ağ kartı eşini ev sahibi bilgisayarda bulabiliriz.
root@CINAR-Test-CNF:/# ip link | grep cni-bd0f9d41-c57f-3427-fc16-3e5106cf6b44 -B 1
21895: vethd7bdc630@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue master cni0 state UP mode DEFAULT group default
link/ether 8e:84:d2:79:58:e0 brd ff:ff:ff:ff:ff:ff link-netns cni-bd0f9d41-c57f-3427-fc16-3e5106cf6b44
Artık bu podu host içinde dinlemek için sadece bu ağ kartını dinleyerek trafiğini yakalayabilirsiniz veya hangi köprü arayüzüne dahil olduğunu görebilir ve podun ait olduğu köprüden tüm trafiği dinleyebilirsiniz.
net tipindeki netns'leri listeleyip host üzerinde hangi sanal ağ kartının process id
değerini bulalım