İ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:
- Hafta 1-2: PERMISSIVE moda kurulum. Tüm uygulamalar çalışıyor mu doğrula.
- Hafta 3: Telemetry ile “kim plain text trafik gönderiyor” raporu. Kiali veya Grafana’da plain text bağlantı sayaçlarını göster.
- Hafta 4-6: Plain text üretenleri tek tek mesh’e dahil et veya ServiceEntry ile policy yaz.
- Hafta 7: Namespace bazlı PeerAuthentication STRICT ekle (önce dev/test, sonra prod).
- 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.



