Yazılım

Mikroservis mimarisi, uygulamaları daha küçük, bağımsız ve yönetilebilir parçalara ayırma stratejisidir. Bu mimarinin karmaşıklığını yönetmek için güçlü bir orkestrasyon aracına ihtiyaç vardır. İşte tam da burada Kubernetes devreye giriyor. Bu blog yazısında, Kubernetes’in temel objelerini, manifest dosyalarının nasıl yazılacağını ve Helm Charts ile uygulama paketlemeyi detaylıca inceleyeceğiz.

 1. Kubernetes Objeleri

 Kubernetes, çeşitli objeler aracılığıyla konteynerize edilmiş uygulamaları yönetir. Bu bölümde, en temel ve sık kullanılan Kubernetes objelerini inceleyeceğiz.

 1.1. Pod

Pod, Kubernetes’teki en küçük ve en temel birimdir. Bir veya daha fazla container’ı gruplar ve aynı kaynakları paylaşmalarını sağlar.

Örnek bir Pod YAML manifestı:

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx:latest
    ports:
    - containerPort: 80
```

Bu manifest:

1. `my-pod` adında bir Pod oluşturur.

2. `nginx:latest` imajını kullanan bir container içerir.

3. Container’ın 80 portunu expose eder.

 1.2. Deployment

Deployment, Pod’ların istenen sayıda çalışmasını ve güncellemelerini yönetir.

Örnek bir Deployment manifestı:


```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-container
        image: my-app:v1
        ports:
        - containerPort: 8080
```

Bu manifest:

1. `my-deployment` adında bir Deployment oluşturur.

2. 3 replika oluşturur.

3. `app: my-app` etiketine sahip Pod’ları seçer.

4. `my-app:v1` imajını kullanan container’lar oluşturur.

 1.3. Service

Service, Pod’lara sabit bir IP adresi ve DNS adı sağlayarak, uygulamanın diğer bileşenler tarafından keşfedilebilmesini sağlar.

Örnek bir Service manifestı:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: my-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
  type: ClusterIP
```

Bu manifest:

1. `my-service` adında bir Service oluşturur.

2. `app: my-app` etiketine sahip Pod’ları seçer.

3. 80 portunu 8080 portuna yönlendirir.

4. `ClusterIP` tipinde bir service oluşturur (cluster içinden erişilebilir).

1.4. Ingress

Ingress, cluster dışından HTTP ve HTTPS trafiğini yönetir ve routing kuralları tanımlar.

Örnek bir Ingress manifestı:

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: myapp.example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: my-service
            port: 
              number: 80
```

Bu manifest:

1. `my-ingress` adında bir Ingress oluşturur.

2. `myapp.example.com` host’u için bir kural tanımlar.

3. `/api` path’ini `my-service` adlı service’e yönlendirir.

2. Kubernetes Manifest Dosyaları Yazma

Kubernetes manifest dosyaları, cluster’ınızda oluşturmak istediğiniz kaynakları tanımlayan YAML dosyalarıdır. İyi bir manifest dosyası yazmak için bazı best practice’leri takip etmelisiniz.

 2.1. Manifest Dosyası Yapısı

Bir Kubernetes manifest dosyası genellikle şu bölümlerden oluşur:

1. `apiVersion`: Kullanılan Kubernetes API versiyonu

2. `kind`: Oluşturulacak kaynağın türü (örn. Pod, Deployment, Service)

3. `metadata`: İsim, namespace, etiketler gibi meta bilgiler

4. `spec`: Kaynağın özelliklerini tanımlayan bölüm

 2.2. Çoklu Kaynak Tanımlama

Bir YAML dosyasında birden fazla kaynak tanımlayabilirsiniz. Kaynakları `—` ile ayırın:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
   Deployment özellikleri...

---

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
   Service özellikleri...
```

 2.3. Ortam Değişkenleri Kullanımı

Container’lara ortam değişkenleri geçmek için `env` veya `envFrom` kullanabilirsiniz:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: my-app:v1
        env:
        - name: DATABASE_URL
          value: "mysql://user:password@db-service:3306/mydb"
        envFrom:
        - configMapRef:
            name: my-config
```

 2.4. ConfigMap ve Secret Kullanımı

Konfigürasyon ve hassas bilgileri ayrı tutmak için ConfigMap ve Secret objelerini kullanın:

ConfigMap örneği:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  APP_COLOR: blue
  APP_MODE: production
```

Secret örneği:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  DB_PASSWORD: base64EncodedPassword
```

Bu ConfigMap ve Secret'ları Pod'larda kullanma:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: my-app:v1
        envFrom:
        - configMapRef:
            name: my-config
        env:
        - name: DATABASE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: my-secret
              key: DB_PASSWORD
```

 2.5. Resource Limits ve Requests

Container’ların kullanabileceği kaynakları sınırlamak ve garanti etmek için resource limits ve requests kullanın:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: my-app:v1
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi
```

 2.6. Health Checks

Liveness ve readiness probe’ları kullanarak uygulamanızın sağlığını kontrol edin:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      containers:
      - name: my-container
        image: my-app:v1
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 3
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          periodSeconds: 5
```

 3. Helm Charts ile Uygulama Paketleme

Helm, Kubernetes uygulamalarını paketlemek, paylaşmak ve dağıtmak için kullanılan bir paket yöneticisidir. Helm Charts, uygulamanızın tüm Kubernetes kaynaklarını tek bir pakette toplamanıza olanak tanır.

 3.1. Helm Chart Yapısı

Tipik bir Helm Chart yapısı şu şekildedir:

```
mychart/
  Chart.yaml
  values.yaml
  charts/
  templates/
    deployment.yaml
    service.yaml
    ingress.yaml
  charts/
  README.md
```

– `Chart.yaml`: Chart’ın meta bilgilerini içerir.

– `values.yaml`: Varsayılan konfigürasyon değerlerini içerir.

– `templates/`: Kubernetes manifest şablonlarını içerir.

– `charts/`: Bağımlı chart’ları içerir (opsiyonel).

 3.2. Chart.yaml Örneği

```yaml
apiVersion: v2
name: my-app
description: A Helm chart for my awesome app
version: 0.1.0
appVersion: "1.0.0"
```

 3.3. values.yaml Örneği

```yaml
replicaCount: 2

image:
  repository: myrepo/myapp
  tag: v1.0.0
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
```

 3.4. Template Örnekleri

deployment.yaml:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "my-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-app.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
```

service.yaml:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "my-app.fullname" . }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "my-app.selectorLabels" . | nindent 4 }}
```

 3.5. Helm Komutları

Helm Chart oluşturma:
```
helm create my-app
```

Helm Chart'ı yükleme:
```
helm install my-release ./my-app
```

Değerleri override ederek yükleme:
```
helm install my-release ./my-app --set replicaCount=3
```

Helm Chart'ı güncelleme:
```
helm upgrade my-release ./my-app
```

Yüklü release'leri listeleme:
```
helm list
```

Bir release'i kaldırma:
```
helm uninstall my-release
```

 3.6. Helm Chart Best Practices

1. **Parametreleştirme**: Mümkün olduğunca çok değeri `values.yaml` dosyasında parametreleştirin.

2. **Koşullu Kaynak Oluşturma**: Bazı kaynakları koşullu olarak oluşturmak için if-else yapılarını kullanın:

   ```yaml
   {{- if .Values.ingress.enabled }}
   apiVersion: networking.k8s.io/v1
   kind: Ingress
    ...
   {{- end }}

3. **Helper Fonksiyonlar**: Tekrar eden mantığı `_helpers.tpl` dosyasında tanımlayın:

   ```yaml
   {{/* Generate basic labels */}}
   {{- define "my-app.labels" -}}
   app.kubernetes.io/name: {{ include "my-app.name" . }}
   app.kubernetes.io/instance: {{ .Release.Name }}
   {{- end }}
   ```

4. **Bağımlılıkları Yönetme**: Bağımlı chart’ları `Chart.yaml` dosyasında belirtin:

   ```yaml
   dependencies:
     - name: mysql
       version: 8.8.3
       repository: https://charts.bitnami.com/bitnami
       condition: mysql.enabled
   ```

5. **Doğrulama**: `helm lint` komutunu kullanarak chart’ınızı doğrulayın.

6. **Sürüm Kontrolü**: Chart’ınızı bir versiyon kontrol sistemi (örn. Git) ile yönetin.

4. Mikroservis Uygulaması Örneği

Şimdi, öğrendiğimiz tüm bu konseptleri bir araya getirerek basit bir e-ticaret mikroservis uygulaması için Kubernetes manifestları ve Helm Chart oluşturalım.

 4.1. Uygulama Mimarisi

Uygulamamız şu mikroservislerden oluşacak:

– Product Service

– Order Service

– User Service

– API Gateway

 4.2. Kubernetes Manifestları

product-deployment.yaml:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: product-service
spec:
  replicas: 2
  selector:
    matchLabels:
      app: product-service
  template:
    metadata:
      labels:
        app: product-service
    spec:
      containers:
      - name: product-service
        image: myrepo/product-service:v1
        ports:
        - containerPort: 8080
        env:
        - name: DB_HOST
          value: product-db-service
```

product-service.yaml:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: product-service
spec:
  selector:
    app: product-service
  ports:
  - port: 80
    targetPort: 8080
```

Benzer şekilde, diğer servisler için de Deployment ve Service manifestları oluşturulmalıdır.

api-gateway-ingress.yaml:

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api-gateway
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: myecommerce.com
    http:
      paths:
      - path: /products
        pathType: Prefix
        backend:
          service:
            name: product-service
            port: 
              number: 80
      - path: /orders
        pathType: Prefix
        backend:
          service:
            name: order-service
            port: 
              number: 80
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: user-service
            port: 
              number: 80
```

 4.3. Helm Chart Oluşturma

Şimdi bu mikroservis uygulaması için bir Helm Chart oluşturalım:

```
helm create ecommerce-app
```

values.yaml:

```yaml
global:
  environment: production

productService:
  replicaCount: 2
  image:
    repository: myrepo/product-service
    tag: v1

orderService:
  replicaCount: 2
  image:
    repository: myrepo/order-service
    tag: v1

userService:
  replicaCount: 2
  image:
    repository: myrepo/user-service
    tag: v1

apiGateway:
  enabled: true
  host: myecommerce.com
```

templates/product-deployment.yaml:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "ecommerce-app.fullname" . }}-product
spec:
  replicas: {{ .Values.productService.replicaCount }}
  selector:
    matchLabels:
      app: product-service
  template:
    metadata:
      labels:
        app: product-service
    spec:
      containers:
      - name: product-service
        image: "{{ .Values.productService.image.repository }}:{{ .Values.productService.image.tag }}"
        ports:
        - containerPort: 8080
        env:
        - name: ENVIRONMENT
          value: {{ .Values.global.environment }}
```

Benzer şekilde, diğer servisler için de template'ler oluşturulmalıdır.

templates/ingress.yaml:

```yaml
{{- if .Values.apiGateway.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "ecommerce-app.fullname" . }}-gateway
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
  - host: {{ .Values.apiGateway.host }}
    http:
      paths:
      - path: /products
        pathType: Prefix
        backend:
          service:
            name: {{ include "ecommerce-app.fullname" . }}-product
            port: 
              number: 80
      - path: /orders
        pathType: Prefix
        backend:
          service:
            name: {{ include "ecommerce-app.fullname" . }}-order
            port: 
              number: 80
      - path: /users
        pathType: Prefix
        backend:
          service:
            name: {{ include "ecommerce-app.fullname" . }}-user
            port: 
              number: 80
{{- end }}
```

 4.4. Helm Chart’ı Yükleme

Chart’ı yüklemek için:

```
helm install my-ecommerce ./ecommerce-app
```

Belirli değerleri override etmek için:

```
helm install my-ecommerce ./ecommerce-app --set productService.replicaCount=3 --set global.environment=staging
```

 5. Sonuç

Bu blog yazısında, Kubernetes ile mikroservis orkestrasyonunun temellerini, Kubernetes objelerini, manifest dosyası yazma tekniklerini ve Helm Charts ile uygulama paketlemeyi detaylı bir şekilde inceledik.

Kubernetes, mikroservis mimarisinin karmaşıklığını yönetmek için güçlü araçlar sunar. Pod’lar, Deployment’lar, Service’ler ve Ingress’ler gibi temel Kubernetes objeleri, mikroservisleri ölçeklendirmek, yönetmek ve dış dünyaya açmak için gerekli yapı taşlarını oluşturur.

Manifest dosyaları, bu Kubernetes objelerini dekleratif bir şekilde tanımlamanıza olanak tanır. İyi yazılmış manifest dosyaları, uygulamanızın istenen durumunu net bir şekilde ifade eder ve Kubernetes’in bu durumu korumasını sağlar.

Helm ise, tüm bu manifest dosyalarını tek bir paket halinde yönetmenize, versiyonlamanıza ve dağıtmanıza olanak tanır. Helm Charts, mikroservis uygulamalarınızı farklı ortamlara kolayca dağıtmanızı ve yönetmenizi sağlar.