Bu yazımda kubernetes’e kısa bir giriş yapıp, daha sonra kubernetes(K8) terimleri — konseptleri üzerinde duracağım.
Şimdi biraz eskiden uygulamaları nasıl deploy ediyorduk ona bakalım.
Geleneksel yöntemde uygulamaları fiziksel serverlara yüklüyorduk. Bir fiziksel makine içinde de kaynakları uygulama bazında izole etmek pek mümkün olmuyordu. Bu sebeple kimi uygulama çok kaynak kullanıyordu ve diğer uygulamalara yeterli kaynak kalmıyordu. Uygulamaları farklı sunuculara kurmak her ne kadar çözüm olsada bu çok maliyetli, uğraştırıcı ve sistem kaynaklarının verimsiz bir şekilde kullanılmasına yol açıyor.
Bunlara çözüm olarak sanallaştırma doğdu. Sanallaştırma bize fiziksel bir makine üzerinde birden çok sanal makine kurabilme şansı verdi, sistem kaynaklarının daha efektif kullanılmasına olanak sağladı,ortamlar arasında izolasyon sağladı. Farkı uygulamalar farklı sanal makineler üzerinde çalıştığı için birbirlerinin kaynaklarını sömürmüyolardı.
Bu sanal makineleri çalıştırmak için fiziksel makine ile sanal makine arasına hypervisor denilen bir katman daha ekleniyor. Bu katman sayesinde sanal makinelere fiziksel sistemden CPU,RAM,Disk alanı gibi kaynakları verebiliyoruz. Yani sanal makineler containerların aksine direk olarak sistem kaynaklarına erişmiyor, onun yerine bir Hardware Abstraction Layer (HAL) üzerinden kaynaklara erişiyor. Bunun sanal makinelere yarattığı bazı dezavantajlar var;
- Container’lara kıyasla daha yavaş boot time
- Her VM için komple işletim sistemi yüklendiği için gereğinden fazla tekrar eden komponent — Sitemde daha fazla yer tutması
- CPU — RAM gibi kaynakları daha fazla tüketmeleri
- Uygulamaları paketlenip taşınması containerlara kıyasla daha zor
Aşağıda da görebilceğiniz gibi container teknolojileri ile yavaş ve hantal hypervisor katmanını aradan kaldırıyoruz.
Containerlar da aslında kendilerine ait CPU,hafıza,disk alanı bulundukları için sanal makinelere benziyorlar fakat hypervisor olmadan, daha esnek bir şekilde izolasyon olduğu için sanal makinelere göre çok daha hızlıdırlar. Bu yüzden bazıları container’lara kısaca “lightweight VM” diyor.
Şimdi kubernetes’e gelelim. Container teknolojileri çok popüler bir hale geldi. Birçok şirket uygulamalarını farklı platformlar üzerinde çalışcak şekilde container mimarisinde deploy etmeye başladı. Bu sebeple bütün bu container’ların bir platform altında yönetilmesini sağlayan tool’lara ihtiyaç oluştu. İşte Kubernetes de tam burada devreye giriyor. Birkaç container’ınız varsa sadece docker API’larını kullanarak problemlerin üstesinden gelmeye çalışabilirsiniz fakat uygulama kapsamı biraz genişlediğinde, yani container sayısınız arttığında bunu sadece docker ile yapmak çok zor hale geliyor.
K8 ile container’ları otomatik olarak deploy edip, sayılarını yüke göre otomatik olarak arttırabilir, canary deployment, otomatik yeniden başlatma, load balancing, DNS gibi özellikleri kolayca ekleyip, operasyonal container işlemlerinizin çoğunu otomotize edebilirsiniz.
Kubernetes aslında bir “Resource scheduler”dır.
Bilgisayar bilimlerinde “scheduling” belli bir işin, o işi yapma yeteneği olan çeşitli birimlere aktırılması, dağıtılması işine denir. Buna örnek olarak işletim sistemlerinde bu bir programın hangi CPU’lar üzerinde çalışacağına karar vermek veya programın hangi kaynak kodunun hangi thread üzerinde çalışacağına karar vermek olarak verebiliriz. Özetle lisedeki iş-işci problemleri gibi düşünebilirsiniz.
Amazon EC2, Azure Fabric, and OpenStack Nova gibi çözümler ise sanal makineleri gerçek makinelere dağıtılması ile ilgilenen resource scheduler’lardır.
Heroku gibi PaaS çözümleri ise servislerin paketlenip sanal makine veya gerçek makinelere dağıtılmasını sağlayan resource scheduler’lardır.
Container tarafında ise bunlara örnek olarak Kubernetes ve Mesosphere’i verebiliriz. Her ikiside alt çalışan fiziksel sistemleri soyutlaştırarak container’ları çalıştırmaya olanak sağlar.
Kubernetes neler yapabilir?
- Servis keşfi ve load balancing
- Depolama yönetimi - Kubernetes’e çeşitli depolama çözümleri bağlayabilirsiniz.
- Otomatik rollouts ve rollbacks
- Otomatik hata düzeltme — fail olmuş container’ları yeniden başlatma
- Horizontal Scaling
- Şifre ve konfigürasyon yönetimi vb …
Şimdi de biraz K8 terimlerinden bahsedelim.
Kubernetes Objeleri
Kubernetes Cluster: Aşağıda görselini paylaştığım, K8'in en büyük komponent’i olarak düşünebilirsiz. K8 tarafından yönetilen node’lar birliğidir. En azından bir worker node ve bir master node olmak zorundadır.
Namespace: K8 bir gerçek cluster üzerinde bir kaç sanal cluster barındırabilir, bu sanal cluster’ların herbirine namespace denir. Genellikle çok büyük K8 yapılarında ihtiyaç duyulur namespace’lere.
Node: Cluster’da ki VM veya gerçek makinelere denir. Peki neden direk sanal makine fln demiyoruz? Çünkü node diyerek bir çeşit soyutlaştırma yapıyoruz. Biz ayrı ayrı makinelerin güçleri ile ilgilenmiyoruz. Onlara sadece “yeri geldiğinde değiştirilebilir” iş güçleri olarak bakıyoruz.
Pod: Container’ların içinde çalıştığı komponentlerdir. En küçük atanabilir birimdir. Kendilerine has IP’leri vardır.İçlerinde bir veya daha fazla container bulundurabilir. Genelde bir container en istenilenidir, bir pod’a çok fazla container koymak mimari açıdan çok doğru olmayabilir. Bu durumu sadece pod içindeki container’lar tightly coupled olduğu zaman kullanmalısınız. Pod’ların en büyük avantajı kopyalanabilir olmalarıdır. Yük altında kolaylıkla kopyalayıp, iş gücünü artırabiliriz.
Init Container: Bunlarıda ön şart olarak düşünebilirsiniz.Asıl app container’lar başlamadan çalışan ön containerlardır. Bunlar tamamlandıktan sonra app container’lar başlar.
Replication Controller: Belli sayıda pod’un her zaman çalıştığını kontrol eden K8 servisi. Replica Set’i bunun yeri versiyonu olarak düşünebilirsiniz, eski kodlarda sıkca göreceksinizdir genelde.
Replica Sets: Replication Controller’ler ile neredeyse aynı işi yapar. Belli sayıda pod’un her zaman çalıştığını kontrol eder. Ufak tefek syntax ve görev farklılıkları vardır aralarında.
Deployment: Uygulamarınızı K8'e deploy ve update etmek için şuan en meşhur ve tavsiye edilen yöntemdir. Replication controllerin yerine geçmesi amacı ile çıkartıldı. İşlemleri yine kendisi gibi yeni olan replica set’ler aracılığı ile yapar. Rollout changes gibi özellikleri vardır. Aşağıdaki örnek deployment kod parçası ReplicaSet aracılığı ile 3 adet nginx pod’u ayağa kaldırır.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
ConfigMap: Konfigrasyon datalarını tutmak için kullandığımız bir yapıdır. Dictionary yani Key- Value şeklinde çalışır. URL’ler,Stringler vb public olan bilgileri saklamak için oldukça kullanışlıdır.
Aşağıdaki gif’te örnek olarak üç ortam yaratılmış ve her bir ortam için bir config map yaratılmış. Uygulamayı farklı bir ortama taşımak için sadece configmap ayarını değiştirmeniz yeterli oluyor. Her bir değişkeni ayrı ayrı yeniden değiştirmenize gerek kalmıyor.
Persistent Volume: Herhangi bir node’a bağlı olmayan, kalıcı olarak veri depolamak için cluster’a bağladığımız komponent. Klasik sanal makine mimarisinin aksine K8'de node’lar gelip geçici iş güçü olarak bakılırlar. Bu yüzden buralarda kalıcı veri depolamak doğru değildir. Bunun için Persistent Volume tercih edilir. Persistent volume’lar diğer komponentlerin aksine cluster tarafından yönetilmez.
Kubernetes Service Account: Podların API server ile haberleşmesinde kullanılan bir K8 kaynağı. Her namespace’de default isminde bir service account olur.
Horizontal Pod Autoscaler: Replication controller, Deployment veya Replica set’leri otomatik olarak scale eden bir kubernetes kaynağı. CPU, RAM veya kendinizin belirleyeceği özel metrikler ile scale etmesini tetikleyebilirsiniz.
fib isimli deployment’ı CPU değerine göre otomatik olarak scale edecek HPA örneği:
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2beta1
metadata:
name: fib
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
apiVersion: app/v1
kind: Deployment
name: fib
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 60
Master Komponentler
Bu komponentler master node üzerinde çalışır, cluster durumunu gözetlerler ve cluster’da oluşan olaylara cevap dönerler. 5 adet master komponent bulunur;
Kubernetes API Server: Cluster’ın önyüzü, kontrol paneli gibi davranan ana komponent. Pods, service gibi objelerin konfigrasyonunu sağlar, RESTful çalışır, Horizontal Scale edip trafiği node’lar arasında dağıtabilirsiniz.
etcd: Cluster hakkında Key-value şeklinde bilgilerin tutulduğu data havuzu. K8 haricinde çoğu distributed uygulamada kullanılır. Bununla ilgili bir yazıyı çok yakın zamanda paylaşacağım.
Kubernetes Scheduler: Yukarıda da daha detaylı bahsettiğim scheduling işini yapan komponent. Temel hedefi hiç bir pod’un node’suz kalmamasını sağlamaktır.
kube-controller-manager: Node, replication set, endpoints (services) ve service accounts gibi birimleri izleyen temel kontrol platformlarında biri. Bu birimlerin her biri için controller denilen işlemler çalışır. Bunları kube-controller-manager çalıştırır.
cloud-controller-manager: Google,Amazon,Azure vb bulut platformları ile iletişimi sağlayan komponent.
Node Komponentler
Bunlar master komponentlerin aksine her node’da çalışır:
kubelet: Her node’da çalışan bir komponent. Konteynerlerin durumunu inceler ve master notlara rapor verir. Aynı zamanda kube-apiserver’dan yeni komutları bekler.
kube-proxy: Her cluster’da mutlaka bir tane olan network kuralları ile ilgilenen komponent.
container runtime: Container’ları çalıştıran yazılım. En meşhur örneği Docker’dır. Rkt, runc, CRI-O (Benim favorim) gibi alternatifleri de vardır.
Kubernetes Service Discovery
Mikroservis mimarisinde servislerin birbirini bulabilmesi çok kritik bir aşamadır. Özellikle kubernetes gibi çoğu şeyin dinamik olarak ayarlandığı günümüz ortamlarında, statik olarak servis IP’leri girmek çoğu zaman işi içinden çıkalamayacak zorluklara sürükler. Şimdi biraz Kubernetes’de service discovery yapmanın ne kadar kolay olduğunu görelim.
K8'de out-of-the-box olarak iki çeşit service discovery desteği vardır- birisi ortam değişkenleri ile, diğeride DNS ile.
Bir pod çalıştığı zaman kubelet otomatik olarak ilgili ortam değişkenlerini node’a ekler. Daha sonra bu ortam değişkenlerini uygulamamıza ekleyerek diğer servisleri bu değişkenler yardımıyla çağırabiliriz. Örnek bir redis-master servisi için kubelet’in eklediği değişkenlere göz atalım.
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
Ortam değişkenleri ile service discovery’de sıralama sorun çıkartabilir. Örneğin bir pod bir servise ortam değişkeni aracılığı ile erişmek istiyorsa mutlaka servisin pod’dan önce yaratılmış olması gereklidir. Bu yüzden benim tercihim ikinci yol olan DNS ile service discovery yapmanızdır.
Domain Name System teriminin kısaltması olan DNS çok özet olarak aklımızda tutmamızın zor olduğu IP’lere bir isim atayarak kullanımı kolaylaştırır. DNS’i kubernetes’de kullanmak için cluster’da kube-dns eklentisinin olduğundan emin olunuz. Default ayarları değiştirmediyseniz kube-dns servisinin detaylarına buradan ulaşabilirsiniz:
kubectl describe svc kube-dns -n kube-system
Dikkat ettiyseniz kube-dns default namespace’de değil, kube-system namespace’inde yaşıyor.
Bundan sonra yapmanız gereken çok birşey kalmıyor aslında. Örnek üstünden gitmek gerekirse, ns-berk namespace’inde yaşayan test-service isimli servisiniz varsa bu servise diğer servislerden;
Eğer aynı namespace’de ise : test-service veya testservice.ns-berk
Farklı namespace’de ise : testservice.ns-berk
adreslerini kullanarak erişebilirsiniz. Bunları test etmek için bir pod’a bağlanıp nslookup kullanabilirsiniz.
Kubernetes’deki en temel konseptleri ve teknolojileri özetledim. Bunları kullanarak container orchestration’a dair çoğu şeyi yapabilirsiniz. Öğrenmek istediğiniz veya daha fazla detay istediğiniz bir K8 konsepti varsa lütfen yorumlara yazınız. Amacım burayı bir türkçe K8 referans yazısını haline getirmek, vakit buldukça buraya daha fazla terim eklemeye çalışacağım. Şimdilik bu kadar. Hoşçakalın!
Kaynaklar