Kapsamlı Envoy Proxy Rehberi — Özellikler, Best Practice'ler ve Pattern'ler
Envoy Proxy ile sistem kurmak, işletmek ve ölçeklendirmek için derinlemesine, pratisyen seviyesinde bir referans — mimari, xDS, trafik yönetimi, gözlemlenebilirlik, güvenlik ve üretimde kanıtlanmış pattern’leri kapsar.
İçindekiler
- Envoy Nedir ve Neden Önemlidir
- Temel Mimari
- Konfigürasyon Modeli: Statik vs Dinamik
- xDS API’leri Açıklaması
- Listener’lar ve Filter Chain’leri
- Cluster’lar, Endpoint’ler ve Servis Keşfi
- Routing (Yönlendirme)
- Load Balancing (Yük Dengeleme)
- Dayanıklılık: Retry, Timeout, Circuit Breaking, Outlier Detection
- Rate Limiting (Hız Sınırlama)
- TLS, mTLS ve Güvenlik
- Kimlik Doğrulama ve Yetkilendirme (RBAC, ExtAuthz, JWT)
- Gözlemlenebilirlik: Stats, Access Log, Tracing
- HTTP Filter’lar ve Genişletilebilirlik (Wasm, Lua, ext_proc)
- Deployment Pattern’leri
- Service Mesh Pattern’leri (Istio, Gateway API)
- Performans Ayarlama (Tuning)
- Operasyonel Best Practice’ler
- Yaygın Tuzaklar ve Anti-Pattern’ler
- Hızlı Referans Cheat Sheet
1. Envoy Nedir ve Neden Önemlidir
Envoy, C++ ile yazılmış, yüksek performanslı bir L3/L4/L7 proxy’dir. Aslen Lyft’te geliştirilmiş olup şu anda mezun olmuş bir CNCF projesidir. Envoy, mevcut bir yığına eklenen sıradan bir yük dengeleyici olarak değil, modern, cloud-native, çok dilli (polyglot) servis mimarileri için ağın kendisi olacak şekilde sıfırdan tasarlanmıştır.
Envoy’u farklı kılan temel özellikler:
- Process-dışı (out-of-process) mimari — Envoy, uygulama diliğinden/runtime’ından bağımsız olarak sidecar veya bağımsız (standalone) bir proxy olarak çalışır. Herhangi bir servis (Java, Go, Python, Node) aynı ağ davranışını elde eder.
- API odaklı dinamik konfigürasyon — xDS protokolü sayesinde Envoy, sıfır kesinti (zero downtime) ile çalışma zamanında yeniden yapılandırılabilir (reload yok, bağlantı kopması yok).
- Ham TCP/UDP proxy’leme için L3/L4 filter mimarisi, protokol farkındalıklı davranış için ise zengin bir L7 HTTP filter zinciri (HTTP/1.1, HTTP/2, HTTP/3-QUIC, gRPC, Thrift, Dubbo, Redis, MongoDB, Kafka, vb.).
- Birinci sınıf gözlemlenebilirlik — detaylı istatistikler (counter, gauge, histogram), yapılandırılmış access log’lar ve dağıtık tracing, sonradan eklenmiş değil, doğrudan içine gömülü.
- Hot restart — Envoy, aktif bağlantıları kesmeden binary/config’ini yeniden yükleyebilir.
- Genişletilebilirlik — native C++ filter’lar, Lua scripting, WebAssembly (Wasm) filter’ları ve gRPC üzerinden external processing (ext_proc).
Envoy’un pratikte kullanıldığı yerler:
- Service mesh’lerde sidecar proxy olarak (Istio, Consul Connect, AWS App Mesh, veri düzlemi/data plane olarak Envoy kullanır).
- Edge/ingress proxy olarak — API gateway’ler, ingress controller’lar (Envoy Gateway, Contour, Gloo Edge, Emissary-ingress).
- Birçok yerde HAProxy/Nginx’in yerine geçen bağımsız L4/L7 yük dengeleyici olarak.
- API Gateway API implementasyonlarının içinde (Kubernetes Gateway API’nin birden fazla Envoy tabanlı implementasyonu vardır).
2. Temel Mimari
Config’e dokunmadan önce yapabileceğiniz en yüksek getirili şey, Envoy’un terminolojisini anlamaktır.
┌─────────────────────────────────────────┐
│ Envoy │
│ │
Downstream ─────▶ │ Listener → Filter Chain → HTTP Filters │ ─────▶ Upstream
(istemci) │ │ │ (Cluster)
│ Router Filter │
│ │ │
│ Route Config │
│ │ │
│ Cluster Manager │
└─────────────────────────────────────────┘
Temel yapı taşları:
| Terim | Anlamı |
|---|---|
| Downstream | Envoy’a bağlanan bir host (istemci veya bu Envoy’u çağıran upstream servis). |
| Upstream | Envoy’un bağlandığı bir host (Envoy’un proxy’lediği backend servis). |
| Listener | Envoy’un bağlanıp (bind) dinlediği isimlendirilmiş bir ağ konumu (IP:port veya Unix domain socket). |
| Filter Chain | Bir listener üzerindeki bağlantılara/isteklere uygulanan sıralı network (L3/L4) ve HTTP (L7) filter’lar kümesi. |
| Cluster | Envoy’un yük dengelemesi yaptığı upstream host’ların (endpoint’lerin) mantıksal grubu — bir Kubernetes Service’e veya Nginx’teki upstream bloğuna benzer. |
| Endpoint | Bir cluster içindeki tek bir upstream host/instance. |
| Route | Gelen istek özelliklerini (path, header, host) bir hedef cluster’a eşler. |
| Runtime | Envoy’un çalışma zamanında okuyabildiği (RTDS aracılığıyla) dinamik özellik-bayrağı/yüzde tabanlı config değerleri. |
Envoy temelde olay güdümlü (event-driven) ve non-blocking çalışır; sabit boyutlu bir worker thread havuzu (--concurrency) çalıştırır, her biri kendi event loop’unu yürütür ve bağlantıları bağımsız olarak kabul edip tamamen işleyebilir. Konfigürasyon işleme, stats flushing ve admin için ayrı bir main thread vardır.
3. Konfigürasyon Modeli: Statik vs Dinamik
Envoy konfigürasyonu temelde protobuf tabanlıdır, genellikle YAML veya JSON olarak yazılır.
Statik konfigürasyon
Her şey doğrudan bootstrap config dosyasında tanımlanır. Basittir; öğrenmek için, küçük/tek amaçlı proxy’ler için veya config’in gerçekten hiç değişmediği durumlar için uygundur.
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 10000 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: backend_service }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: backend_service
connect_timeout: 5s
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: backend_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: backend.internal, port_value: 8080 }
Dinamik konfigürasyon (xDS)
Üretimdeki Envoy deployment’ları neredeyse her zaman dinamik konfigürasyon kullanır; burada bir control plane (Istio Pilot, go-control-plane tabanlı sunucular, Contour, vb.) config’i gRPC stream’leri üzerinden Envoy’a gönderir (push eder). Sıfır kesintili, filo genelinde (fleet-wide) güncellemeleri mümkün kılan şey budur.
dynamic_resources:
lds_config:
resource_api_version: V3
ads: {}
cds_config:
resource_api_version: V3
ads: {}
ads_config:
api_type: GRPC
transport_api_version: V3
grpc_services:
- envoy_grpc: { cluster_name: xds_cluster }
Best practice: Dinamik kurulumlarda bile, bootstrap config’i (Envoy’un control plane’ini nasıl bulacağını tanımlayan kısım) statiktir — elle/config-management ile yönettiğiniz tek parça budur, geri kalan her şey xDS’ten akar.
4. xDS API’leri Açıklaması
xDS = “discovery service” (keşif servisi) ailesi. Her harf bir kaynak türüne karşılık gelir:
| API | Tam Adı | Neyi Keşfeder |
|---|---|---|
| LDS | Listener Discovery Service | Listener’lar |
| RDS | Route Discovery Service | Route konfigürasyonları |
| CDS | Cluster Discovery Service | Cluster’lar |
| EDS | Endpoint Discovery Service | Cluster üyeliği (endpoint’ler/IP’ler) |
| SDS | Secret Discovery Service | TLS sertifikaları/anahtarları, çalışma zamanında güvenli şekilde teslim edilir |
| VHDS | Virtual Host Discovery Service | Tek tek virtual host’lar (ince taneli RDS) |
| RTDS | Runtime Discovery Service | Çalışma zamanı özellik bayrakları |
| ECDS | Extension Config Discovery Service | Filter/extension konfigürasyonu |
ADS (Aggregated Discovery Service), yukarıdakilerin tümünü tek bir gRPC stream üzerinden multiplekslerçalıştırır — ayrı LDS/RDS/CDS/EDS stream’leri arasında güncelleme sırası (ordering) yarışlarından kaçınmak için üretimde şiddetle önerilir.
Güncelleme sırası önemlidir
Envoy’un control plane implementasyonları, trafiğin karadeliğe düşmesini (blackhole) önlemek için belirli bir güncelleme sırasına uymalıdır:
CDS (cluster'lar) → EDS (o cluster'lar için endpoint'ler) → LDS (listener'lar) → RDS (cluster'lara referans veren route'lar)
Henüz var olmayan bir cluster’a yeni bir route eklemek = isteklerin başarısız olması demektir. İyi control plane’ler (Istio, go-control-plane’in SnapshotCache‘i) bu sırayı sizin için yönetir, ancak rollout sırasında blackhole’ları debug ederken bunu anlamak esastır.
State-of-the-World vs Incremental (Delta) xDS
- SotW (State of the World): her güncelleme, bir türün tüm kaynak listesini gönderir. Basittir ama ölçekte pahalıdır (her küçük değişiklikte binlerce cluster’ın yeniden gönderilmesi).
- Delta xDS: yalnızca farkı (eklenen/güncellenen/kaldırılan kaynakları) gönderir. Çok büyük filolar için gereklidir (Istio, 1.12+ sürümünden beri Delta xDS’i varsayılan olarak kullanır).
Best practice: Birkaç yüzden fazla cluster/route olan herhangi bir ortamda, control-plane ve data-plane kaynak kullanımını kontrol altında tutmak için ADS + Delta xDS kullanın.
5. Listener’lar ve Filter Chain’leri
Bir Listener, bir adrese bağlanır ve kabul edilen her bağlantıya bir filter chain uygular.
Filter chain eşleştirme (matching)
Tek bir listener’ın birden fazla filter chain’i olabilir; bunlar gelen bağlantının özelliklerine göre seçilir — SNI, hedef port, kaynak IP aralığı, ALPN, transport protokolü (örn. tls_inspector ile TLS’in tespit edilmesi).
listeners:
- name: multiplexed_listener
address:
socket_address: { address: 0.0.0.0, port_value: 443 }
listener_filters:
- name: envoy.filters.listener.tls_inspector
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains:
- filter_chain_match:
server_names: ["api.example.com"]
filters: [ ... api için http_connection_manager ... ]
- filter_chain_match:
server_names: ["admin.example.com"]
filters: [ ... admin için http_connection_manager ... ]
Bu, L4 seviyesinde SNI tabanlı yönlendirmenin arkasındaki mekanizmadır — Envoy, hostname’e göre farklı backend’lere yönlendirmek için TLS’i sonlandırmak (terminate) zorunda bile değildir (bkz. TLS passthrough pattern’leri).
Network filter’lar vs HTTP filter’lar
- Network filter’lar ham bağlantı byte’ları üzerinde (L3/L4) çalışır:
tcp_proxy,http_connection_manager(L4→L7 köprüsü),redis_proxy,mongo_proxy, RBAC (network seviyesi), rate limiting (network seviyesi). - HTTP filter’lar, byte’lar HTTP isteklerine/yanıtlarına ayrıştırıldıktan sonra
http_connection_manageriçinde çalışır:router,cors,jwt_authn,ext_authz,rate_limit,fault,lua,wasm,grpc_web,health_check,compressor, vb.
Sıra önemlidir. HTTP filter’lar istek yolunda listelenme sırasına göre, yanıt yolunda ise ters sırada çalışır. Gerçekte upstream’e yönlendirmeyi yapan router filter’ı her zaman en sonda olmalıdır.
http_filters:
- name: envoy.filters.http.jwt_authn # 1. önce kimlik doğrula
- name: envoy.filters.http.rbac # 2. sonra yetkilendir
- name: envoy.filters.http.ext_authz # 3. opsiyonel harici auth kontrolü
- name: envoy.filters.http.fault # 4. fault injection (test amaçlı)
- name: envoy.filters.http.cors # 5. CORS işleme
- name: envoy.filters.http.router # 6. HER ZAMAN SONDA — gerçek proxy'lemeyi yapar
6. Cluster’lar, Endpoint’ler ve Servis Keşfi
Bir Cluster, Envoy’un “yük dengelemesi yapabileceğim isimlendirilmiş backend grubu” soyutlamasıdır. Envoy birden fazla keşif türünü (discovery type) destekler:
| Tür | Açıklama | Kullanım Senaryosu |
|---|---|---|
STATIC | Config’te sabit IP listesi | Test, gerçekten statik altyapı |
STRICT_DNS | DNS’i çözer, TTL’de yeniler, dönen tüm IP’leri takip eder | Geleneksel DNS tabanlı servis keşfi |
LOGICAL_DNS | DNS’i çözer ama yalnızca ilk dönen IP’yi kullanır; her yeni bağlantıda tekrar çözer | Büyük/rotasyonlu DNS havuzları (örn. cloud LB’ler) |
EDS | Control plane tarafından Endpoint Discovery Service ile push edilen dinamik | Kubernetes, service mesh — üretim varsayılanı |
ORIGINAL_DST | Bağlantının orijinal hedefine (NAT/redirect öncesi) yönlendirir | Şeffaf proxy’leme, sidecar interception |
clusters:
- name: payments_service
connect_timeout: 2s
type: EDS
eds_cluster_config:
eds_config: { ads: {} }
lb_policy: ROUND_ROBIN
health_checks:
- timeout: 1s
interval: 5s
unhealthy_threshold: 3
healthy_threshold: 2
http_health_check:
path: /healthz
circuit_breakers:
thresholds:
- priority: DEFAULT
max_connections: 1000
max_pending_requests: 1000
max_requests: 1000
max_retries: 3
Best practice: Kubernetes’te DNS tabanlı keşif yerine (gerçek bir control plane tarafından beslenen) EDS‘yi tercih edin — DNS tabanlı keşifte cache/TTL gecikme sorunları vardır ve endpoint başına sağlık sinyalleri veya ağırlıklı (weighted) yönlendirme gibi özellikleri bu kadar temiz vermez.
Health check: aktif vs pasif
- Aktif health check’ler — Envoy, belirli bir aralıkla endpoint’leri proaktif olarak yoklar (
http_health_check,tcp_health_check,grpc_health_check). - Pasif health check’ler (Outlier Detection) — Envoy gerçek trafiği izler ve ekstra probe trafiği olmadan hata/timeout döndüren host’ları dışarı atar. Bkz. Bölüm 9.
Best practice: İkisini birlikte çalıştırın. Aktif kontroller, trafik onlara ulaşmadan önce ölü host’ları yakalar; outlier detection ise aktif kontrollerin kaçırabileceği “gri hata"yı (host yanıt verir ama kötü yanıt verir) yakalar.
7. Routing (Yönlendirme)
Route konfigürasyonu, virtual host’lara (Host/:authority header’ı ile eşleşir) ve route match kurallarına (path, header, query param, gRPC method, vb.) göre istekleri cluster’lara eşler.
route_config:
name: main_routes
virtual_hosts:
- name: api
domains: ["api.example.com"]
routes:
- match:
prefix: "/v2/"
headers:
- name: "x-canary"
string_match: { exact: "true" }
route:
cluster: api_service_canary
- match: { prefix: "/v2/" }
route:
cluster: api_service_v2
timeout: 15s
retry_policy:
retry_on: "5xx,reset,connect-failure"
num_retries: 2
- match: { prefix: "/" }
route: { cluster: api_service_v1 }
Trafik bölme / ağırlıklı cluster’lar (weighted clusters)
Canary release’ler ve blue/green deploy’lar weighted_clusters ile yapılır:
route:
weighted_clusters:
clusters:
- name: api_service_v1
weight: 90
- name: api_service_v2
weight: 10
total_weight: 100
Header tabanlı yönlendirme pattern’leri
Yaygın üretim pattern’leri:
- Header ile canary (
x-canary: true) — dahili test ekiplerinin/QA’nın yeni sürümlere erişmesi için. - Cookie veya user-id hash ile A/B testing —
request_headers_to_add‘ı hash tabanlı yönlendirme ile birleştirerek. - Trafik aynalama (mirroring/shadowing) — istemciye verilen yanıtı etkilemeden trafiğin bir kopyasını yeni bir servise gönderme:
route:
cluster: api_service_v1
request_mirror_policies:
- cluster: api_service_v2_shadow
runtime_fraction:
default_value: { numerator: 10, denominator: HUNDRED }
Mirroring, yeni bir servis sürümünü gerçek yanıtlar vermeye başlamadan önce gerçek üretim yükü altında doğrulamanın en güvenli yoludur.
Redirect’ler, rewrite’lar ve doğrudan yanıtlar
- match: { prefix: "/old-path" }
redirect: { path_redirect: "/new-path", response_code: MOVED_PERMANENTLY }
- match: { prefix: "/health" }
direct_response: { status: 200, body: { inline_string: "OK" } }
- match: { prefix: "/api/" }
route:
cluster: backend
prefix_rewrite: "/"
8. Load Balancing (Yük Dengeleme)
Envoy cluster seviyesinde birden fazla LB politikasını destekler:
| Politika | Davranış | En Uygun Kullanım |
|---|---|---|
ROUND_ROBIN | Sağlıklı host’lar arasında sırayla döner | Basit, homojen backend’ler |
LEAST_REQUEST | En az aktif isteğe sahip host’u seçer (varsayılan olarak power-of-two-choices kullanır) | Değişken istek maliyeti/süresi — genellikle en iyi varsayılan |
RANDOM | Rastgele seçim | Yüksek throughput, stateless, basit |
RING_HASH | Bir halka (ring) üzerinde consistent hashing | Session affinity / cache dostu yönlendirme |
MAGLEV | Google’ın consistent hashing algoritması, ring hash’ten daha hızlı tablo oluşturma | Ölçekte consistent hashing gerektiren büyük cluster’lar |
CLUSTER_PROVIDED | Cluster seviyesinde uygulanan özel bir LB implementasyonuna devreder | Özel LB mantığı |
Best practice: LEAST_REQUEST, değişken gecikmeli HTTP servisleri için genellikle ROUND_ROBIN‘e tercih edilen varsayılan seçenektir; çünkü round robin, sırf sıra gereği zaten aşırı yüklenmiş bir host’a istek gönderebilir.
Locality-aware ve zone-aware load balancing
Envoy, çağıranla aynı zone/bölge içinde yönlendirmeyi tercih edebilir; yalnızca yerel zone’da kapasite yoksa diğer zone’lara düşer — cross-AZ veri transfer maliyetlerini ve gecikmeyi azaltmak için kritiktir.
cluster:
common_lb_config:
locality_weighted_lb_config: {}
zone_aware_lb_config:
routing_enabled: { value: 100 }
min_cluster_size: 6
Session affinity
Stateful backend’ler için, RING_HASH veya MAGLEV‘in bir hash policy’si (cookie, header veya kaynak IP) ile birleştirilmesi, istemci başına tutarlı yönlendirme sağlar:
route:
cluster: sticky_backend
hash_policy:
- cookie:
name: "session-id"
ttl: 3600s
9. Dayanıklılık: Retry, Timeout, Circuit Breaking, Outlier Detection
Envoy’un sadece bir router değil, bir dayanıklılık (resiliency) katmanı olarak ününü kazandığı yer burasıdır.
Timeout’lar
İki timeout kavramı önemlidir ve sık sık karıştırılır:
- Route/istek timeout’u (
timeout:) — retry’lar dahil, tüm istek/yanıt için izin verilen toplam süre. per_try_timeout— her bir tekil retry denemesi için izin verilen süre. Toplam timeout’a eşit veya küçük olmalıdır.
route:
cluster: backend
timeout: 10s
retry_policy:
retry_on: "5xx,reconnect,connect-failure,refused-stream"
num_retries: 3
per_try_timeout: 2s
retry_back_off:
base_interval: 0.1s
max_interval: 1s
Best practice: Her zaman açık (explicit) timeout’lar ayarlayın. Envoy’un varsayılan istek timeout’u 15 saniyedir; bu genellikle gecikmeye duyarlı API’ler için çok uzun, long-polling/streaming için ise çok kısadır — her route için ayrı ayarlayın.
Retry’lar — iki tarafı keskin bıçak
Retry’lar, geçici hatalar için kuyruk gecikmesini (tail latency) ve güvenilirliği iyileştirir, ancak yük altında naif retry’lar bir kesintiyi büyüten retry storm (retry fırtınası) yaratabilir.
Bunu şu şekillerde hafifletin:
retry_budget— retry’ları sabit bir sayı yerine aktif isteklerin bir yüzdesi olarak sınırlar, yük altında adaptiftir:
retry_policy:
retry_on: "5xx"
retry_back_off:
base_interval: 0.1s
retry_budget:
budget_percent: { value: 20 }
min_retry_concurrency: 3
- Yalnızca idempotent işlemleri retry edin (GET, idempotency key’li PUT) — güvenli olduğunu bilmiyorsanız asla körlemesine POST retry etmeyin.
- Retry’ları circuit breaker’larla birleştirin, böylece retry’lar zaten hata veren bir cluster’ı dövmeyi durdurur.
Circuit Breaking
Klasik “N hata sonrası tripleyen” circuit breaker’lardan (örn. Hystrix) farklı olarak, Envoy’un circuit breaker’ları kaynak sınırı kapılarıdır (resource limit gate) — hem Envoy’u hem de upstream’i aşırı yüklenmeye karşı korumak için bir cluster’a eşzamanlı bağlantı/istek/retry sayısını sınırlar:
circuit_breakers:
thresholds:
- priority: DEFAULT
max_connections: 1024
max_pending_requests: 1024
max_requests: 1024
max_retries: 3
track_remaining: true
Bir eşik (threshold) aşıldığında, yeni istekler süresiz kuyruğa girmek yerine hızlı başarısız olur (fail fast) (503) — bu, kademeli hataya (cascading failure) karşı kritik bir korumadır.
Outlier Detection (pasif health checking)
Aktif bir health-check endpoint’ine ihtiyaç duymadan, gözlemlenen hata oranlarına dayanarak host’ları load balancing havuzundan dışarı atar:
outlier_detection:
consecutive_5xx: 5
interval: 10s
base_ejection_time: 30s
max_ejection_percent: 50
split_external_local_origin_errors: true
Best practice kombinasyonu: timeout’lar + retry budget’lı sınırlı retry’lar + circuit breaker’lar + outlier detection birlikte Envoy’un dayanıklılık yığınını (resilience stack) oluşturur — bunlardan sadece birini kullanmak boşluklar bırakır (örn. circuit breaker olmadan retry, kısmi bir kesintiyi tam bir kesintiye dönüştürebilir).
10. Rate Limiting (Hız Sınırlama)
Envoy hem local (Envoy instance başına, harici bağımlılık yok) hem de global (gRPC rate limit servisi üzerinden, filo genelinde paylaşılan state ile) rate limiting’i destekler.
Local rate limiting (token bucket, instance başına)
http_filters:
- name: envoy.filters.http.local_ratelimit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
stat_prefix: http_local_rate_limiter
token_bucket:
max_tokens: 100
tokens_per_fill: 100
fill_interval: 60s
filter_enabled:
runtime_key: local_rate_limit_enabled
default_value: { numerator: 100, denominator: HUNDRED }
filter_enforced:
runtime_key: local_rate_limit_enforced
default_value: { numerator: 100, denominator: HUNDRED }
response_headers_to_add:
- append_action: OVERWRITE_IF_EXISTS_OR_ADD
header: { key: "x-local-rate-limit", value: "true" }
Ucuz, hızlı, ağ hop’u yok — ancak her Envoy instance’ı kendi bucket’ını uyguladığından, etkili limitler replica sayısıyla ölçeklenir.
Global rate limiting (ext_ratelimit gRPC servisi ile)
http_filters:
- name: envoy.filters.http.ratelimit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
domain: "api_ratelimit"
rate_limit_service:
grpc_service:
envoy_grpc: { cluster_name: ratelimit_service }
transport_api_version: V3
Tüm filo genelinde state paylaşan bir rate-limit servisinin (örn. Redis destekli envoyproxy/ratelimit) deploy edilmesini gerektirir.
Best practice: Local rate limiting’i ucuz bir ilk savunma hattı olarak (instance başına DoS koruması), global rate limiting’i ise gerçek iş mantığı kotası uygulaması için kullanın (örn. “API anahtarı başına dakikada 100 istek”).
11. TLS, mTLS ve Güvenlik
TLS sonlandırma (downstream)
filter_chains:
- transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificate_sds_secret_configs:
- name: server_cert
sds_config: { ads: {} }
tls_params:
tls_minimum_protocol_version: TLSv1_2
Upstream’e TLS başlatma
clusters:
- name: secure_backend
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
sni: backend.internal
Servisler arası mTLS (mutual TLS)
İstemci sertifikalarını zorunlu kılmak güçlü servisten servise kimlik sağlar — zero-trust service mesh’lerin temelidir:
common_tls_context:
tls_certificate_sds_secret_configs: [...]
validation_context_sds_secret_config:
name: validation_context
sds_config: { ads: {} }
require_client_certificate: true
Best practice: TLS sertifikalarını her zaman statik config’te satır içi (inline) dosya yolları yerine SDS (Secret Discovery Service) ile teslim edin — SDS, restart olmadan rotasyona izin verir ve secret’ların düz metin config dosyalarında/git repolarında durmasını önler.
Yaygın TLS tuzakları
tls_minimum_protocol_version‘ı unutmak (varsayılanlar gevşek olabilir; TLS 1.2+‘ya sabitleyin).- Bir listener’ı birden fazla filter chain paylaştığında SNI uyuşmazlıkları — her zaman
openssl s_client -servernameile test edin. - SDS sertifikalarını süresi dolmadan önce rotasyona sokmamak —
cluster.<name>.ssl.*ve sertifika süre dolumu istatistiklerini izleyin.
12. Kimlik Doğrulama ve Yetkilendirme (RBAC, ExtAuthz, JWT)
JWT kimlik doğrulama
http_filters:
- name: envoy.filters.http.jwt_authn
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication
providers:
auth0:
issuer: "https://example.auth0.com/"
remote_jwks:
http_uri:
uri: "https://example.auth0.com/.well-known/jwks.json"
cluster: auth0_jwks
timeout: 5s
cache_duration: 300s
forward: true
rules:
- match: { prefix: "/api/" }
requires: { provider_name: "auth0" }
RBAC (rol tabanlı erişim kontrolü)
Principal’a (kaynak IP, mTLS kimliği, JWT claim’leri) ve izne (path, method, header) dayalı ince taneli allow/deny kuralları:
http_filters:
- name: envoy.filters.http.rbac
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC
rules:
action: ALLOW
policies:
"admin-access":
permissions:
- and_rules:
rules:
- url_path: { path: { prefix: "/admin" } }
principals:
- authenticated:
principal_name: { exact: "spiffe://cluster.local/ns/default/sa/admin" }
Harici yetkilendirme (ext_authz)
Allow/deny kararını harici bir gRPC veya HTTP servisine devreder — karmaşık politikalar için kullanışlıdır (OPA/Open Policy Agent çok yaygın bir eşleşmedir):
http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
grpc_service:
envoy_grpc: { cluster_name: opa_authz }
timeout: 0.25s
failure_mode_allow: false
Best practice: failure_mode_allow: false güvenli varsayılandır — authz servisine ulaşılamazsa, varsayılan olarak açık başarısız olmak (fail open) yerine reddedin (deny). Yalnızca açıkça kritik olmayan yollarda true olarak ayarlayın.
13. Gözlemlenebilirlik: Stats, Access Log, Tracing
Envoy kutudan çıktığı haliyle son derece gözlemlenebilirdir — bu, onu tanımlayan güçlü yönlerinden biridir.
Stats (İstatistikler)
Üç tür vardır: counter, gauge, histogram — /stats, /stats/prometheus üzerinden expose edilir veya StatsD/dogstatsd sink’leri aracılığıyla push edilir.
Üretimde alarm kurulması gereken kilit istatistikler:
cluster.<name>.upstream_rq_5xx/upstream_rq_timeout— upstream hatalarıcluster.<name>.upstream_cx_connect_fail— backend’lere bağlantı hatalarıcluster.<name>.circuit_breakers.default.rq_open— circuit breaker tetiklenmelericluster.<name>.outlier_detection.ejections_active— şu anda dışarı atılmış (eject) host’larlistener.<addr>.downstream_cx_overflow— listener backlog/aşırı yükserver.memory_allocated,server.concurrency— kaynak baskısı
stats_sinks:
- name: envoy.stat_sinks.metrics_service
typed_config:
"@type": type.googleapis.com/envoy.config.metrics.v3.MetricsServiceConfig
grpc_service:
envoy_grpc: { cluster_name: stats_sink }
Best practice: Yüksek cluster/route sayılarında hangi istatistiklerin gerçekten yayınlandığını filtrelemek için stats_matcher kullanın — sınırsız endpoint başına istatistikler, ölçekte gerçek bir bellek/kardinalite sorununa dönüşebilir.
Access logging
Listener/filter chain başına yapılandırılabilir, yapılandırılmış (structured) log:
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/dev/stdout"
log_format:
json_format:
start_time: "%START_TIME%"
method: "%REQ(:METHOD)%"
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
response_code: "%RESPONSE_CODE%"
upstream_cluster: "%UPSTREAM_CLUSTER%"
duration_ms: "%DURATION%"
upstream_host: "%UPSTREAM_HOST%"
response_flags: "%RESPONSE_FLAGS%"
%RESPONSE_FLAGS% altın değerindedir — bir isteğin neden başarısız olduğunu (UO = upstream overflow, UF = upstream bağlantı hatası, UT = upstream timeout, NR = route yok, RL = rate limit uygulandı, vb.) upstream log’larıyla korelasyon kurma ihtiyacı olmadan söyler.
Dağıtık tracing (distributed tracing)
Envoy, Zipkin, Jaeger, Datadog, OpenTelemetry ve AWS X-Ray’i native olarak destekler:
tracing:
provider:
name: envoy.tracers.opentelemetry
typed_config:
"@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig
grpc_service:
envoy_grpc: { cluster_name: otel_collector }
service_name: "checkout-service"
Envoy, trace header’larını (traceparent, x-b3-*) otomatik olarak yayar/oluşturur, ancak uygulamaların gelen trace header’larını kendi giden çağrılarında yaymaları gerekir — Envoy, uygulamanızın iş mantığı boyunca span’leri birbirine dikemez.
14. HTTP Filter’lar ve Genişletilebilirlik (Wasm, Lua, ext_proc)
Yerleşik filter’lar yeterli olmadığında, Envoy artan esneklik/karmaşıklık sırasına göre üç genişletme mekanizması sunar:
Lua filter (hızlı yazılır, process içinde)
http_filters:
- name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
default_source_code:
inline_string: |
function envoy_on_request(request_handle)
request_handle:headers():add("x-custom-header", "hello")
end
Hafif header manipülasyonu, basit özel mantık ve prototipleme için iyidir.
WebAssembly (Wasm) filter
Rust, C++, AssemblyScript, TinyGo ile filter’lar derleyin — sandbox’lanmış, Envoy sürümleri arasında taşınabilir, Envoy’un kendisini yeniden derlemeden hot-swap edilebilir.
http_filters:
- name: envoy.filters.http.wasm
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
config:
name: "my_filter"
vm_config:
runtime: "envoy.wasm.runtime.v8"
code:
local: { filename: "/etc/envoy/filters/my_filter.wasm" }
Best practice: Wasm, yeniden kullanılabilir, versiyonlanmış, organizasyon geneli filter’lar için doğru seçimdir (örn. 50 ekip arasında paylaşılan standart bir auth-header-injection filter’ı) — filter mantığını Envoy binary release döngüsünden ayırır.
External Processing (ext_proc)
İstek/yanıt verisini keyfi dönüşüm için process-dışı bir gRPC servisine akıtır — en güçlü ve en yüksek gecikmeli seçenektir, proxy’nin kendisinde bulunmaması gereken karmaşık iş mantığı için idealdir:
http_filters:
- name: envoy.filters.http.ext_proc
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor
grpc_service:
envoy_grpc: { cluster_name: ext_proc_service }
processing_mode:
request_header_mode: SEND
response_header_mode: SEND
Aralarında seçim yapma: Hızlı process-içi değişiklikler için Lua → ekipler arasında paylaşılan taşınabilir/yeniden kullanılabilir filter’lar için Wasm → data plane’in hot path’inde tutulmaması gereken ağır/karmaşık mantık için ext_proc (tam dil/kütüphane özgürlüğü karşılığında ağ hop’u gecikmesini kabul ederek).
15. Deployment Pattern’leri
1. Sidecar proxy (service mesh)
Her uygulama pod’u/instance’ı için bir Envoy instance’ı, tüm gelen/giden trafiği şeffaf şekilde yakalar (genellikle iptables yönlendirmesi ile ORIGINAL_DST cluster’ına). Bu, Istio/Consul Connect/App Mesh modelidir. Uygulama kod değişikliği olmadan servis başına mTLS, retry ve gözlemlenebilirlik sağlar.
2. Edge/gateway proxy
Çevrede (perimeter) paylaşılan bir Envoy instance filosu; TLS sonlandırma, dahili servislere yönlendirme, auth, rate limiting işlemlerini yürütür. Bu “API Gateway” pattern’idir (Envoy Gateway, Contour, Gloo, Emissary-ingress, Istio Ingress Gateway).
3. Front proxy + TLS passthrough (çift proxy / SNI routing)
TLS’i hiç sonlandırmayan, yalnızca SNI’ye göre (tcp_proxy + tls_inspector ile) TLS’i gerçekten sonlandıran dahili Envoy instance’larına yönlendiren bir edge Envoy — edge’in özel anahtarları tutmaması gerektiğinde veya istemcilerin gerçek uçtan uca TLS’e ihtiyacı olduğunda kullanılır.
4. Bağımsız L4/L7 yük dengeleyici
Dahili yük dengeleme için HAProxy/Nginx’in yerine geçer — config oluşturma araçları (control plane’ler) reload olmadan güncellemeleri sürebildiğinden genellikle daha basittir.
5. Veritabanı/protokol proxy’si
Envoy’un redis_proxy, mongo_proxy, thrift_proxy, dubbo_proxy ve kafka_broker filter’ları, HTTP olmayan protokolleri de proxy’lemesine izin verir — bu protokoller için de HTTP’de olduğu gibi connection pooling, gözlemlenebilirlik ve auth sağlar.
Sidecar mesh’ler için best practice: Kaynak overhead’ini izleyin — her sidecar pod başına CPU/bellek tüketir. concurrency‘i ayarlayın, LEAST_REQUEST LB kullanın ve kullanılmayan stats/filter’ları devre dışı bırakın (her istekte gereksiz Wasm/Lua çalıştırmak gerçek istek başına gecikme ekler).
16. Service Mesh Pattern’leri (Istio, Gateway API)
Günümüzde çoğu kişinin Envoy ile ilk karşılaşması Istio üzerinden olur; Istio, data plane’i olarak yalnızca Envoy’u kullanır, istiod ise xDS config’ini push eden control plane’dir.
Ham Envoy üzerine katmanlanmış Istio’ya özgü kavramlar
- VirtualService → Envoy
RouteConfiguration‘a (RDS) derlenir. - DestinationRule → Envoy
Clusterconfig’ine (LB politikası, circuit breaker’lar, TLS ayarları, subset’ler) derlenir. - Gateway → mesh ingress/egress’te Envoy
Listenerconfig’ine derlenir. - PeerAuthentication / AuthorizationPolicy → Envoy
RBACfilter config’ine + mTLS ayarlarına derlenir. - EnvoyFilter → Istio’nun soyutlamaları ihtiyacınız olan bir şeyi expose etmediğinde ham Envoy config’ini doğrudan patch’lemek için bir kaçış kapısı — güçlü ama Istio upgrade’leri arasında kırılgandır; dikkatle ve az kullanın.
Kubernetes Gateway API
Ingress’in yerini alan daha yeni, vendor-neutral standart — birkaç implementasyon, Envoy’u altta yatan data plane olarak kullanır (Envoy Gateway, Envoy projesinin kendisi tarafından bakımı yapılan referans implementasyondur; ayrıca Istio’nun Gateway API desteği, GKE Gateway, vb.). Envoy’un Listener/Route modeline temiz şekilde eşlenen rol odaklı kaynaklar (GatewayClass, Gateway, HTTPRoute, TCPRoute) getirir.
Best practice: Yalnızca mTLS + gözlemlenebilirlik için bir mesh benimsiyorsanız ve gelişmiş trafik kaydırma (traffic shifting) ihtiyacınız yoksa, klasik sidecar’lardan daha az pod başına overhead ile ihtiyaçlarınızı karşılayıp karşılamadığını görmek için daha basit sidecar’sız bir mesh’i (Istio’nun ambient mode’u; pod başına Envoy “ztunnel” + waypoint proxy’leri kullanır) değerlendirin.
17. Performans Ayarlama (Tuning)
--concurrency N— kullanılabilir CPU çekirdek sayısına eşit (veya control-plane/admin işi için biraz alan bırakacak şekilde biraz altına) ayarlayın. Çok fazla worker thread context-switch overhead’ine, çok az ise CPU’nun yetersiz kullanılmasına yol açar.- Connection pooling — cluster’larda
max_connections,max_requests_per_connection‘ı ayarlayın; HTTP/2 multiplexing’i (http2_protocol_options) destekleyen upstream’lere olan bağlantı sıklığını azaltır. - Buffer limitleri —
per_connection_buffer_limit_bytesbackpressure’ı kontrol eder; çok yüksek olması yük altında bellek şişmesi riski taşır, çok düşük olması ise ani (bursty) trafikte erken bağlantı reset’lerine yol açar. - Kullanılmayan istatistikleri devre dışı bırakın — ölçekte yüksek kardinaliteli endpoint/route başına istatistikler belleğe hakim olabilir;
stats_matcherexclusion listeleri kullanın. - Hot path’te aşırı Lua/Wasm’dan kaçının — her filter gecikme ekler; özel filter’lar eklemeden önce ve sonra
wrk/nighthawk(Envoy’un kendi yük test aracı) ile benchmark yapın. - HTTP/2 & HTTP/3 (QUIC) — upstream’de
http2_protocol_options‘ı ve downstream’decodec_type: HTTP3‘ü (UDP listener ile) etkinleştirmek, mobil/yüksek gecikmeli istemciler için bağlantı kurulum gecikmesini önemli ölçüde azaltabilir. - Hot restart / drain —
drain_time‘ı yapılandırın ve SIGTERM tabanlı graceful shutdown kullanın, böylece rolling deploy’lar sırasında devam eden istekler kesilmek yerine tamamlanır.
Envoy’a özgü metrik korelasyonuna ihtiyacınız olduğunda genel araçlar yerine gerçekçi, Envoy farkındalıklı benchmark için Nighthawk‘ı (Envoy’un yoldaş yük üreticisi) kullanın.
18. Operasyonel Best Practice’ler
- Üretimde her zaman tek bir gRPC stream ile ADS kullanın, ayrı LDS/RDS/CDS/EDS bağlantıları değil — config sapması/sıralama yarışlarından kaçının.
- Control plane değişikliklerinizi versiyonlayın ve canary’leyin — kötü bir xDS push’u anında filo genelinde etki yapabilir; control-plane config değişikliklerini tıpkı uygulama deploy’ları gibi kademeli olarak sürün.
- Her yerde açık timeout’lar ayarlayın — üretim route’ları için asla varsayılanlara güvenmeyin.
- Retry’ları circuit breaker’lar ve retry budget’larla eşleştirin — asla tek başına “num_retries” göndermeyin.
- Tüm sertifikalar için SDS kullanın — sertifikaları asla statik config’e veya image’lara gömmeyin.
- Sadece ham 5xx sayılarını değil,
RESPONSE_FLAGS‘ı, circuit breaker tetiklenmelerini ve outlier ejection’ları izleyin — bayraklar size nedenini söyler. - Güvenlik açısından kritik yollarda ext_authz için
failure_mode_allow: false‘ı koruyun. - Birkaç yüz cluster/route’u geçtiğinizde kardinaliteyi kontrol etmek için
stats_matcherkullanın. - Shutdown/deploy sırasında bağlantıları düzgünce drain edin (
drain_time, listener drain, SIGTERM öncesi healthcheck-fail pattern’leri). - Envoy/Istio sürümlerini dikkatle sabitleyin ve release notlarını okuyun — deprecated/kaldırılmış extension’lar (Envoy’un belgelenmiş bir deprecation politikası vardır, genellikle 2 minor sürüm), upgrade sırasında config’leri sessizce bozabilir.
- Rollout’tan önce config değişikliklerini
envoy --mode validateile test edin ve gerçekte neyin aktif olduğunu doğrulamak için admin/config_dumpendpoint’ini kullanın. - İlk debug durağınız olarak admin arayüzünün
/clusters,/listeners,/stats,/server_infoendpoint’lerini kullanın — tahmin etmeyin, gerçek çalışma zamanı state’ini inceleyin.
19. Yaygın Tuzaklar ve Anti-Pattern’ler
| Tuzak | Neden Zarar Verir | Çözüm |
|---|---|---|
| Circuit breaker’sız retry’lar | Kısmi kesintileri tam kesintiye büyütür (“retry storm”) | retry_budget + circuit_breakers ekleyin |
| Config dosyalarında statik TLS sertifikaları | Restart olmadan rotasyona sokulamaz; secret’lar git/config-management içinde | SDS kullanın |
| Açık route timeout’ları yok | Varsayılanlar gecikme profilinize uygun olmayabilir; askıda kalan istekler birikir | Route başına timeout ve per_try_timeout ayarlayın |
| Ayrı LDS/RDS/CDS/EDS stream’leri | Rollout sırasında güncelleme sırası yarışları geçici 503’lere yol açar | ADS kullanın (tek birleştirilmiş stream) |
| Ölçekte sınırsız endpoint başına istatistik | Büyük filolarda bellek/kardinalite patlaması | stats_matcher exclusion’ları |
Auth yollarında failure_mode_allow: true | Authz servisi kapandığında açık başarısız olur — güvenlik açığı | Kritik yollarda false ayarlayın |
Log’larda %RESPONSE_FLAGS%‘ı görmezden gelmek | Hataların gerçek kök nedenini (UO/UF/UT/NR/vb.) kaçırırsınız | Access log formatına ekleyin, üzerlerine alarm kurun |
| Idempotent olmayan POST’ları körlemesine retry etmek | Yinelenen yan etkilere neden olabilir (çift ödeme vb.) | retry_on‘ı kısıtlayın, idempotency key kullanın |
| Filter chain matching yerine tek dev bir filter chain | Akıl yürütmesi zor, domain’ler arasında yeniden kullanımı zor | SNI/port tabanlı bölünmeler için filter_chain_match kullanın |
| EnvoyFilter’ı (Istio) ilk çare olarak ele almak | Istio upgrade’leri arasında kırılgan, denetlemesi zor | Native Istio CRD’lerini tercih edin; EnvoyFilter’ı az kullanın |
20. Hızlı Referans Cheat Sheet
# Çalıştırmadan config'i doğrula
envoy --mode validate -c envoy.yaml
# N worker thread ile çalıştır
envoy -c envoy.yaml --concurrency 4
# Admin endpoint'leri (varsayılan port 9901)
GET /stats → tüm istatistikler (metin)
GET /stats/prometheus → Prometheus formatlı istatistikler
GET /clusters → cluster sağlığı/üyeliği
GET /listeners → aktif listener'lar
GET /config_dump → şu anda aktif config (xDS sonrası)
GET /server_info → versiyon, uptime, state
POST /healthcheck/fail → bu Envoy'u sağlıksız olarak işaretle (graceful drain)
POST /drain_listeners → bağlantıları drain etmeye başla
# Kilit yanıt bayrakları (access log'larda)
UO = Upstream Overflow (circuit breaker tetiklendi)
UF = Upstream bağlantı hatası (Failure)
UT = Upstream istek Timeout'u
NR = Yapılandırılmış Route yok (No Route)
RL = Rate Limited (hız sınırlandı)
UAEX = Unauthorized (ext_authz reddetti)
LR = Bağlantı Yerel Reset'i
DC = Downstream bağlantı sonlandırması
Herhangi bir üretim route’u için önerilen varsayılan dayanıklılık yığını
route:
timeout: 10s
retry_policy:
retry_on: "5xx,reset,connect-failure,refused-stream"
num_retries: 2
per_try_timeout: 3s
retry_back_off: { base_interval: 0.1s, max_interval: 1s }
retry_budget:
budget_percent: { value: 20 }
min_retry_concurrency: 3
cluster:
circuit_breakers:
thresholds:
- priority: DEFAULT
max_connections: 1000
max_pending_requests: 1000
max_requests: 1000
max_retries: 3
outlier_detection:
consecutive_5xx: 5
interval: 10s
base_ejection_time: 30s
max_ejection_percent: 50
health_checks:
- timeout: 1s
interval: 5s
unhealthy_threshold: 3
healthy_threshold: 2
http_health_check: { path: /healthz }
Daha Fazla Okuma
- Resmi dokümantasyon: https://www.envoyproxy.io/docs
- xDS protokol spesifikasyonu: https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol
- Envoy Gateway (Gateway API referans implementasyonu): https://gateway.envoyproxy.io
- Nighthawk yük üretici: https://github.com/envoyproxy/nighthawk
- go-control-plane (kendi control plane’inizi oluşturun): https://github.com/envoyproxy/go-control-plane
Bu rehber, Envoy’un stabil v3 API yüzeyini ve mevcut Envoy release hatları itibarıyla yaygın üretim pattern’lerini yansıtmaktadır. Extension isimleri/alanları major sürümler arasında değişebilir — her zaman çalıştırdığınız sürüme karşı /config_dump ve resmi API referansı üzerinden çapraz kontrol yapın.