Kubernetes: İlk uygulamayı dağıtma

Kubernetes üzerinde uygulama dağıtmak için pratik rehber. Minikube kurulumundan Deployment, Service ve ConfigMap'lere kadar somut örneklerle.

İlk uygulamayı dağıtmak için Kubernetes rehberi

Kubernetes (K8s), konteyner orkestrasyonu için fiili standart haline geldi. Google tarafından tasarlanan ve şu anda CNCF tarafından sürdürülen Kubernetes, konteynerleştirilmiş uygulamaların dağıtımını, ölçeklendirilmesini ve yönetimini otomatikleştirir. Bu rehber, yerel bir kümenin kurulmasını ve ilk uygulamanın dağıtılmasını adım adım anlatır.

Ön koşullar

Kubernetes'e derinlemesine girmeden önce temel Docker bilgisine sahip olunması önerilir. Konteynerler, Kubernetes'in orkestre ettiği temel yapı taşlarıdır. Docker rehberinin önceden okunması, burada sunulan kavramların anlaşılmasını çok daha kolay kılar.

Kubernetes mimarisini anlamak

Kubernetes, master-worker mimarisine dayanır. Control Plane küme hakkında genel kararları verirken, Node'lar iş yüklerini çalıştırır.

text
# Simplified Kubernetes Architecture

┌─────────────────────────────────────────────────────────────┐
│                      CONTROL PLANE                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │ API Server  │  │ Scheduler   │  │ Controller Manager  │ │
│  └─────────────┘  └─────────────┘  └─────────────────────┘ │
│  ┌─────────────────────────────────────────────────────────┐│
│  │                        etcd                             ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
         ┌────────────────────┼────────────────────┐
         ▼                    ▼                    ▼
┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
│     NODE 1      │  │     NODE 2      │  │     NODE 3      │
│  ┌───────────┐  │  │  ┌───────────┐  │  │  ┌───────────┐  │
│  │  kubelet  │  │  │  │  kubelet  │  │  │  │  kubelet  │  │
│  ├───────────┤  │  │  ├───────────┤  │  │  ├───────────┤  │
│  │ kube-proxy│  │  │  │ kube-proxy│  │  │  │ kube-proxy│  │
│  ├───────────┤  │  │  ├───────────┤  │  │  ├───────────┤  │
│  │   Pods    │  │  │  │   Pods    │  │  │  │   Pods    │  │
│  └───────────┘  │  │  └───────────┘  │  │  └───────────┘  │
└─────────────────┘  └─────────────────┘  └─────────────────┘

API Server, tüm komutlar için giriş noktasıdır. etcd küme durumunu saklar. Scheduler, Pod'ları Node'lara atar. Controller'lar, sistemin istenen durumunu korur.

Yerel ortamı kurmak

Kubernetes ile yerel olarak deneyim yapmak için birkaç seçenek mevcuttur: minikube, kind, k3d veya Docker Desktop. Minikube, öğrenmek için en popüler çözüm olmaya devam eder.

bash
# terminal
# Install kubectl (Kubernetes client)
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/

# Verify installation
kubectl version --client
# Client Version: v1.31.0

# Install minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

# Start the local cluster
minikube start --driver=docker --cpus=2 --memory=4096

# Check status
minikube status
# minikube: Running
# cluster: Running
# kubectl: Configured

Minikube, sanal bir makine veya Docker konteyneri içinde tek düğümlü bir Kubernetes kümesi oluşturur. Tahsis edilen kaynaklar (CPU, bellek) ihtiyaca göre ayarlanabilir.

bash
# terminal
# Access the Kubernetes dashboard (web interface)
minikube dashboard

# Check cluster nodes
kubectl get nodes
# NAME       STATUS   ROLES           AGE   VERSION
# minikube   Ready    control-plane   5m    v1.31.0

# Detailed cluster information
kubectl cluster-info
Minikube alternatifleri

Kind (Kubernetes in Docker) daha hızlı başlar ve CI/CD testlerine daha iyi uyum sağlar. K3d, Kubernetes'in hafif bir dağıtımı olan k3s'i kullanır. Docker Desktop, Kubernetes'i doğrudan entegre eder ancak daha fazla kaynak tüketir.

Pod'lar: temel birim

Pod, Kubernetes'teki en küçük dağıtılabilir birimdir. Bir Pod, aynı ağı ve depolamayı paylaşan bir veya daha fazla konteyneri kapsar.

yaml
# pod-simple.yaml
apiVersion: v1
kind: Pod
metadata:
  # Unique Pod name within the namespace
  name: nginx-pod
  # Labels for organization and selection
  labels:
    app: nginx
    environment: development
spec:
  containers:
    # Main container definition
    - name: nginx
      # Docker image to use
      image: nginx:1.25-alpine
      # Ports exposed by the container
      ports:
        - containerPort: 80
      # Container resource allocation
      resources:
        requests:
          memory: "64Mi"
          cpu: "100m"
        limits:
          memory: "128Mi"
          cpu: "200m"

Bu YAML manifest, tek bir nginx konteyneri içeren bir Pod'u tanımlar. Etiketler, Pod'ları tanımlamayı ve seçmeyi sağlar. Kaynaklar minimum garantileri (requests) ve maksimum sınırları (limits) belirler.

bash
# terminal
# Create the Pod
kubectl apply -f pod-simple.yaml
# pod/nginx-pod created

# List Pods
kubectl get pods
# NAME        READY   STATUS    RESTARTS   AGE
# nginx-pod   1/1     Running   0          30s

# Full Pod details
kubectl describe pod nginx-pod

# Container logs
kubectl logs nginx-pod

# Execute a command inside the Pod
kubectl exec -it nginx-pod -- /bin/sh

# Delete the Pod
kubectl delete pod nginx-pod

Pod'lar doğası gereği geçicidir. Çökme veya silme durumunda Kubernetes onları otomatik olarak yeniden oluşturmaz. Deployment'lar bu sınırlamayı çözer.

Deployment'lar: bildirimsel yönetim

Deployment, aynı tipteki Pod kümesi için istenen durumu tanımlar. Kubernetes, gerektiğinde Pod'lar oluşturarak, güncelleyerek veya silerek bu durumu otomatik olarak korur.

yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  # Deployment name
  name: webapp-deployment
  labels:
    app: webapp
spec:
  # Desired number of replicas
  replicas: 3
  # Selector to identify managed Pods
  selector:
    matchLabels:
      app: webapp
  # Template for Pod creation
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "200m"
          # Liveness probe: restarts container on failure
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          # Readiness probe: removes Pod from Service on failure
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5

Deployment, 3 aynı Pod'u koruyan bir ReplicaSet oluşturur. Probe'lar konteynerlerin durumunu kontrol eder ve Kubernetes'in sorunlara otomatik olarak tepki vermesini sağlar.

bash
# terminal
# Create the Deployment
kubectl apply -f deployment.yaml
# deployment.apps/webapp-deployment created

# Verify the Deployment
kubectl get deployments
# NAME                READY   UP-TO-DATE   AVAILABLE   AGE
# webapp-deployment   3/3     3            3           1m

# List Pods created by the Deployment
kubectl get pods -l app=webapp
# NAME                                READY   STATUS    RESTARTS   AGE
# webapp-deployment-7d9f8b6c4-abc12   1/1     Running   0          1m
# webapp-deployment-7d9f8b6c4-def34   1/1     Running   0          1m
# webapp-deployment-7d9f8b6c4-ghi56   1/1     Running   0          1m

# Manual scaling
kubectl scale deployment webapp-deployment --replicas=5

# Deployment history
kubectl rollout history deployment webapp-deployment

Bir Pod'u silmek, istenen replika sayısını korumak için yeni bir Pod'un oluşturulmasını otomatik olarak tetikler.

DevOps mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Service'ler: ağ erişimi

Pod'lar geçici IP adreslerine sahiptir. Service'ler, yerleşik yük dengeleme ile bir Pod kümesine erişmek için kararlı bir adres sağlar.

yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-service
spec:
  # Service type: ClusterIP (internal), NodePort, LoadBalancer
  type: ClusterIP
  # Selector to identify target Pods
  selector:
    app: webapp
  ports:
    # Port exposed by the Service
    - port: 80
      # Target container port
      targetPort: 80
      # Protocol (TCP by default)
      protocol: TCP

Bu ClusterIP Service yalnızca küme içinden erişilebilir. webapp-service:80 adresine yapılan istekler, app: webapp etiketini taşıyan Pod'lar arasında dağıtılır.

bash
# terminal
# Create the Service
kubectl apply -f service.yaml
# service/webapp-service created

# List Services
kubectl get services
# NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
# webapp-service   ClusterIP   10.96.123.456   <none>        80/TCP    30s

# Test from a temporary Pod
kubectl run curl-test --rm -it --image=curlimages/curl -- curl webapp-service

# Detailed Service description
kubectl describe service webapp-service

Uygulamayı kümenin dışına açmak için NodePort veya LoadBalancer türü gereklidir.

yaml
# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp-nodeport
spec:
  type: NodePort
  selector:
    app: webapp
  ports:
    - port: 80
      targetPort: 80
      # Port on each Node (30000-32767)
      nodePort: 30080

Minikube ile minikube service webapp-nodeport komutu, tarayıcıyı otomatik olarak doğru URL'de açar.

ConfigMap'ler: dışsallaştırılmış yapılandırma

ConfigMap'ler yapılandırmayı koddan ayırır. Değerler ortam değişkenleri olarak enjekte edilir veya dosya olarak monte edilir.

yaml
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: webapp-config
data:
  # Simple key-value pairs
  APP_ENV: "production"
  LOG_LEVEL: "info"
  MAX_CONNECTIONS: "100"
  # Multiline configuration (complete file)
  nginx.conf: |
    server {
        listen 80;
        server_name localhost;

        location / {
            root /usr/share/nginx/html;
            index index.html;
        }

        location /health {
            return 200 'OK';
            add_header Content-Type text/plain;
        }
    }

ConfigMap'ler hassas olmayan verileri saklar. Sırlar (parolalar, token'lar) için Kubernetes Secret'ları daha uygundur.

yaml
# deployment-with-config.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-configured
spec:
  replicas: 2
  selector:
    matchLabels:
      app: webapp-configured
  template:
    metadata:
      labels:
        app: webapp-configured
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          # Inject environment variables
          envFrom:
            - configMapRef:
                name: webapp-config
          # Or individual variables
          env:
            - name: SPECIFIC_VAR
              valueFrom:
                configMapKeyRef:
                  name: webapp-config
                  key: LOG_LEVEL
          # Mount configuration file
          volumeMounts:
            - name: nginx-config
              mountPath: /etc/nginx/conf.d/default.conf
              subPath: nginx.conf
      volumes:
        - name: nginx-config
          configMap:
            name: webapp-config

Bu yapılandırma ortam değişkenlerini enjekte eder ve nginx.conf dosyasını konteyner içine monte eder.

bash
# terminal
# Apply resources
kubectl apply -f configmap.yaml
kubectl apply -f deployment-with-config.yaml

# Verify environment variables
kubectl exec deployment/webapp-configured -- printenv | grep APP_ENV
# APP_ENV=production

# Verify mounted file
kubectl exec deployment/webapp-configured -- cat /etc/nginx/conf.d/default.conf
ConfigMap güncellemeleri

Bir ConfigMap'i değiştirmek Pod'ları otomatik olarak yeniden başlatmaz. Değişiklikleri uygulamak için manuel yeniden başlatma gerekir: kubectl rollout restart deployment webapp-configured. Reloader gibi araçlar bu süreci otomatikleştirir.

Secret'lar: hassas veriler

Secret'lar parolalar, token'lar veya SSH anahtarları gibi hassas bilgileri saklar. Base64 ile kodlanmış olsalar da varsayılan olarak depolanırken şifrelenmezler.

yaml
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: webapp-secrets
type: Opaque
# Values must be base64-encoded
data:
  # echo -n 'admin' | base64
  username: YWRtaW4=
  # echo -n 'supersecretpassword' | base64
  password: c3VwZXJzZWNyZXRwYXNzd29yZA==
---
# Alternative: stringData accepts plain text values
apiVersion: v1
kind: Secret
metadata:
  name: webapp-secrets-plain
type: Opaque
stringData:
  username: admin
  password: supersecretpassword

Secret'lar ConfigMap'lerle aynı şekilde enjekte edilir.

yaml
# deployment-with-secrets.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-secure
spec:
  replicas: 1
  selector:
    matchLabels:
      app: webapp-secure
  template:
    metadata:
      labels:
        app: webapp-secure
    spec:
      containers:
        - name: webapp
          image: nginx:1.25-alpine
          env:
            - name: DB_USERNAME
              valueFrom:
                secretKeyRef:
                  name: webapp-secrets
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: webapp-secrets
                  key: password
bash
# terminal
# Create the Secret
kubectl apply -f secret.yaml

# List Secrets (values are not displayed)
kubectl get secrets
# NAME              TYPE     DATA   AGE
# webapp-secrets    Opaque   2      10s

# Decode a value
kubectl get secret webapp-secrets -o jsonpath='{.data.password}' | base64 -d
# supersecretpassword

Namespace'ler: mantıksal izolasyon

Namespace'ler bir kümeyi izole sanal ortamlara böler. Bu ayrım, aynı küme üzerinde birden fazla ekibi veya ortamı yönetmeyi mümkün kılar.

yaml
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: development
  labels:
    environment: development
---
apiVersion: v1
kind: Namespace
metadata:
  name: staging
  labels:
    environment: staging

Her kaynak belirli bir namespace içinde oluşturulabilir.

bash
# terminal
# Create namespaces
kubectl apply -f namespace.yaml

# List namespaces
kubectl get namespaces
# NAME          STATUS   AGE
# default       Active   1d
# development   Active   10s
# staging       Active   10s

# Create a resource in a specific namespace
kubectl apply -f deployment.yaml -n development

# List Pods in a namespace
kubectl get pods -n development

# Change default namespace
kubectl config set-context --current --namespace=development

Farklı namespace'lerdeki kaynaklar varsayılan olarak izole edilir. Namespace'ler arası iletişim dahili DNS üzerinden gerçekleşir: service-name.namespace.svc.cluster.local.

Eksiksiz uygulama: kaynakları birleştirme

İşte sunulan tüm kavramları birleştiren eksiksiz bir uygulama.

yaml
# complete-app.yaml
---
# Dedicated Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: myapp
---
# ConfigMap for configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
  namespace: myapp
data:
  APP_NAME: "MyApp"
  LOG_LEVEL: "info"
---
# Secret for sensitive data
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secrets
  namespace: myapp
type: Opaque
stringData:
  api-key: "sk-1234567890abcdef"
---
# Deployment with 3 replicas
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  namespace: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: nginx:1.25-alpine
          ports:
            - containerPort: 80
          envFrom:
            - configMapRef:
                name: myapp-config
          env:
            - name: API_KEY
              valueFrom:
                secretKeyRef:
                  name: myapp-secrets
                  key: api-key
          resources:
            requests:
              memory: "64Mi"
              cpu: "100m"
            limits:
              memory: "128Mi"
              cpu: "200m"
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 5
            periodSeconds: 5
---
# Service for internal exposure
apiVersion: v1
kind: Service
metadata:
  name: myapp-service
  namespace: myapp
spec:
  type: ClusterIP
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
---
# NodePort Service for external access (development)
apiVersion: v1
kind: Service
metadata:
  name: myapp-nodeport
  namespace: myapp
spec:
  type: NodePort
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30100

Bu tek dosya, dışsallaştırılmış yapılandırma, sırlar, yüksek kullanılabilirlik ve ağ erişimi ile eksiksiz bir uygulamayı dağıtır.

bash
# terminal
# Deploy the complete application
kubectl apply -f complete-app.yaml

# Verify all resources
kubectl get all -n myapp
# NAME                         READY   STATUS    RESTARTS   AGE
# pod/myapp-7d9f8b6c4-abc12    1/1     Running   0          30s
# pod/myapp-7d9f8b6c4-def34    1/1     Running   0          30s
# pod/myapp-7d9f8b6c4-ghi56    1/1     Running   0          30s
#
# NAME                    TYPE        CLUSTER-IP      PORT(S)        AGE
# service/myapp-service   ClusterIP   10.96.123.456   80/TCP         30s
# service/myapp-nodeport  NodePort    10.96.123.789   80:30100/TCP   30s
#
# NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
# deployment.apps/myapp   3/3     3            3           30s

# Access the application with minikube
minikube service myapp-nodeport -n myapp

Güncellemeler ve geri almalar

Kubernetes, kademeli güncellemeleri ve geri almaları kolaylaştırır.

bash
# terminal
# Update the Deployment image
kubectl set image deployment/myapp myapp=nginx:1.26-alpine -n myapp

# Track deployment in real-time
kubectl rollout status deployment/myapp -n myapp
# Waiting for deployment "myapp" rollout to finish: 1 out of 3 new replicas updated
# Waiting for deployment "myapp" rollout to finish: 2 out of 3 new replicas updated
# deployment "myapp" successfully rolled out

# Revision history
kubectl rollout history deployment/myapp -n myapp
# REVISION  CHANGE-CAUSE
# 1         <none>
# 2         <none>

# Rollback to previous revision
kubectl rollout undo deployment/myapp -n myapp

# Rollback to a specific revision
kubectl rollout undo deployment/myapp --to-revision=1 -n myapp

Varsayılan güncelleme stratejisi (RollingUpdate), eski Pod'ları yenileri ile kademeli olarak değiştirir ve kesintisiz erişilebilirliği garanti eder.

Temel kubectl komutları

bash
# terminal
# ========================================
# General Information
# ========================================
kubectl cluster-info                    # Cluster info
kubectl get nodes -o wide               # Nodes with details
kubectl api-resources                   # List resource types

# ========================================
# Resource Management
# ========================================
kubectl get all                         # All namespace resources
kubectl get pods -A                     # Pods from all namespaces
kubectl get pods -o wide                # Pods with IP and Node
kubectl get pods -w                     # Watch mode (real-time)

# ========================================
# Inspection and Debugging
# ========================================
kubectl describe pod <name>             # Full details
kubectl logs <pod> -f                   # Streaming logs
kubectl logs <pod> -c <container>       # Specific container logs
kubectl exec -it <pod> -- /bin/sh       # Interactive shell
kubectl port-forward <pod> 8080:80      # Local tunnel to Pod

# ========================================
# Editing and Deletion
# ========================================
kubectl edit deployment <name>          # Live editing (vi)
kubectl delete -f manifest.yaml         # Delete via file
kubectl delete pod <name> --force       # Force deletion

Sonuç

Kubernetes, bildirimsel, dayanıklı ve genişletilebilir bir çerçeve sunarak konteynerleştirilmiş uygulama yönetimini dönüştürür. Burada sunulan temel kavramlar, üretime hazır dağıtımların temelini oluşturur.

İlk Kubernetes dağıtımı için kontrol listesi

  • ✅ Çalışan yerel küme (minikube, kind veya k3d)
  • ✅ Kurulu ve yapılandırılmış kubectl
  • ✅ Replikalar ve health probe'lara sahip Deployment
  • ✅ Ağ erişimi için Service
  • ✅ Dışsallaştırılmış yapılandırma için ConfigMap
  • ✅ Hassas veriler için Secret
  • ✅ İzolasyon için Namespace
  • ✅ Tanımlanmış kaynak limitleri (requests/limits)
  • ✅ Güncelleme stratejisi ve geri alma kontrol altında

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Kubernetes'e hakim olmak, ölçeklenebilir cloud-native mimarilerin kapısını açar. Sonraki adımlar arasında HTTP yönlendirmesi için Ingress Controller'ları, depolama için PersistentVolume'leri ve paket yönetimi için Helm'i keşfetmek yer alır. Kubernetes, DevOps ve SRE görüşmelerinde önemli bir kazanım haline gelir.

Etiketler

#kubernetes
#k8s
#container orchestration
#devops
#deployment

Paylaş

İlgili makaleler