Production Kubernetes Kontrol Listesi: Kaynak Limitleri, RBAC ve Gözlemlenebilirlik

2026-04-18 8 min

Kubernetes, çılgınca yanlış yapılandırılmış bir iş yükünü mutlu mesut çalıştırır. Memory limit koymayı unuttuğunuzu, gece 3'te bir node yanmaya başlayana kadar size söylemez. Aşağıdaki kontrol listesi, bir kümeye önemli bir şey teslim etmeden önce mutlaka geçtiğim minimum.

1. Her container'a requests ve limits ata

Yapabileceğiniz en yüksek kaldıraçlı tek şey. Limit yoksa, sızdıran bir pod memory'i tüketerek tüm node'u götürebilir. Request yoksa, scheduler iyi yerleştirme kararı veremez ve dolu-sonra-OOM olan node'larla kalırsınız.

resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    memory: 256Mi

Memory'nin limiti var ama CPU'nun yalnızca request'i. Bu kasıtlı. Memory aşımı pod'u öldürür; CPU aşımı sadece throttle eder. Agresif CPU limit'lerinden kaynaklanan throttling, debug ettiğim servislerde gizemli latency sıçramalarının sık bir nedeni oldu. CPU'yu kapsız bırakın, scheduler'ın işini request'le yapmasına izin verin.

2. RBAC: en az ayrıcalık, istisna yok

Bir iş yüküyle gelen her ServiceAccount, yalnızca gerçekten kullandığı verb ve resource'ları listeleyen bir Role (veya ClusterRole) almalı. Varsayılan ServiceAccount'un izni yok — istediğiniz tam da bu, daha geniş bir şeye bind etmeyin.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: my-app
  name: config-reader
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list", "watch"]

Bir CI işini kolaylaştırmak için resource veya verb'lere "*" verme dürtüsüne direnin. Şimdiki kolaylık, sonra bir incident raporu olur.

3. Network policy: default deny

Varsayılan olarak her pod, kümedeki diğer her podla konuşabilir. Bir sandbox'ın ötesindeki her şey için her namespace'e default-deny network policy deploy edin, sonra ihtiyaç duyduğunuz spesifik trafiği allow edin.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: my-app
spec:
  podSelector: {}
  policyTypes: ["Ingress", "Egress"]

Default-deny devreye girdikten sonra, meşru akışlar için küçük allow policy'leri yazarsınız. İlk yapışınızda, kimsenin dokümante etmediği yollardan birbiriyle konuşan servisleri keşfetmek bir gün sürebilir.

4. Anlamlı probe'lar

Liveness probe, öldürülmesi gereken bir süreci tespit etmeli. Readiness probe, ayakta olan ama trafik almaya hazır olmayan bir süreci tespit etmeli. Kötü probe'lardan kaynaklanan production incident'lerinin çoğu ya (a) çok agresif liveness'in meşru yavaş işlemler sırasında pod'u öldürmesi, ya da (b) readiness'in liveness'le karıştırılıp yavaş başlayan pod'ların ısınması bitmeden öldürülmesi şeklindeydi.

readinessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10
  failureThreshold: 3

Aynı endpoint her iki probe'u da destekliyorsa, readiness yine de daha ucuz veya daha hoşgörülü olmalı. Sert kontrol liveness olmalı.

5. PodDisruptionBudget

PDB olmadan, rutin bir node drain (küme yükseltmesi veya autoscaler scale-down sırasında) deployment'ınızın tüm replica'larını aynı anda evict edebilir. PDB ile birlikte eviction minimum'unuza saygı duyar.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-app
spec:
  minAvailable: 1
  selector:
    matchLabels:
      app: my-app

İki replica'lı deployment'lar için minAvailable: 1 doğru. Daha büyük deployment'lar için yüzde olarak maxUnavailable'ı tercih edin.

6. Gözlemlenebilirlik: üç sinyal, sadece metrik değil

Prometheus ve Grafana metrik yarısını çözer. Log veya trace çözmez ve diğer ikisi olmadan bir incident sınıfı için kör debug edersiniz.

  • Metrikler: Prometheus, her pod'un /metrics'inden scrape edilir. Mutlak eşiklere değil, değişim oranına alert atın.
  • Loglar: merkezi bir toplayıcı (Loki, Elastic, Cloudwatch agent). Düz metin değil, yapılandırılmış JSON log.
  • Trace'ler: uygulamada OpenTelemetry SDK, Tempo veya Jaeger'a gönderilir. Servisler arası latency sorunlarında en faydalı.

En hızlı kazanım log'lar. En zor sonradan ekleneni trace'ler.

7. İmaj policy'si

İmaj tag'lerini digest'e pin'leyin, latest gibi kayan tag'lere değil. CI'da imajları CVE için tarayın (Trivy ucuz ve iyi). Non-root user ile çalıştırın. Uygulama izin veriyorsa read-only root filesystem kullanın.

securityContext:
  runAsNonRoot: true
  runAsUser: 1001
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false

Hiçbiri egzotik değil. Sıkıcı incident'leri engelleyen sıkıcı kontroller.