Kubernetes Service Nedir?

Kubernetes Service, aynı hizmeti sağlayan bir Pod grubuna tek ve sabit bir giriş noktası oluşturmak için kullanılan Kubernetes nesnesidir. Her servisin hizmet verdiği süre boyunca değişmeyen bir IP adresi ve port numarası vardır. Bu sayede dinamik adreslere sahip Pod'lara erişim Service üzerinden kolaylıkla sağlanmış olur.

Pod'lar, herhangi bir zamanda hata vermesi, scale edilmesi veya farklı herhangi bir sebep yüzünden sonlandırılabilir. Ayrıca bir Pod'a atanan rastgele IP adresi yine Pod'un yenilenmesi sonucu farklı rastgele bir IP adresiyle değiştirilebilir. Bu ve benzeri senaryolarda Pod içinde çalışan uygulamanıza onun adresini bilmeden erişemezsiniz. Bu sorunları çözmek için ise Kubernetes Service nesnesi devreye girer.

Kubernetes Service kullanmak için diğer bir nedende birden fazla Pod ile çalışan uygulamanıza gelen trafiği load balancer ile dağıtmaktır. Örneğin bir frontend uygulamanızın üç adet replikası çalışıyorsa, Service nesnesi, gelen istekleri bu üç Pod'a rastgele bir şekilde dağıtır.

Yukarıdaki şemada göreceğiniz üzere, IP adresleri her daim sabit kalacak Frontend ve Backend service'leri, kendilerine gelen trafiği yönettiği Pod'lara yönlendirirler. Böylece bir Service'in altında bir tane veya binlerce Pod çalışsa bile Service giriş noktası sabit kalacağı için Client'lar sorunsuz bir şekilde isteklerini Service üzerinden uygulamamıza gönderebilecektir. Aksi halde Pod'ların adresleri değişken olacağından her seferinde istek adresini öğrenmeleri gerekecekti.

1. Kubernetes Service Tipleri

Bir Kubernetes Service, oluşturken belirttiğimiz tipe göre farklı davranış biçimleri sergiler. Service nesnesi için kullanabileceğimiz 3 tip vardır:

  • ClusterIP
  • NodePort
  • LoadBalancer

Her bir Service tipinin nasıl çalıştığını detaylıca inceleyelim.

1.1. ClusterIP Service Tipi

ClusterIP tipi, varsayılan Kubernetes Service tipi olarak belirlenir ve bir Service oluştururken type parametresini belirtmezseniz, otomatik olarak ClusterIP tipinde bir servis oluşturulur.

ClusterIP tipinde oluşturduğunuz Service'lere sadece cluster içinden erişilebilir.

ClusterIP tipindeki Service'ler, genelde DB veya backend uygulamaları gibi doğrudan dışarıdan gelen trafiğe kapalı olup, yalnızca cluster'ın içindeki frontend uygulamaları gibi aracı uygulamalarla iletişime geçilen senaryolar için uygundur.

1.2. NodePort Service Tipi

NodePort tipi, bir uygulamanın Kubernetes cluster'ı dışındaki kullanıcılar veya uygulamalar tarafından erişilmesi gerektiğinde kullanılır.

NodePort tip Service kullanıldığında, Kubernetes cluster'ındaki her bir node'un IP adresi üzerinde belirli bir port numarası atanır ve bu port numarası üzerinden herhangi bir node'un IP adresi ile servise erişim sağlanabilir.

Bu tip, Service'e harici bir IP adresi atanması gerektirmez ve uygulamanın hem internal Service IP adresi hem de cluster içindeki tüm node'ların IP adresleri üzerinden erişilebilir olmasını sağlar.

Örneğin yukarıdaki şemada, Node 1 veya Node 2'nin IP adresi üzerinden 30123 nolu port numarası ile Service'e ulaşabilirsiniz. Service isteğin hangi Node IP adresi üzerinden geldiğine bakmaksızın rastgele bir Pod'a trafiği yönlendirecektir.

NodePort, varsayılan olarak 30000-32767 arasında bir port numarası atar. Ancak, istediğiniz bir port numarasını da seçebilirsiniz.

💡
İstek Node 1 üzerinden gelse bile, Service ttrafiği Node 2 üzerinde çalışan Pod'a yönlendirebilir. Bunu engellemek için externalTrafficPolicy parametresini yapılandırabilirsiniz. Detaylarını ilerleyen başlıklarda göreceğiz.
💡
Kullanılacak port adresi tüm node'lar üzerinde aynı olacak şekilde tahsis edilir. Tüm node'lar aynı port numarasını expose edeceği için port numarasının tüm node'larda boşta olmasına ve gerekli firewall izinlerinin verilmiş olmasına dikkat edilmelidir.

1.3. LoadBalancer Service Tipi

LoadBalancer tipi, NodePort'un bir extension'ıdır ve cloud provider'larda desteklenmesi durumunda otomatik olarak bir Load Balancer hizmeti ayarlayarak cluster'daki node'lara yönlendirme yapar.

NodePort tipini kullandığınızda, client'lar node IP adreslerine isteklerini atarlar. Fakat node'lar hata durumuna geçtiğinde ve erişilemez olduğunda client'lar uygulamalarınıza erişemez. Bu sebepten ötürü node'larınızın önüne bir Load Balancer koymanız gerekir.

Load Balancer tipinde bir Service oluşturduğunuzda, Kubernetes cluster'ınızın üzerinde çalıştığı cloud provider (AWS, GKE vs) eğer bu LoadBalancer tipinde Service'i destekliyorsa otomatik olarak bir Load Balancer uygulaması oluşturur ve bu Load Balancer Service'e kendine ait public IP adresi ve port atar.

💡
Eğer Kubernetes cluster'ınız LoadBalancer tipini desteklemiyorsa (örneğin minikube), siz LoadBalancer tipini belirtseniz bile NodePort tipince bir Service oluşturacaktır.

2. Service Nesnesi Oluşturmak

Kubernetes Service tiplerinin nasıl çalıştığını gördükten sonra, herbirinin nasıl oluşturulacağına tek tek bakalım.

Service nesnelerini oluşturmaya başlamadan önce dikkat etmeniz gereken önemli bir hatırlatma mevcut: Kubernetes Servis nesneleri, herhangi bir Pod oluşturmaz. Sadece selector aracılığıyla eşleşen Pod'lara trafiği yönlendirir.

Bu sebeple, aşağıdaki Service örneklerini uygulamadan önce, ReplicaSet konusunda gördüğünüz gibi Pod'larınızı oluşturmanız gerekmektedir. Tabi dilerseniz Replication Controller'da kullanabilirsiniz fakat bunun yerine ReplicaSet kullanmanızı öneririz.

Kubernetes ReplicaSet Nedir?
Kubernetes ReplicaSet, belirli bir pod sayısını yönetmek ve high availability sağlamak için kullanılan bir Kubernetes nesnesidir.

2.1. ClusterIP Tipinde Service Oluşturmak

ClusterIP tipinde bir Service nesnesi oluşturmak için aşağıdaki YAML dosyasını referans alabilirsiniz:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  • Bu yaml dosyası my-service adında bir ClusterIP tipinde bir Kubernetes Service oluşturur. selector alanı, Service'in gelen istekleri hangi Pod'lara yönlendireceğini belirler. Bu örnekte, app: my-app etiketi olan Pod'lar seçilir.
  • type alanı, servisin tipini belirtir ve ClusterIP olarak belirtilir. ClusterIP tipinde bir servis oluşturmak için type parametresini ayarlamanıza gerek yoktur. Çünkü varsayılan tip ClusterIP tipidir.
  • ports alanı, Service tarafından dinlenecek portu belirtir. Bu örnekte, 80 numaralı bir TCP portu dinlenir ve bu porta gelen istekler hedef Pod'ların 8080 numaralı portuna yönlendirilir.

Manifest dosyası hazır olduktan sonra kubectl create veya kubectl apply komutlarından birisi ile Service nesnesini oluşturabilirsiniz.

 kubectl create -f file-service.yaml

Ardından kubectl get service komutunu kullandığınızda Service detaylarını göreceksiniz.

$ kubectl get services
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP   67d
my-service   ClusterIP   10.97.42.16   <none>        80/TCP    4s

Çıktıda gördüğünüz gibi my-service isimli ClusterIP tipindeki Service, 10.97.42.16 IP adresi ve 80 portu (port(s) = 80) ile sadece cluster içinden erişilebilir halde (external-ip = <none>) çalışır hale gelmiştir.

Service'in trafiği my-app label'lı Pod'lara yönlendirip yönlendirmediğini test etmek için cluster'ınızda yer alan herhangi bir Pod üzerinden curl komutu çalıştırabilirsiniz.

kubectl exec -it randompod-76dzr -- curl -s http://10.97.42.16:80

Yukarıdaki testteki senaryo şu şekilde çalışır:

2.2. NodePort Tipinde Service Oluşturmak

NodePort tipinde bir Service nesnesi oluşturmak için aşağıdaki YAML dosyasını referans alabilirsiniz:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app: my-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
    nodePort: 30123
  • Bu yaml dosyasının bir önceki ClusterIP yaml dosyasından farkı type ve nodePort parametreleridir.
  • nodePort ile clusterdaki node'ların hangi portunun giriş noktası olarak kullanılacağını belirtirsiniz. Eğer nodePort parametresini eklemezseniz 30000-32767 arasında rastgele bir port atanır.

Manifest dosyası hazır olduktan sonra kubectl create veya kubectl apply komutlarından birisi ile Service nesnesini oluşturabilirsiniz.

 kubectl create -f file-service.yaml

Ardından kubectl get service komutunu kullandığınızda Service detaylarını göreceksiniz.

$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        68d
my-service   NodePort    10.109.107.74   <none>        80:30123/TCP   115s

Çıktıda gördüğünüz gibi my-service isimli NodePort tipindeki Service artık şu iki yerden trafik alır hale gelmiştir:

  • 10.109.107.74 IP adresi ve 80 portu (port(s) = 80:30123) ile sadece cluster içinden
  • Clusterdaki herhangi bir node'un IP adresi ve 30123 (port(s) = 80:30123) ile tüm intternetten

Artık ClusterIP başlığında yaptığımız testin aynısını bu iki erişim methoduyla tekrarlayabilirsiniz.

🛑
Eğer minikube kullanıyorsanız node'larınız sanal makine içinde çalıştığı için node'un IP adresi ile testinizi gerçekleştiremezsiniz. Bu durumda minikube service my-service --url komutu ile minikube'e özel oluşturduğunuz service'e açılan bir bağlantısı adresi alıp testinizi yapabilirsiniz.

2.3. LoadBalancer Tipinde Service Oluşturmak

LoadBalancer tipinde bir Service nesnesi oluşturmak için aşağıdaki YAML dosyasını referans alabilirsiniz:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: LoadBalancer
  selector:
    app: my-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
    nodePort: 32143
  • Bu yaml dosyasının bir önceki ClusterIP yaml dosyasından farkı type ve nodePort parametreleridir.
  • nodePort ile clusterdaki node'ların hangi portunun giriş noktası olarak kullanılacağını belirtirsiniz. Eğer nodePort parametresini eklemezseniz 30000-32767 arasında rastgele bir port atanır.

Manifest dosyası hazır olduktan sonra kubectl create veya kubectl apply komutlarından birisi ile Service nesnesini oluşturabilirsiniz.

 kubectl create -f file-service.yaml

Ardından kubectl get service komutunu kullandığınızda Service detaylarını göreceksiniz.

$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP          PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1       <none>               443/TCP        68d
my-service   NodePort    10.54.17.42     130.211.38.153       80:32143/TCP   115s

Çıktıda gördüğünüz gibi my-service isimli LoadBalancer tipindeki Service artık şu üç yerden trafik alır hale gelmiştir:

  • 10.54.17.42 IP adresi ve 80 portu (port(s) = 80:30123) ile sadece cluster içinden
  • 130.211.38.153 IP adresi ve 80 portu (port(s) = 80:30123) ile tüm intternetten
  • Clusterdaki herhangi bir node'un IP adresi ve 30123 (port(s) = 80:30123) ile tüm intternetten

Şimdi NodePort başlığında yaptığımız testin aynısını bu iki erişim methoduyla tekrarlayabilirsiniz.

🛑
Eğer Kubernetes cluster'ınız bir cloud provider (AWS, GKE vs) üzerinde kurulu değilse External-IP alamayacağınız için public IP ile test yapamazsınız. Ayrıca minikube LoadBalancer tipini desteklemez. Manifest dosyanızda LoadBalancer seçseniz bile NodePort tipi bir Service elde etmiş olursunuz.
kubectl get services
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP        68d
my-service   LoadBalancer   10.105.116.55   <pending>     80:30123/TCP   58s

Uyarıdaki mesajı test ettiğinizde External-IP sütunun daima <pending> durumunda kaldığını görürsünüz.

3. Service Nesnelerinin Ek Özellikleri

Kubernetes Service nesnesi beraberinde birçok parametre ve bu parametrelere bağlı olarak kullanım senaryosu sunar. Bu başlık altında bunlardan en önemlilerini ve bilmeniz gerekenleri listeleyeceğiz.

3.1. Session Affinity Özelliği

Kubernetes Service Session Affinity, belirli bir oturuma ait isteklerin aynı pod'a yönlendirilmesini sağlayan bir özelliktir. Bu, özellikle HTTP veya diğer protokollerde oturum yönetimi yapıldığında yararlı olabilir.

Birden fazla pod'a trafiği yönlendirdiğiniz bir Service oluşturduğunuzda, attığınız her istekte trafiğin rastgele bir pod'a gittiğini görmüştünüz.

Attığınız her istek rastgele bir pod'a gönderilir.

Eğer gönderdiğiniz bir isteğin her zaman aynı pod'a yönlendirilmesini istiyorsanız sessionAffinity parametresini kullanabilirsiniz.

Bir Kubernetes Service'inde Session Affinity özelliği etkinleştirildiğinde, aynı client IP adresinden gelen istekler hep aynı pod'a yönlendirilir. Bu sayede, oturum kimliği ile ilişkili pod'da tutulan oturum bilgilerinin korunması ve istemcilerin aynı oturumda devam etmeleri sağlanır.

apiVersion: v1
kind: Service
spec:
 sessionAffinity: ClientIP

sessionAffinity parametresi iki değer alabilir:

  1. None: Varsayılan değerdir ve sessionAffinity parametresini kullanmadığınızda kullanılır. Tüm gelen istekler rastgele pod'lara yönlendirilir.
  2. ClientIP: Aynı IP adresinden gelen istekler artık hep aynı pod'a yönlendirilir.
💡
Cookie bazlı bir session affinity desteklenmez. Çünkü servisler TCP ve UDP paketlerini filtrelerler. Cookie'ler ise HTTP protokülü ise application layer'da HTTP protokolü ile kullanılabilen bir özelliktir.

3.2. externalTrafficPolicy İle Ekstra Hop Engellemek

NodePort tipini anlatırken Service'in gelen isteği hangi Node IP adresi üzerinden geldiğine bakmaksızın rastgele bir Pod'a yönlendireceğini söylemiştik.

Resimde göreceğiniz gibi client isteğini Node 1 üzerinden gönderdi fakat Service rastgele olacak şekilde gelen isteği Node 2 üzerindeki Pod'a yönlendirdi. Bu işleyiş network'te fazladan bir hop, gecikme ve maaliyet anlamına gelir.

Bu davranışı engellemek için Service manifest dosyasında externalTrafficPolicy parametresini tanımlayabiliriz.

spec:
 externalTrafficPolicy: Local

Bu parametre ile Service artık gelen istekleri, isteğin geldiği Node üzerindeki Pod'lara yönlendirir. Fakat eğer isteğin geldiği Node üzerinde çalışan bir Pod yoksa istek askıda kalır ve başka bir Pod'a yönlendirilmez.Bu nedenle, isteğin geleceğin node'lar üzerinde en az bir Pod'un çalıştığından emin olmalısınız.

Bu parametreyi kullanmanın bir dezavantajı daha vardır. Normalde gelen tüm istekler Service'in altındaki tüm Pod'lara eşit dağıtılır. Fakat bu parametre ile bu dağıtımın oranı değişir.

Örneğin Node A üzerinde bir, Node B üzerinde iki Pod çalıştığını varsayalım. Load Balancer trafiği Node'lara sırasıyla dağıtacağı için Node A trafik geldiğinde bu Node üzerinde çalışan Pod tüm trafiğin yarısını karşılamış olacak.

3.3. Bir Service İçin Birden Fazla Port Tanımlamak

Kubernetes Service nesneleri birden fazla portu aynı anda dinleyebilirler. Eğer Pod'larda çalışan uygulamalarınız için birden fazla port açıksa herbir port için ayrı ayrı Service oluşturmanıza gerek yoktur. Bunun yerine manifest dosyanıza ilgili portları ekleyebilirsiniz.

Örneğin uygulamanız 8080 portundan gelen HTTP isteklerini, 8443 üzerinden gelen HTTPS isteklerini ve 8021 üzerinden gelen FTP isteklerine cevap verecek şekilde çalışıyorsa Service manifest dosyanızı şu şekilde yapılandırabilirsiniz:

apiVersion: v1
kind: Service
metadata:
 name: my-service
spec:
 ports:
 - name: http
   port: 80
   targetPort: 8080
 - name: https
   port: 443
   targetPort: 8443
 - name: ftp
   port: 21
   targetPort: 821
 selector:
   app: my-app
💡
Bir Service nesnesinin portları örnekteki gibi çoklanabilir fakat label selector tüm Service geneli için seçilebilir. Port bazlı label selector ayarlanamaz.

3.4. Port'lara İsim Tanımlamak

Yukarıdaki başlıkta bir Service nesnesine birden fazla port tanımlayabileceğimizi gördünüz. Ekstra faydalı bir yetenek olarak targetPort parametrelerine port numarası yerine Pod'larda tanımlanmış port isimlerini de verebilirsiniz.

Uygulamanızın şu anda HTTP isteklerini 8080 portundan karşıladığını varsayalım. Yukarıdaki örnek manifesteleri de buna göre yazmıştık. Fakat ilerleyen zamanlarda bu portu herhangi bir sebep yüzünden değiştirmek istediğinizde Service nesnesini de düzenlemeniz gerekir. Aksi halde Service, gelen trafiği doğru porta yönlendiremez.

Service nesnelerinde bu tür düzenlemeler yapmak uygun değildir. Bu nedenle eğer Pod manifestinde portlara isim verirseniz ve Service manifestinde bu isimlere yönlendirme ayarlarsanız, uygulamanızın port numaraları değişse bile artık Service nesnesini düzenlemeniz gerekmez.

Örnek olarak Pod manifest dosyamızda port tanımlarımızı name parametreleriyle oluşturalım:

kind: Pod
spec:
 containers:
 - name: my-app
 ports:
 - name: http
   containerPort: 8080
 - name: https
   containerPort: 8443
 - name: ftp
   containerPort: 821

Artık Service manifest dosyamızda direkt port isimlerini kullanabiliriz:

apiVersion: v1
kind: Service
metadata:
 name: my-service
spec:
 ports:
 - name: http
   port: 80
   targetPort: http
 - name: https
   port: 443
   targetPort: https
 - name: ftp
   port: 21
   targetPort: ftp
 selector:
   app: my-app

Bundan sonra uygulamanızın portları değişse bile Service her daim kesintisiz yönlendirme yapmaya devam edecektir.

3.5. Pod'lar İçin Service Keşfi

Bir Service oluşturarak, artık Pod'larınıza erişmek için tek ve kararlı bir IP adresiniz ve bağlantı noktanız olmuş olur. Bu adres, Service'in tüm ömrü boyunca değişmeden kalacaktır. Bu Service'in arkasındaki Pod'lar ise gelip gidebilir, IP'leri değişebilir, sayıları artabilir veya azalabilir.

Peki bir Pod'lar bir Service'e bağlanmak istediğinde (örneğin frontend pod'ları backend Service'ine bağlanacağı zaman) ilgili Service'in IP'sini ve portunu nasıl bilir? Önce Service'i oluşturmanız, ardından IP adresini Pod'ların config dosyasına manuel olarak eklemeniz mi gerekiyor? Tam olarak değil. Kubernetes, Pod'ların bir Service'in IP'sini ve portlarını keşfetmesi için bazı yollar sağlar.

3.5.1 Service Bilgilerinin Pod'lara Environment Variables'larına Eklenmesi

Bir Pod oluşturulduğunda, Kubernetes, bu Pod'un environment variables listesine her Service'in IP adresi ve port numarasını ekler. Örneğin bir üstteki Service manifest dosyasını oluşturup rastgele bir Pod'un env listesine bakarsak ilgili değişkenleri görürüz.

$ kubectl exec my-replicaset-c87v2 -- env
•••
MY_SERVICE_PORT_80_TCP_ADDR=10.101.120.58
MY_SERVICE_PORT_80_TCP_PORT=80
•••
•••
MY_SERVICE_PORT_443_TCP_ADDR=10.101.120.58
MY_SERVICE_PORT_443_TCP_PORT=443
•••
•••
🚧
Bir Service oluşturduğunuzda, bu Service'i oluşturmadan önce mevcut olan Pod'larda ilgili environment variable'ları göremezseniz. Eğer bu variable'ların oluşturulmasını istiyorsanız eski Pod'ları silerek yeniden oluşturmalısınız.

Böylece uygulamanızda bu environment variable'larını kullanarak cluster'da yer alan herhangi bir Service'e kolaylıkla ulaşabilirsiniz.

3.5.2 DNS Server İle Service Bilgilerine Ulaşmak

Kubernetes cluster'ınız, kube-system isimli bir namespace içerir. Bu namespace içinde çalışan service'leri listelerseniz kube-dns isimli bir Service'i görürsünüz. kube-dns Service'i DNS Server görevi görür ve cluster'da yer alan tüm nesnelerin birbirleriyle DNS üzerinden haberleşebilmesini sağlar.

kubectl get services -n kube-system -o wide
NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                  AGE   SELECTOR
kube-dns         ClusterIP   10.96.0.10      <none>        53/UDP,53/TCP,9153/TCP   68d   k8s-app=kube-dns
metrics-server   ClusterIP   10.105.83.162   <none>        443/TCP                  46d   k8s-app=metrics-server

Kubernetes, bir pod oluşturulduğunda ilgili Pod'un /etc/resolv.conf dosyasına cluster'da DNS Server olarak çalışan kube-dns isimli Service'in IP adres bilgisini ekler.

kubectl exec my-replicaset-c87v2 -- cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Böylece tüm Kubernetes nesneleri, örneğin Pod'lar, başka bir Kubernetes nesnesiyle iletişime geçeceği zaman onun kaynak adını kullanabilir.

Örneğin, bir Pod, oluşturduğumuz my-service isimli Service'e istek atacağı zaman şu isimleri kullanarak iletişime geçebilir:

  • my-service.default.svc.cluster.local
  • my-service.svc.cluster.local
  • my-service.cluster.local
  • my-service

Yani bir Pod'un içinde şu komutların hepsi başarılı bir şekilde yanıt verecektir:

curl http://my-service
curl http://my-service.cluster.local
curl http://my-service.svc.cluster.local 
curl http://my-service.default.svc.cluster.local 

3.6. Service IP Adreslerini Pinglemek

Muhtemelen son örnekte yaptığınız gibi mevcut bir Pod'a girip Service'e curl komutu göndererek test edeceksiniz. Fakat eğer başarılı bir sonuç alamazsanız Service IP adresini çalışıp çalışmadığını test etmek için pinglemeyi deneyeceksiniz.

$ ping my-service
PING my-service.default.svc.cluster.local (10.111.249.153): 56 data bytes
^C--- my-service.default.svc.cluster.local ping statistics ---
54 packets transmitted, 0 packets received, 100% packet loss

Hmm. Service curl atabiliyorsunuz, ancak ping atmak işe yaramıyor. Bunun nedeni, Service'in cluster IP'sinin sanal bir IP olması ve yalnızca Service port numarasıyla birleştirildiğinde anlam kazanmasıdır. Bu nendele daha fazla ping atmayı kesebilirsiniz :)

3.7. Service Pod'ları Nasıl Bulur?

Service'ler, trafiği hangi Pod'lara yönlendireceği bilgisini elde etmek için Endpoints isimli bir Kubernetes nesnesi kullanırlar. Yani, bir Service doğrudan Pod'lara bağlantı vermez.

Bir Service nesnesi oluşturduğunuzda otomatik olarak aynı isimle bir de Endpoints nesnesi oluşturulur.

Herhangi bir Service için kubectl describe komutunu çalıştırdığınızda Endpoints isimli bir parametrenin olduğunu görürsünüz.

$ kubectl describe service my-service
Name: my-service
Namespace: default
Labels: <none>
Selector: app=my-app
Type: ClusterIP
IP: 10.111.249.153
Port: <unset> 80/TCP
Endpoints: 10.244.2.118:80,10.244.2.122:80,10.244.2.123:80
Session Affinity: None

Kubernetes Endpoints nesnesi, bir Service'in kullanacağı IP adresi ve portların tutulduğu bir liste görevi görür.

Endpoints, bir Kubernetes nesnesi olduğu için de kubectl get endpoints ile görüntülenebilir ve kubectl describe endpoints komutu ile detaylarına bakabilirsiniz.

$ kubectl get endpoints
NAME         ENDPOINTS                                         AGE
my-service   10.244.2.118:80,10.244.2.122:80,10.244.2.123:80   50s
$ kubectl describe endpoints my-service
Name:         my-service
Namespace:    default
Labels:       <none>
Annotations:  endpoints.kubernetes.io/last-change-trigger-time: 2023-05-10T13:13:19Z
Subsets:
  Addresses:          10.244.2.118,10.244.2.122,10.244.2.123
  NotReadyAddresses:  <none>
  Ports:
    Name     Port  Protocol
    ----     ----  --------
    <unset>  80    TCP

Events:  <none>
💡
Service oluştururken kullandığımız selector, Service ile birlikte otomatik oluşturulan Endpoint nesnesinin IP adres ve port listesini oluşturulurken kullanılır. Service için bir etkisi yoktur.

Kubernetes Endpoints için daha fazla detayı aşağıdaki yazımızda bulabilirsiniz:

Kubernetes Endpoints Nedir?
Kubernetes Endpoints, bir Service’in yönlendirme yapacağı adresleri tutmak için kullanılan bir Kubernetes nesnesidir.

3.8. Service Trafiğini Bir Domaine Yönlendirmek

Service trafiğini selector ile seçilen Pod'lar veya Endpoints nesnesi ile oluşturduğunuz dış adreslere yönlendirmek yerine harici bir fully qualified domain name (FQDN) adrese de yönlendirebilirsiniz.

Harici bir domaine yönlendirme yapmak için Service manifest dosyasında selector kullanmamalı ve type parametresini ExternalName seçmelisiniz.

apiVersion: v1
kind: Service
metadata:
 name: external-service
spec:
 type: ExternalName
 externalName: someapi.somecompany.com
 ports:
 - port: 80

Service'i bu şekilde oluşturduktan sonra artık Service'e gelen istekler ilgili FQDN adresine yönlendirilecektir. Böylece bu domaini Pod'larda konfigüre etmek yerine tek bir nesneden yönetebilir ve ileride gerçekleşebilecek herhangi bir adres değişikliğinde Pod configlerinin etkilenmemesini sağlamış olursunuz.

3.9. Sorunlu Pod'lara Service Trafiğini Engellemek

Bir Service nesnesini oluşturduğunuzda, Service'e gelen trafik hemen endpoints listesinde yer alan Pod'lara yönlendirilir. Fakat eğer Pod'larınızda bir problem varsa client'lar sorun yaşamaya başlar. Bu durumu engellemek için Readiness ve Liveness probe kullanmanız gerekir. Böylece eğer bir Pod hazır değil veya unhealthy bir durumdaysa Service ilgili Pod'a trafiği yönlendirmeyecektir.


Sıradaki yazı ile eğitim serisine devam edebilirsiniz.

Kubernetes Readiness ve Liveness Nedir?
Kubernetes readiness ve liveness, uygulamaların hizmete hazır olup olmadığını ve çalışmaya devam edip etmediğini takip etmek için bir dizi mekanizma sunar.