Laptop with code editor open, notebook and pen on wooden desk, perfect for tech and work themes.

İzmir’deki bir e-ticaret platformunda 47 mikroservis vardı: Java Spring Boot, Node.js, Python FastAPI, hatta birkaç Go servisi. Trafik artarken iki problem büyüdü: (1) servisler arası TLS yoktu, güvenlik denetimi yan gözle bakıyordu; (2) bir API gecikmesinin hangi servisten geldiği aramak yarım gün sürüyordu. Ekip “service mesh ekleyelim” deyince Istio’ya gittik. Üç ay süren bu projeden çıkardığım kararlar bu yazıda. Her karar öncesi düşündüğüm tablonun, sahada nasıl çıktığının kayıtları.

Karar 1: Ambient Mode mü Sidecar mı?

Istio 1.18’den itibaren ambient mode (sidecar’sız) genel kullanıma açık. 2026 itibarıyla 1.24 sürümü ile production-ready sayılıyor. Karar matriksi:

Sidecar mode Ambient mode
Her pod’a Envoy injection Node-level ztunnel + waypoint proxies
Pod resource overhead: ~50 MB RAM, ~50 mCPU/pod Per-node overhead: ztunnel + opsiyonel waypoint pod
Tüm L7 özellikleri her pod’da L4 sadece ztunnel; L7 için waypoint proxy gerekli
Olgun, tooling iyi, debugging iyi Daha yeni, debugging deneyimi gelişmekte

İzmir’de 47 servis × ortalama 4 replica = 188 pod. Sidecar moduna geçsek ~9.4 GB RAM + ~9.4 vCPU sadece sidecar overhead’ı için. Cluster %18 daha büyük node grubu istemek gerekiyordu. Ambient mode’a gittik. L7 policy lazım olan 6 servis için waypoint proxy ekledik. Kaynak overhead’ı ~%4’e indi. Tek dezavantaj: bazı 3rd party operator’lar (Kiali eski versiyon, eski Jaeger setup’ı) ambient ile sorunlu çalıştı, hepsini upgrade etmek gerekti.

Eğer projenin başındaysan ve 1.24+ kullanıyorsan ambient mode’a git. Eski bir Istio sidecar setup’ı varsa, geçişin değer karşılığını hesaplamadan migration başlatma; sidecar zaten çalışıyorsa “değiştirmek için değiştirme” tuzağı var.

Karar 2: mTLS Strict’e Geçiş Akışı

Mesh’i kurarken default mTLS modu PERMISSIVE’dir; mTLS yapan da mTLS yapmayan da kabul edilir. Hedef tabii ki STRICT olmak ama doğrudan geçersen mesh dışındaki bir bağımlılık (eski legacy, partner servis) düşer. Sahada uyguladığım kademe:

  1. Hafta 1-2: PERMISSIVE moda kurulum. Tüm uygulamalar çalışıyor mu doğrula.
  2. Hafta 3: Telemetry ile “kim plain text trafik gönderiyor” raporu. Kiali veya Grafana’da plain text bağlantı sayaçlarını göster.
  3. Hafta 4-6: Plain text üretenleri tek tek mesh’e dahil et veya ServiceEntry ile policy yaz.
  4. Hafta 7: Namespace bazlı PeerAuthentication STRICT ekle (önce dev/test, sonra prod).
  5. Hafta 8: Mesh-wide STRICT (root namespace istio-system’de PeerAuthentication).
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: default
  namespace: istio-system
spec:
  mtls:
    mode: STRICT

İzmir’de bu akışta tek “downtime” yaşadığımız nokta: bir RabbitMQ client kütüphanesi (eski Spring Cloud Stream binder) AMQP üzerinden plain text gidiyordu, mesh STRICT olunca düştü. ServiceEntry + DestinationRule ile mTLS DISABLE ettik o özel hostname için.

Karar 3: IngressGateway mı Gateway API mı?

Istio 1.20+ ile Kubernetes Gateway API standart hale geliyor; Istio’nun klasik Gateway + VirtualService CRD’lerinin yerine sektör genel Gateway + HTTPRoute kullanılıyor. Yeni proje için doğrudan Gateway API’a git. Eski VirtualService kalabalığı varsa migration için istioctl experimental komutları yardımcı oluyor ama büyük efor. İzmir projesinde 23 VirtualService vardı, hepsini HTTPRoute’a çevirdik, takım bir gün boyunca hata ayıkladı (path matching semantiği biraz farklı).

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cart-service
  namespace: shop
spec:
  parentRefs:
    - name: shop-gateway
      namespace: ingress
  hostnames: ["shop.example.com"]
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/cart
      backendRefs:
        - name: cart-service
          port: 80
          weight: 95
        - name: cart-service-v2
          port: 80
          weight: 5

Karar 4: Retry Budget’ı Default Bırakma

Istio default retry policy yok; ama VirtualService’te retry yazarsan Envoy aggressive retry yapar ve retry storm oluşturursun. Sahada kuralımız: retry sadece idempotent operasyonlar için (GET, PUT idempotent ise), per-try timeout düşük (~250 ms), max retry 2, retry backoff exponential. POST’lara retry ekleme (sipariş ikiye katlanır). Circuit breaker (DestinationRule outlierDetection) ile beraber kur.

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: payment-service
spec:
  host: payment-service
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100
      http:
        http1MaxPendingRequests: 50
        http2MaxRequests: 100
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 60s
      maxEjectionPercent: 50

Karar 5: Telemetry — Default Tracing’i Kapat

Istio default %1 sampling ile tracing yapar ama 47 servisli bir mesh’te bu bile Jaeger/Tempo backend’ini boğar. Sahada uyguladığım kalıp:

  • Tracing sampling %0.1 (binde bir) tüm servisler için.
  • Critical path servislerinde (ödeme, sipariş, login) %100 sampling, ama header bazlı.
  • Metrics Prometheus’a gidiyor; Telemetry CRD ile servise göre özel label ekleme.
  • Access log’lar sadece error+ seviyesinde JSON formatında.

İzmir’de Tempo backend ilk hafta CPU’ya boğuldu, sampling’i %1’den %0.1’e düşürdük + critical path’lerde header tabanlı (“baggage” header geçen request’ler %100 izlenir) çözüm getirdik.

Karar 6: Sidecar Resource Limits — Default Çok Düşük

Default sidecar 100 mCPU/128 MB ile gelir. High-throughput bir API gateway pod’unda bu yetmez, sidecar throttle olur, gecikme artar. Sahada kuralım:

# IstioOperator config
spec:
  components:
    pilot:
      k8s:
        resources:
          requests:
            cpu: 500m
            memory: 2Gi
  values:
    global:
      proxy:
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 2000m
            memory: 1Gi

Limits’i request’in 5-10 katı yap, request’i düşük tut. Burst trafik için yer kalsın.

Karar 7: Authorization Policy — Default Deny

Mesh’i kurar kurmaz default ALLOW kalır. Sahada kuralımız: namespace’e namespace-wide DENY policy ekle, sonra her servis için spesifik ALLOW yaz. “Zero trust” diye de pazarlanan yaklaşım.

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: default-deny
  namespace: shop
spec:
  {}  # boş spec = deny all
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: cart-allow-from-frontend
  namespace: shop
spec:
  selector:
    matchLabels:
      app: cart-service
  rules:
    - from:
        - source:
            principals: ["cluster.local/ns/shop/sa/frontend"]
      to:
        - operation:
            methods: ["GET", "POST"]
            paths: ["/api/cart/*"]

İzmir’de bu adımı haftalara yaydık; her servis sahibiyle “kim çağırıyor” konuştuk. Süreç sırasında 3 servis “şu other servisten gelen çağrı varmış, kimse bilmiyormuş” diye keşfedildi. Hayalet bağımlılık ortaya çıktı, audit değer üretti.

Karar 8: Canary Deployment Pattern

Istio’nun en pazarlanan kullanımı canary deployment. Pratikte uygulamak için tek başına Istio yetmez; Argo Rollouts veya Flagger ile entegre edersen otomatik trafik shift yapar.

# Flagger Canary kaynağı
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: cart-service
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: cart-service
  service:
    port: 80
    gateways: ["shop-gateway"]
    hosts: ["shop.example.com"]
  analysis:
    interval: 1m
    threshold: 5
    maxWeight: 50
    stepWeight: 10
    metrics:
      - name: request-success-rate
        thresholdRange:
          min: 99
        interval: 1m
      - name: request-duration
        thresholdRange:
          max: 500
        interval: 30s

Bu setup ile yeni versiyon trafik almaya %10’dan başlar, her dakika başarı oranı + p99 gecikme metriklerine bakar, başarılıysa %50’ye çıkar, sorun olursa otomatik rollback yapar. İzmir’de yılda ortalama 3 rollback yaşandı; hepsi Flagger tarafından otomatik tetiklendi, manuel müdahale gerekmedi.

Karar 9: Kiali Yerine Cilium Hubble veya OpenTelemetry

Kiali bir zamanlar service mesh observability’nin standardıydı. 2026’da rakipleri çok daha güçlü:

  • Eğer cluster’da Cilium CNI kullanıyorsan, Hubble UI ile zaten L7 trafik görüntüleme var, ek bir şey kurmana gerek yok.
  • OpenTelemetry collector + Tempo + Grafana stack’i Kiali’nin sunduklarının %90’ını veriyor ve daha esnek.
  • Kiali hâlâ “topology view” için iyi ama production debugging’de Grafana dashboards + Tempo trace UI daha kullanışlı.

İzmir projesinde Kiali’yi 2 ay kullandıktan sonra OpenTelemetry stack’ine geçtik, ekibin debugging süresi yarıya indi.

Sonuç: Mesh Bedava Değil ama Doğru Kurulduğunda Karşılığı Var

Üç ay sonunda elde ettiklerimiz: Tüm servisler arası mTLS, audit’te “kim kime ne zaman bağlandı” raporu, otomatik canary deployment, hayalet bağımlılıkların ortaya çıkması, ortalama incident MTTR’nin 47 dakikadan 18 dakikaya düşmesi. Karşılığında ödediğimiz: takım eğitimi (30 gün), 4 mühendis-ay implementasyon, ~%4 ek cluster maliyeti.

Service mesh’i hype olarak değil, “neyi çözüyor” sorusuyla aç. Çözdüğü problemler küçükse mesh ekleme, kompleksite ekliyorsun. 30+ servisli, multi-team, compliance gereksinimi olan ortamlarda Istio (özellikle ambient mode ile) eskisinden çok daha pragmatik bir seçim. İzmir’deki ekip mesh’i koyduktan sonra geri çıkarmayı düşünmedi; yeni servis ekledikçe değer arttı.

CloudSpark Cloud üzerinde Kubernetes (CSPK) kullanıyorsan, ambient mode Istio kurulumu CNCF guide’larına uyumlu çalışıyor; cluster overhead’ı planlarken yukarıdaki sayıları başlangıç noktası olarak alabilirsin.

🇹🇷 Türkçe🇬🇧 English🇩🇪 Deutsch🇫🇷 Français🇸🇦 العربية🇷🇺 Русский🇪🇸 Español