2. Deployment ve Istio
← Önceki: 1. Istio Service Mesh
Yazının 2. kısmında öncelikle local ortamdaki Kubernetes cluster’ımıza Istio kurulumu yapacağız, seçtiğimiz bir cluster üzerinde istio-injection enable olarak label ekleyeceğiz ve ardından Go ile bir client ve bir server yazacağız. Client belli aralıklar ile server tarafına http istekleri gönderecek ve yanıt alacak daha sonrasında client ve server için Kubernetes deployment ve service objelerini yazacağız.
Bu aşamaların ardından client ve server uygulamalarını Kubernetes objeleri sayesinde cluster’ımız üzerinde deploy edeceğiz.
Burada sonuç olarak beklentimiz Istio’nun bizim eklediğimiz deployment yaml’a istinaden oluşacak pod’ları yakalaması ve bu podların yanına side-car container’ını inject etmesi.
Özetle bu yazı şu aşamalalardan oluşacak.
- Istio kurulum ve istio-injection
- Client ve server uygulamalarını yazmak
- Client ve server için Kubernetes manifestlerini yazmak
- Istio injection için pod inceleme
Istio kurulumu ve istio-injection
Bu işlem için cihazda kurulu bir cluster olması gerektiğini hatırlatarak devam ediyorum. Local k8s cluster için: https://kind.sigs.k8s.io
Mevcut clusterımıza istio yükleyerek başlayalım.
istioctl install
Şimdi her şey yolunda ise namespace’leri kontrol ederek devam edelim. Istio kendi kubernetes nesnelerini “istio-system” namespace’i altına kuruyor. Bu doğrultuda namespace’leri listeleyerek kontrol edebiliriz.
kubectl get ns
NAME STATUS AGE
default Active 3h54m
istio-system Active 3h49m
Bu komut sonucunda istio-system çıktısını görüyorsak her şey yolunda gidiyor.
Son olarak tüm işlemlerin başarılı olup olmadığını görmek için verify komutunu çalıştırabiliriz.
istioctl verify-install
Her şey yolunda ise sırada istio-injection bulunuyor.
Istio-injection’dan bir önceki yazıda da bahsetmiştim. Istio-injection aslında belirlediğimiz bir namespace için label tanımlama işinden ibaret. Biz bu label’ı tanımladığımızda Istio bu namespace’de yayınlanan uygulamalara side-car ekliyor ve yayınlanan servisleri tespit edip service discovery yapıyor.
Evet ilgili label’ı ekleyelim.
kubectl label namespace default istio-injection=enabled --overwrite
Ben default namespace için istio-injection’u aktif ettim.
Şimdi label eklenmiş mi kontrol edelim.
kubectl get ns --show-labels
NAME STATUS AGE LABELS
default Active 3h53m istio-injection=enabled
Şimdi server uygulamamızı yazarak devam edebiliriz. Basit bir server yazacağız, bir adet endpoint hizmet verecek ve 200 dönecek.
server/main.go
package main
import "net/http"
func main() {
http.HandleFunc("/test", test)
http.ListenAndServe(":8080", nil)
}
func test(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
w.Write([]byte("hi"))
}
Hızlıca bu uygulamayı Dockerize edelim.
server/Dockerfile
FROM golang:1.20
WORKDIR /app
COPY . .
RUN go build -o main main.go
CMD ["./main"]
EXPOSE 8080
Artık bu uygulamadan bir Docker image yaratıp imajı local cluster’ımızın registry’sine atabiliriz.
Dockerfile’ın bulunduğu klasörde:
docker build . -t server:v1
Image yaratıldıktan sonra Kind registry’sine yükleyelim:
kind load docker-image server:v1
Artık Kubernetes objelerini hazırlayabiliriz.
Basit bir yaml hazırlayalım, bu yaml dosyası deployment ve service objesi içerecek.
server/manifest.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: server-deployment
labels:
name: server
app: server
version: v1
spec:
replicas: 1
selector:
matchLabels:
name: server
template:
metadata:
labels:
name: server
app: server
version: v1
spec:
containers:
- name: server
image: server:v1
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: server-service
spec:
selector:
name: server
ports:
- protocol: TCP
port: 8080
targetPort: 8080
Deployment dosyası Kubernetes web sitesindeki basit örnek ile nerede ise aynı sadece alışılmışın dışında 2 adet label var, app ve version bunları daha sonra Kiali bölümünde inceleyeceğiz.
Service objesi zaten oldukça açık hedef container’lardaki 8080 portuna isteklerin yönlendirilmesini sağlayacak.
Aynı aşamaları client tarafı için de uygulayacağız.
Şimdi client tarafı için gerekenleri yapalım.
Client uygulamamızın amacı belirli aralıklarla server uygulamasına http istekleri göndermek olacak. Epey basit bir kod:
client/main.go
package main
import (
"fmt"
"io"
"net/http"
"time"
)
func main() {
t := time.NewTicker(time.Second)
for range t.C {
client := &http.Client{}
addr := "http://server-service.default.svc.cluster.local:8080/test"
res, err := client.Get(addr)
if err != nil {
fmt.Printf("error occured while getting %s :%v\n", addr, err)
continue
}
body, _ := io.ReadAll(res.Body)
res.Body.Close()
fmt.Printf("Date: %s Status Code: %d Response Body: %s\n", time.Now().String(), res.StatusCode, string(body))
}
}
Burada dikkat etmemiz gereken tek şey addr değişkeni olacaktır. Istio service adresleri için FQDN kullanıyor. Yani bir service objesine ulaşmak için host şu formatta olmalı:
<svc-name>.<namespace>.svc.cluster.local
Şimdi benzer bir Dockerfile ile client uygulamamızı Dockerize edelim.
client/Dockerfile
FROM golang:1.20
WORKDIR /app
COPY . .
RUN go build -o main main.go
CMD ["./main"]
Client Dockerfile dosyasının bulunduğu dizinde:
docker build . -t client:v1
Client image’ını da kind registry’sine yükleyelim.
kind load docker-image client:v1
Son olarak Client uygulamamızın Kubernetes objesini içeren yaml dosyasını hazırlayalım. Client için sadece Pod objesi yeterli olacaktır.
client/manifest.yaml
apiVersion: v1
kind: Pod
metadata:
name: client
labels:
app: client
version: v1
spec:
containers:
- name: client
image: client:v1
Evet artık client ve server uygulamalarını deploy etmek için hazırız.
kubectl apply -f server/manifest.yaml
Şimdi deploy ettiğimiz server uygulamasını kontrol edelim.
Bu yaptıklarımızın sonucunda beklentimiz istio’nun bu objeleri yakalaması ve hem service discovery gerçekleştirmesi hem de uygulama podlarımızın içerisine side-car container eklemesi olacaktır.
Öncelikli server podlarını kontrol ederek başlayalım.
kubectl get pods
NAME READY STATUS RESTARTS AGE
server-deployment-98df8b777-rgtmm 2/2 Running 0 119s
Burada 2 container gözüküyor, inceleyelim.
kubectl describe pod server-deployment-98df8b777-rgtmm
Çıktıyı incelediğiniz incelediğinizde uygulama container’ı haricinde “istio-proxy” adında bir container daha olduğunu göreceksiniz. Istio-injection’da bir sorun yok gibi duruyor.
Şimdi client uygulamasını oluşturalım ve http isteklerini loglardan inceleyelim.
kubectl apply -f manifest.yml
Podları tekrar listeleyelim.
kubectl get pods
NAME READY STATUS RESTARTS AGE
client 2/2 Running 0 37s
server-deployment-98df8b777-rgtmm 2/2 Running 0 6m50s
Client uygulamamızın da side-car’ı eklenmiş duruyor.
Şimdi client loglarına göz atalım.
kubectl logs client
Date: 2023-08-28 18:17:45.687685297 Status Code: 200 Response Body: hi
Date: 2023-08-28 18:17:46.673205297 Status Code: 200 Response Body: hi
Date: 2023-08-28 18:17:47.676762256 Status Code: 200 Response Body: hi
Date: 2023-08-28 18:17:48.677489798 Status Code: 200 Response Body: hi
Date: 2023-08-28 18:17:49.673319299 Status Code: 200 Response Body: hi
Client uygulamamız server’a başarılı şekilde ulaşabiliyor.
Şimdiye kadar başarılı şekilde Istio kurulumu yaptık, uygulamalarımızı Istio’nun side-car inject edebileceği şekilde yaratabildik.
Uygulamaların ikisi de sağlıklı şekilde çalışıyor, client server uygulamasına Istio üzerinden erişebiliyor.
Bir sonraki yazıda Kiali adlı araç ile Istio objelerini ve Istio üzerindeki ağ trafiğini inceleyceğiz .
→ Sonraki: 3. Kiali ile Istio Ağ Trafiği