← blog · 12 Eylül 2026

Service Mesh Ne Zaman Gerekir, Ne Zaman Sadece Karmaşıklık Katar

Istio, Linkerd ve Cilium arasındaki farkı, mesh'i haklı çıkaran gerçek ihtiyaçları ve kurulumdan sonra karşılaşılan somut tuzakları anlatan bir karar rehberi.

Sorun nereden çıkıyor

Bir sistemde servis sayısı arttıkça her serviste aynı şeyler tekrar yazılır: karşı taraf çağrılırken kaç kez yeniden deneneceği, zaman aşımı süresi, devre kesici (circuit breaker) eşiği, karşılıklı TLS (mTLS) doğrulaması, hangi isteğin hangi servise gittiğinin izlenmesi. Bunu her ekip kendi HTTP istemcisinde elle yazarsa dil ve kütüphane başına farklı davranış ortaya çıkar. Ortak bir kütüphaneye taşınırsa bu sefer o kütüphanenin sürüm yükseltmesini bütün servislerin aynı anda yapması gerekir, ki bu da büyük bir organizasyonda gerçekçi değildir.

Service mesh bu sorumluluğu uygulama kodundan çıkarıp ağ katmanına taşır. Her pod'un yanına bir proxy (sidecar) konur, servisler birbirine değil kendi yanındaki proxy'ye konuşur, proxy'ler arası trafik kontrol düzlemi (control plane) tarafından yönetilen kurallara göre akar. Uygulama kodu retry, timeout ya da TLS ile hiç ilgilenmez; bunlar mesh'in konfigürasyonuna yazılır.

Bunun bir bedeli var: ekstra bir ağ atlaması, ekstra CPU ve bellek, ve öğrenilmesi gereken yeni bir kontrol düzlemi. Mesh'i doğru yerde kullanmak, bu bedeli neyin karşıladığını net görmekten geçiyor.

Üç farklı yaklaşım

Istio, Envoy tabanlı sidecar proxy kullanır ve şu an en geniş özellik setine sahip mesh'tir: ağırlıklı trafik dağıtımı, hata enjeksiyonu, zengin metrik toplama, ince taneli yetkilendirme kuralları. Bedeli, en yüksek operasyonel karmaşıklık ve en yüksek kaynak tüketimidir; her pod'a bir Envoy sidecar'ı eklenir ve bu sidecar'ların kendi bellek limitleri, kendi güncelleme döngüsü vardır.

Linkerd, kendi yazdığı daha hafif bir proxy (Rust ile yazılmış linkerd2-proxy) kullanır. Özellik seti Istio'dan dardır ama kurulumu ve zihin modeli çok daha basittir; çoğu ekip için mTLS, temel retry/timeout ve altın sinyaller (latency, hata oranı, istek hacmi) zaten yeterlidir.

Cilium, eBPF tabanlı olduğu için mesh işlevinin bir kısmını (mTLS, L3/L4 politika, gözlemlenebilirlik) sidecar olmadan, çekirdek seviyesinde yapabiliyor. Sidecar'sız yaklaşım pod başına ekstra proxy container'ı yükünü ortadan kaldırır, ama L7 trafik yönlendirme ve ince taneli yönlendirme kuralları konusunda henüz Istio kadar olgun değil.

Ne zaman gerçekten gerekir

Mesh'i haklı çıkaran şey servis sayısı değil, aşağıdaki ihtiyaçlardan en az birinin gerçek olmasıdır:

Birden fazla ekip aynı kümede çalışıyor ve her biri kendi servisi için trafik politikası (retry, timeout, circuit breaker) tanımlamak istiyor ama merkezi bir platform ekibinin her değişiklikte devreye girmesini istemiyor. Mesh, bu politikayı uygulama koduna değil Kubernetes kaynaklarına (CRD) yazdırdığı için özerkliği mümkün kılar.

Zorunlu ve otomatik mTLS gerekiyor: sertifika üretimi, rotasyonu ve doğrulaması elle ya da uygulama kodunda değil, altyapı tarafından, tüm servisler arasında tutarlı şekilde yapılmalı. Uyumluluk gereksinimi olan ortamlarda bu genelde en güçlü gerekçedir.

Kademeli yayın (canary) ya da A/B trafik ayrımı L7 seviyesinde, yani HTTP başlığına veya kullanıcı kimliğine göre yapılmalı, sadece ağırlıklı yönlendirme değil.

Servis başına altın sinyalleri (gecikme, hata oranı, istek hacmi) uygulama kodunu değiştirmeden, otomatik olarak toplamak gerekiyor.

Ne zaman gerekmiyor

On, on beş servisten küçük, tek ekibin sahip olduğu bir sistemde mesh genelde zarar verir. mTLS gerekiyorsa cert-manager ile sertifika üretip uygulamanın kendi TLS terminasyonunu yapması, ya da servis ağı basitse ingress seviyesinde TLS sonlandırma yeterlidir. Kademeli yayın ihtiyacı sadece ağırlıklı trafik bölmekse, tam bir mesh kurmadan Gateway API'nin HTTPRoute kaynağındaki backendRefs ağırlıklarıyla bu zaten çözülür; iki sürüme farklı ağırlık verip kademeli geçiş yapmak mesh'siz de mümkündür. Retry ve timeout ihtiyacı çoğu modern HTTP istemci kütüphanesinde zaten var; sorun sadece bunu her ekibin tutarlı yapması ise, ortak bir konfigürasyon şablonu mesh'ten daha ucuza aynı işi görür.

Kısaca: mesh bir "ölçek" çözümü değil, bir "özerklik ve otomasyon" çözümüdür. Küçük ve tek ekipli sistemlerde bu otomasyonun getirdiği fayda, işletim maliyetini karşılamaz.

Basit bir trafik bölme örneği

Istio ile iki sürüm arasında ağırlıklı trafik bölme, DestinationRule ile alt kümeleri tanımlayıp VirtualService ile ağırlığı vermekle yapılır:

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: odeme-servisi
spec:
  host: odeme-servisi
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: odeme-servisi
spec:
  hosts:
    - odeme-servisi
  http:
    - route:
        - destination:
            host: odeme-servisi
            subset: v1
          weight: 90
        - destination:
            host: odeme-servisi
            subset: v2
          weight: 10

Bu örnekte trafiğin yüzde onu yeni sürüme gider; hata oranı ve gecikme metrikleri izlenip sorun çıkmazsa ağırlık kademeli olarak artırılır.

Tuzaklar

Sidecar başlama sırası. Sidecar proxy, uygulama container'ı ile aynı anda başlar; ama proxy henüz hazır olmadan uygulama ilk isteğini yaparsa bağlantı reddedilir. Kubernetes'in yerel (native) sidecar container desteği bu sırayı büyük ölçüde düzeltti, ama eski sürümlerdeki kümelerde ya da bu desteği kullanmayan kurulumlarda pod başlangıcında ara sıra görülen "connection refused" hataları genelde bu yarış durumundandır.

mTLS'i sıkı moda (STRICT) tek seferde açmak. Mesh dışındaki bir iş yükü (örneğin kubelet'in düz HTTP ile yaptığı health check ya da mesh'e dahil edilmemiş eski bir servis) mTLS zorunlu hale geldiğinde aniden bağlantı kuramaz olur. Bu geçişi PERMISSIVE modda başlatıp, hangi servisin hâlâ düz TLS/HTTP kullandığını gözlemleyip, temizlendikten sonra STRICT'e geçmek gerekir.

Sidecar'ın kaynak maliyetini pod başına hesaba katmamak. Yüzlerce pod'luk bir kümede her pod'a eklenen proxy container'ı toplamda ciddi bir CPU/bellek talebi oluşturur; kapasite planlaması yapılırken bu genelde unutulur ve mesh kurulduktan sonra küme kaynak kullanımı beklenmedik şekilde artar.

Kademeli yayında oturum tutarlılığı. Ağırlıklı yönlendirme her isteği bağımsız olarak dağıtır; bir kullanıcının art arda gelen istekleri farklı sürümlere düşebilir. Bu, önbelleğe alınmış bir oturum ya da özellik bayrağı durumuyla çakışırsa tutarsız davranışa yol açar. Çözüm, DestinationRule içinde bir çerez veya başlığa göre tutarlı hash (consistent hash) tabanlı yönlendirme tanımlamaktır, ki aynı kullanıcı isteğin ömrü boyunca aynı sürümde kalsın.

Kontrol düzlemi ile veri düzlemi sürüm uyumsuzluğu. Küme Kubernetes sürümünü yükseltirken mesh'in kendi sürümünü aynı anda düşünmemek, desteklenmeyen bir API sürümüyle karşılaşıp trafik yönetiminin sessizce bozulmasına yol açabilir. Mesh'in desteklediği Kubernetes sürüm aralığı her yükseltmeden önce kontrol edilmelidir.

Sonuç

Mesh'e "büyüdüğümüz için" değil, somut bir otomasyon veya uyumluluk ihtiyacı için geçin. İhtiyaç sadece kademeli yayınsa Gateway API'nin ağırlıklı yönlendirmesi genelde yeterlidir. İhtiyaç gerçekten otomatik, tutarlı mTLS ve ekipler arası özerklikse, önce Linkerd'in daha basit modeliyle başlamak, Istio'nun tam özellik setine yalnızca zengin L7 trafik yönetimi ya da hata enjeksiyonu gibi somut bir ihtiyaç çıktığında geçmek çoğu kurulum için daha az riskli bir yoldur.