Kubernetes LAB01 4/20

Kubernetes Kurulumu

Merhaba arkadaşlar, bir önceki yazımızda Kubernetes kurulumu için birtakım yollar ve adımlardan bahsetmiştik. Bu laboratuvarda kubeadm kullanarak kubernetes cluster kurulumu gerçekleştireceğiz. Kubernetes kullanan topluluklar arasında bağımsız bir araç olması sebebiyle kubernetes cluster kurmak için birincil yöntem olması gerektiği vurgulanmaktadır.

kubeadm komutunu kullanırken uyarı veya hata olarak bazı gereksinimler karşınıza çıkabilir. Çoğu komutlar normal kullanıcılar tarafından çalıştırılırken bazıları için root ayrıcalıklarını kullanmamız gerekecek. GCP yada AWS gibi uzaktan erişim noktalarından erişiyorsanız Linux makinenize uzaktan erişim sağlamak için PuTTy gibi bir SSH istemcisi kullanmanız gerekecektir. Ayrıca varsa SSH anahtarını yüklemeyi unutmayalım.

Kubernetes öğrenirken Linux makinenizde güvenlik duvarını devre dışı bırakın. Bileşenler arası iletişim için gerekli bağlantı noktaları için bu önemli olacaktır. GCP kullanıyorsanız tüm trafiğin tüm portlardan akacak şekilde ayarlamayı unutmayın (allows all traffic to all ports). VirtualBox kullanıyorsanız VM’ler arası ağ ağlantısının promiscuous modda olduğundan emin olmalıyız.

Benim burada kullanmış olduğum Linux makine GCP üzerinde bulunmaktadır ve bahsettiğim tüm ayarlar yapılmış durumdadur. Ubuntu 16.04 versiyonunu kurulu. 2 vCPU ve 7.5 GB memory’si bulunmaktadır.

Kuruluma başlayalım.

PuTTy gibi SSH istemcisi kullanarak yada VirtualBox ile linux makinemize bağlandıktan sonra aşağıdaki komutları çalıştırıp güncelleme yaptırıyoruz.

$ sudo -i
# apt-get update && apt-get upgrade -y

Bir container ortami için ana seçeneğimiz Docker’dır. Aşağıdaki komutu çalıştırarak Docker kurulumu yapabilirsiniz.

# apt-get install -y docker.io

Linux makinemiz için kubernetes deposu oluşturalım. Benim kullandığım makine Ubuntu 16.04 olduğu için kubernetes-xenial kelimesini main anahtar kelimesi ile ekliyorum.

# vim /etc/apt/sources.list.d/kubernetes.list

deb http://apt.kubernetes.io/ kubernetes-xenial main   # ekleyeceğimiz satır.

Paketimiz için bir GPG anahtarı ekliyoruz.

# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -

OK     # alacağımız çıktı.

Yeni eklediğimiz depo ile birlikte yeni güncelleştirmeleri alalım.

# apt-get update

Artık kubeadm, kubelet ve kubectl yazılımlarımızı indirebileceğimiz duruma geldik.

# apt-get install -y kubeadm kubelet kubectl

Container Networking Interface (CNI) için hangi pod ağının kullanılacağına karar vermek için cluster içindeki beklenen talepler dikkate alınmalıdır. Cluster başına bir pod ağı olabilir. Ağ, container’dan container’a, pod’dan pod’a, pod’dan servise ve harici servis dışı iletişime izin vermelidir.

Calico adında bir ağ eklentisi kullanacağız. Şuan mevcutta bulunan Calico CNI kullanarak konuşlandırılmıyor. Calico’nun versiyonları RBAC ile esneklik için birden fazla yapılandırma dosyasına sahiptir. URL’ler uzun olduğu için yapılandırma dosyalarını kısaltılmış link üzerinden indireceğiz. Calico projesini buradan inceleyebilirsiniz.

# wget https://tinyurl.com/yb4xturm -O rbac-kdd.yaml
# wget https://tinyurl.com/y8lvqc9g -O calico.yaml

İndirmiş olduğumuz Calico dosyasını less komutu ile açtığımız zaman içerisinde CALICO_IPV4POOL_CIDR değerinin “192.168.0.0/16” olduğunu görürüz burda bu değer ile birlikte kubeadm komutuna vereceğimiz değeri aynı olduğuna dikkat edip kubernetes cluster kurulumunu başlatmalıyız.

# kubeadm init --kubernetes-version 1.14.0 --pod-network-cidr 192.168.0.0/16 | tee kubeadm-init.out

Adım adım kodları açıklamak gerekirse;

  • kubeadm init => Cluster oluşturur.
  • –kubernetes-version => kullanacağımız (indirmiş olduğumuz) kubernetes versiyonunu girip kuruluma bu versiyon üstünden devam ettirir.
  • –pod-netword-cidr => IP aralığımız, Calico dosyasının içerisindeki değerin aynısını yazdık
  • tee kubeadm-init.out => Çıktıları kayıt ettirir

Kurulum, aşağıdaki gibi bir çıktı verir ve kurulumdan sonra yapılandırma için komutlar önerir.

[init] using Kubernetes version: v1.14.0
[preflight] running pre-flight checks
[preflight/images] Pulling images required for setting up aKubernetes cluster
[preflight/images] This might take a minute or two, dependingon the speed of your internet connection
.
.
.
Your Kubernetes master has initialized successfully!
To start using your cluster, you need to run the following asa regular user:

mkdir -p $HOME/.kubesudo 
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.Run "kubectl apply -f [podnetwork].yaml" with one of the optionslisted at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of machines by running the followingon each node as root:
kubeadm join 10.128.0.2:6443 --token bsy76u.xbfuzztjytp42ftk \
    --discovery-token-ca-cert-hash sha256:f7ba5d86cc2cd4c8d5038763c351bcea74d2f18ae10f5def27ba846be6f9b89c

Kurulum tamamlandıktan sonra bize önermiş olduğu yapılandırma işlemlerini tamamlayalım.

# exit
$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config
$ less .kube/config => kurulumu kontrol edebilirsiniz.

Ağ eklenti yapılandırmasını cluster’ınıza uygulayın. Dosyayı önce geçerli kullanıcınıza (root olmayan) kopyalamayı unutmayın.

$ sudo cp /root/rbac-kdd.yaml .
$ kubectl apply -f rbac-kdd.yaml
$ sudo cp /root/calico.yaml .
$ kubectl apply -f calico.yaml

Cluster’ı Büyütelim

Mevcutta kullanmış olduğunuz Kubernetes Cluster’ını büyütmek için aynı platformda (benim kullanmış olduğum GCP) bir VM daha oluşturuyoruz. Oluşturduğumuz VM’i üst kısımdaki kuruluma benzer bir şekilde devam ettircez. Oluşturulan VM için aynı SSH anahtarını kullanabilirsiniz.

$ sudo -i
# apt-get update && apt-get upgrade -y
# apt-get install -y docker.io
# vim /etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main => ekleyeceğimiz satır.
# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
OK => alacağımız çıktı.
# apt-get update
# apt-get install -y kubeadm kubelet kubectl
# exit

Bu işlemleri worker node’unuza uyguladıktan sonra master node’unuzun IP adresini öğrenelim. Arabirim adı node’un çalıştığı yere göre farklılıklar gösterecektir. GCP içerisinde şuanda bu node türü için arabirim ens4’tür.

(master node)$ ip addr show ens4 | grep inet
inet 10.128.0.2/32 brd 10.128.0.2 scope global ens4
inet6 fe80::4001:aff:fe8e:e/64 scope link

Bu aşamada join komutunu master node’umuza uyguluyoruz. Master node’daki token’ı bulalım. Bu token varsayılan olarak 24 saat geçerlidir. Eğer süre geçtiye ve yeni bir tane oluşturmak isitiyorsanız kubeadm token create komutunu kullanabilirsiniz. Token’ları listelemek için ise kubeadm token list komutunu kullanabilirsiniz.

(master node)$ sudo kubeadm token list
TOKEN                     TTL   EXPIRES               39fmdo.p3ia1beow1tsybwy   23h   2019-04-09T13:27:33Z 

Token’ın süresi geçtiyse TTL kısmında invalid yazar. Yeni token oluşturmak için aşağıdaki komutu kullanabilirsiniz.

(master node)$ sudo kubeadm token create
39fmdo.p3ia1beow1tsybwy

Kubernetes 1.9 versiyonundan itibaren master node’e node’ların güvenli bir şekilde bağlanması için Discovery Token CA Cert Hash oluşturmalı ve kullanmalısınız. Aşağıdaki komutu master node’da çalıştırıp bu işlemi yapabilirsiniz.

(master node)$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

f7ba5d86cc2cd4c8d5038763c351bcea74d2f18ae10f5def27ba846be6f9b89c

Bu durumdan itibaren artık worker node’u master node’a ekleyebiliriz. Aşağıdaki komutları worker node’da çalıştırın. Edindiğimiz bilgileri parametre olarak vermeyi unutmayalım.

(worker node)# kubeadm join --token 39fmdo.p3ia1beow1tsybwy 10.128.0.2:6443 --discovery-token-ca-cert-hash sha256:f7ba5d86cc2cd4c8d5038763c351bcea74d2f18ae10f5def27ba846be6f9b89c
# exit
$ kubectl get nodes

The connection to the server localhost:8080 was refused- did you specify the right host or port?

Artık yeni oluşturduğumuz node’u master node’a bağladık. Master node’da aşağıdaki komutu çalıştırırsanız iki tane node olduğunu görebilirsiniz.

(master-node)$ kubectl get nodes
NAME      STATUS     ROLES    AGE   VERSION
k8s-vm    Ready      master   27h   v1.14.0
k8s-vm2   NotReady   <none>   19s   v1.14.0

Yalnız burda şunu unutmamamız gerekiyor. Worker node içerisinde kubectl get nodes komutunu çalıştırdığımızda çalışmadığını görürüz. Bunun sebebi worker node içerisinde ./kube/config yapılandırması olmamasıdır. Buna ihtiyacımız yok zaten worker node’umuzu master node üzerinden yöneteceğiz.

(worker-node)$ kubectl get nodes
The connection to the server localhost:8080 was refused - did you specify the right host or port?

Node içerisinde taint tanımlı olabilmektedir. Taint konusunu ileriki eğitim yazılarımızda göreceğiz. Burda sadece bunu kaldıracağız. Şimdi bu taint’lere bakalım ve ortadan kaldıralım.

$ kubectl describe node | grep -i taint
Taints:             node-role.kubernetes.io/master:NoSchedule
Taints:             <none>

$ kubectl taint nodes --all node-role.kubernetes.io/master-
node/master-node-1 untainted
error: taint "node-role.kubernetes.io/master:" not foun

Basit Bir Uygulama Dağıtalım

Şimdi oluşturduğumuz ortamı test edebiliriz. Bunun için nginx web server kurulumu yapalım. Bir uygulamayı bir container’da dağıtıp izleyelim. (Kafa karışmasını önlemek adına aşağıdaki kodları master node’da yazıyoruz.)

$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created

$ kubectl get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           38s

Eğer bir deployment’ın detaylarını görüntülemek istiyorsak describe komutunu kullanırız.

$ kubectl describe deployment nginx
ment nginx
Name:                   nginx
Namespace:              default
CreationTimestamp:      Mon, 08 Apr 2019 13:53:18 +0000
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=nginx
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 
....

Oluşturulmuş bir dağıtımın(deployment) YAML formatını görmek istiyorsan -o yaml parametresini kullanabiliriz.

$ kubectl get deployment nginx -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2019-04-08T13:53:18Z"
  generation: 1
  labels:
    app: nginx
  name: nginx
....

YAML çıktısını bir dosyaya kayıt edelim.

$ kubectl get deployment nginx -o yaml > ornek.yaml

Şimdi oluşturduğumzu dağıtımı silip, elimizde bulunan YAML dosyasından bir dağıtım oluşturalım.

$ kubectl delete deployment nginx
deployment.extensions "nginx" deleted

$ kubectl  create -f ornek.yaml
deployment.extension/nginx created

Nesne oluşturmadan ham YAML veya JSON çıktısını almak için –dry-run parametresini kullanabiliriz. Bu parametre nesne oluşturmaz, sadece oluşturuyormuş gibi yapar.

$ kubectl create deployment two --image=nginx --dry-run -o yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: two
  name: two
....

$ kubectl get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   1/1     1            1           19m

Şuanda bir container içerisinde konuşlandırılmış bir nginx web sunucumuz mevcuttur. Bu web sunucusunun giriş sayfasına ulaşmak için bizim servislere ihtiyacımız vardır. Bir uygulamanın içerisinde servis çıkarmak istiyorsak expose komutunu kullanırız. Daha fazla ayrıntı için expose -h komutunu çalıştırabilirsiniz.

$ kubectl expose deployment/nginx

error: couldn't find port via --port flag or introspection
See 'kubectl expose -h' for help and examples

Servisi çalıştırmak istediğimizde bu hata ile karşılaşmamız çok normal bir durum. Çünkü container’ı biz direk olarak deploy ettik. Dolayısıyla container için bir port ve protocol belirlemedik. Bunun için daha önceden oluşturduğumuz nginx YAML dosyasını açalım ve container’a port ve protocol belirleyelim. Ardından dağıtılmış olan container ile replace edelim.

$ vim ornek.yaml
....
spec:
      containers:
      - image: nginx
        name: nginx
        ports:                 # ekledik
        - containerPort: 80    # ekledik
          protocol: TCP        # ekledik
        resources: {}
....

$ kubectl replace -f ornek.yaml
deployment.apps/nginx replaced

Pod ve deployment’ları aynı anda listelemek için virgül ile ayırabilirsiniz.

$ kubectl get deploy,pod
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/nginx   1/1     1            1           2m54s
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-56db997f77-x582m   1/1     Running   0          2m54s

Şimdi nginx dağıtımı içerisindeki servisimizi çalıştırabiliriz.

$ kubectl expose deployment/nginx
service/nginx exposed

nginx dağıtımımız üzerinden oluşturduğumuz servisi aşağıdaki komut ile bilgilerini görebilir ve listeleyebiliriz. Aşağıdan servis yapılandırmasını doğrulayabiliriz. Listedeki Cluster-IP bizim endpoint’imiz değildir. Calico kubelet ve kube-proxy tarafından Cluster-IP’sinin Endpoint’e işlemesini sağlar. Aşağıda Endpoint’in IP’sine bakarak bunu anlayabiliriz.

$ kubectl get svc nginx
NAME    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   10.106.116.194   <none>        80/TCP    91s

$ kubectl get ep nginx
NAME    ENDPOINTS        AGE
nginx   192.168.1.4:80   3m25s

Pod’umuzun hangi Node’da çalıştığını öğrenelim.

$ kubectl describe pod nginx-56db997f77-x582m | grep Node:
Node:               k8s-vm2/10.142.0.15 => 2. node(worker node'umuz)

curl komutu ile nginx başlangıç sayfasına bağlanalım. Bakalım herşey yolunda gitmiş mi 🙂

$ curl 10.106.116.194:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
....

Şimdi uygulamamızı scale edelim. Web sunucumuzu bir taneden üç taneye çıkaralım.

$ kubectl scale deployment nginx --replicas=3
deployment.extensions/nginx scaled

$ kubectl get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           20m

Endpoint’lerimize bakalım. Onlarda nasıl bir değişiklik olmuş.

$ kubectl get ep nginx
NAME    ENDPOINTS                                      AGE
nginx   192.168.1.4:80,192.168.1.5:80,192.168.1.6:80   18m

Bir pod silindiği zaman ReplicaSet controller’ı tarafından yeni bir pod hemen dağıtılır. Bunun denemesini şöyle yapabiliriz.

$ kubectl get po -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP
nginx-56db997f77-6vszn   1/1     Running   0          5m24s   192.168.1.6
nginx-56db997f77-n9n9p   1/1     Running   0          5m24s   192.168.1.5
nginx-56db997f77-x582m   1/1     Running   0          24m     192.168.1.4  

$ kubectl delete po nginx-56db997f77-6vszn
pod "nginx-56db997f77-6vszn" deleted

$ kubectl get po -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP 
nginx-56db997f77-57rgw   1/1     Running   0          71s     192.168.1.7  
nginx-56db997f77-n9n9p   1/1     Running   0          7m44s   192.168.1.5  
nginx-56db997f77-x582m   1/1     Running   0          26m     192.168.1.4  

$ kubectl get ep nginx
NAME    ENDPOINTS                                      AGE
nginx   192.168.1.4:80,192.168.1.5:80,192.168.1.7:80   23m

Sonuç itibariyle ReplicaSet kullanarak scale ettiğimiz zaman bir pod silindiğinde yerine bizim ayarlamış olduğumuz adet(3) sağlanacak kadar pod dağıtılır. Bu pod’lara yeni IP’ler atanır. Ve bu pod’un sağladığı endpoint değişmiş olur. Ama sonuçta bir nginx’e ClusterIP ile eriştiğimiz için arkada tarafta olan (yıkılan ve yeniden dağıtılan pod) işlemler bizim için kesinti oluşturmaz.

Cluster Dışından Erişim Sağlayalım

exec komutu ile pod’un içerisine erişebilirsiniz. print-env komutunu kullanarak pod’un içerisindeki ortam değişkenlerini yazdırabilirsiniz.

$ kubectl get po
NAME                     READY   STATUS    RESTARTS   AGE
nginx-56db997f77-57rgw   1/1     Running   0          6m44s
nginx-56db997f77-n9n9p   1/1     Running   0          13m
nginx-56db997f77-x582m   1/1     Running   0          32m

$ kubectl exec nginx-56db997f77-57rgw -- printenv | grep KUBERNETES
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp

Daha önceden oluşturduğumuz nginx servisini silelim.

$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   28h
nginx        ClusterIP   10.106.116.194   <none>        80/TCP    31m

$ kubectl delete svc nginx
service "nginx" deleted

Servisii yeniden dağıtalım ama bu sefer LoadBalancer olarak kuracağız. Servise bu sefer baktığımızda EXTERNAL_IP <none> değilde pending olarak görürüz. Bir sağlayıcı LoadBalancer’a yanıt vermediği sürece pending olarak gözükmeye devam eder.

$ kubectl expose deployment nginx --type=LoadBalancer
service/nginx exposed

$ kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP        29h
nginx        LoadBalancer   10.101.110.55   <pending>     80:30339/TCP   19s

Linux makinemizin public IP adresini kullanarak kendi diz üstü bilgisayarınızın web tarayıcısı üzerinden artık nginx web sunucusuna erişebilirsiniz.

Public IP – nginx

Kurulumları kaldıralım. Deployment’ı silmek Endpoint ve Service’leri silmek anlamına gelmiyor. Endpoint ve Service’leride kaldırdığımız deployment gibi kaldırmamız gerekiyor.

$ kubectl delete deployment nginx
deployment.extensions "nginx" deleted

$ kubectl delete ep nginx
endpoints "nginx" deleted

$ kubectl delete svc nginx
service "nginx" deleted

Kubernetes eğitiminin ilk eğitim laboratuvarını burada sonlandırmış oluyoruz. Bir sonraki konu başlığımız Kubernetes Mimarisi‘ni yakından inceleme fırsatımız olacak, 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 !!!!

Bir cevap yazın

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