Cilium çalıştıran Kubernetes cluster'larının çoğunda her node'da zaten bir Envoy proxy var. Yine de çoğu, yanına ayrı bir ingress controller kuruyor, genelde ingress-nginx. Aynı işi yapan iki proxy. Bu yazıda Cilium Gateway API'nin ne olduğuna, hangi sorunu çözdüğüne ve ne kazandırdığına bakıyorum; sonra ikinci proxy'yi kaldırdığım lab'ı gösteriyorum: tek bir shared Gateway, 90/10 traffic split, header ile canary, cert-manager'dan HTTPS ve redirect. Dört yerde patladı; gerçek hata mesajlarıyla sonda.
Cilium Gateway API nedir?
Gateway API, trafiği cluster'a almanın Kubernetes standardı. Ingress objesinin halefi. Controller'a özel annotation'larla dolu tek bir obje yerine işi birkaç net kaynağa bölüyor:
- GatewayClass: gateway'i hangi implementasyon çalıştırıyor (burada Cilium).
- Gateway: giriş noktasının kendisi. Hangi port, hangi hostname, hangi TLS sertifikası, hangi namespace'ler route bağlayabilir.
- HTTPRoute: yönlendirme kuralları. Host, path, header ve trafiğin ne kadarının hangi backend'e gideceği.
Cilium Gateway API, bu standardın Cilium implementasyonu. Controller cilium-operator'ın içinde çalışıyor, trafik ise Cilium'un L7 policy ve Hubble için zaten çalıştırdığı cilium-envoy DaemonSet'inden geçiyor. Tek bir Helm değeri ile açılıyor (gatewayAPI.enabled); kurulacak ayrı bir controller yok.
Neyi çözüyor?
Tek iş için iki proxy. Network plugin'iniz Cilium ise Envoy zaten her node'da. Yanındaki ingress controller ikinci bir proxy: güncellenecek ikinci bir şey, takip edilecek ikinci bir güvenlik yaması listesi, bir istek yavaşladığında bakılacak ikinci bir yer.
Annotation'lara gömülü canary ve yönlendirme kuralları. Ingress sadece host ve path'ten anlıyor. Geri kalan her şey (trafik ağırlığı, header eşleşmesi, redirect) annotation, ve her controller'ın annotation'ı farklı. Controller değiştirmek hepsini yeniden yazmak demek; annotation'daki bir yazım hatası da çoğu zaman sessizce yok sayılıyor.
Net bir sahibi yok. Ingress'te TLS sertifikası, hostname'ler ve uygulamanın route'ları aynı objede. Platform ekibi ile uygulama ekibi aynı dosyayı düzenliyor. Gateway API bunları ayırıyor: Gateway platform ekibinin, HTTPRoute'lar uygulama ekiplerinin.
Cilium üzerinde Gateway API ne kazandırıyor?
| Kazanım | Pratikte anlamı | Lab'da |
|---|---|---|
| İki proxy yerine bir | Gateway trafiği Cilium'un zaten çalıştırdığı Envoy'dan geçiyor | Ekstra kurulan bileşen: sadece cert-manager |
| Ağırlık ve header annotation değil, alan | Canary, route'ta weight: 90 / weight: 10 |
200 istek: 177'si v1'e, 23'ü v2'ye |
| Net sahiplik | Gateway platform ekibinde, uygulamalar kendi namespace'inden route bağlıyor | Etiketsiz namespace'ten gelen route reddedildi |
| Taşınabilir | Aynı HTTPRoute Envoy Gateway, Istio ve diğerlerinde çalışır; sadece GatewayClass değişir |
Route'lar düz Gateway API v1 |
| Elle sertifika yok | cert-manager Gateway'deki tek bir annotation'ı okuyup Secret'ı kendisi üretiyor | Sertifika, wait başlamadan Ready |
Nasıl çalışıyor?

Operator bir Gateway gördüğünde onun için bir LoadBalancer Service oluşturuyor. kind'da bulut load balancer'ı yok; IP, IPAM yazısındaki gibi Cilium'un LB-IPAM pool'undan geliyor ve L2 announcement ile ağa duyuruluyor. Bir istek o IP'ye geldiğinde Cilium agent onu node'daki Envoy'a yönlendiriyor, Envoy da HTTPRoute'lardaki kuralları uyguluyor. Ayrı controller pod'u yok, ayrı proxy yok.
Lab: ne kurdum
Her şey bir MacBook'ta kind üzerinde (Colima, 4 CPU / 8 GB): Kubernetes 1.37, kube-proxy'siz Cilium 1.20.2, Gateway API v1.6.1, cert-manager v1.21.2. Uygulama iki sürümlü podinfo, v1 ve v2; cevap hangi sürümün döndüğünü söylüyor, split saymak için bu yeterli. Lab'ın tamamı, boş makineden son kontrole kadar, son koşuda 3 dakika 38 saniye sürdü.
Adım 1: Önce Gateway API CRD'leri, sonra Cilium
Burada sıra önemli. Cilium operator açılışta yedi Gateway API kaynak tipinin hepsinin var olduğunu kontrol ediyor. Biri eksikse Gateway controller hiç başlamıyor (aşağıdaki ilk hata bu). CRD'ler yerindeyken cilium GatewayClass'ı kabul edildi, platform namespace'indeki shared Gateway pool'dan IP aldı ve bir saniyeden kısa sürede Programmed oldu.

Accepted sadece "objeyi anladım" demek. Programmed ise "konfigürasyon Envoy'da" demek. Hata ayıklarken Programmed'a bakın.
Adım 2: Route'lar, 90/10 split ve header ile canary
Uygulama ekibi HTTPRoute'ları kendi namespace'inde (demo) yazıyor. Aynı route'un üç sürümünü art arda uyguladım; gerçek bir canary geçişi Git'te tek bir dosyayı böyle değiştirirdi:
podinfo.lab.localhost'u v1'e gidiyor.- v1 ile v2 arasında 90 ve 10 ağırlık. 200 isteğin 177'si v1'e, 23'ü v2'ye gitti. Önceki koşular 178/22 ve 186/14 verdi. Split istek başına ve istatistiksel; 90/10'a yaklaşıyor ama birebir tutmuyor.
x-canary: alwaysheader'ı taşıyan istekler v2'ye, geri kalan her şey v1'e. Test eden kişi yeni sürüme bilerek böyle ulaşıyor.

Bunların hiçbiri annotation gerektirmedi. Ağırlık ve header eşleşmesi route'un normal alanları.
Adım 3: cert-manager ile HTTPS, sonra redirect
HTTPS için Gateway'e 443 portunda ikinci bir listener ve bir ClusterIssuer'ı gösteren tek bir annotation ekledim. cert-manager annotation'ı görüp sertifika Secret'ını kendisi üretti; benim wait komutum başlamadan Ready'di. Lab için kendinden imzalı bir root CA kullandım ve test sertifikayı o CA'ya karşı doğruluyor (-k yok). Son olarak 80 portundaki küçük bir route HTTPS'e 301 dönüyor.

Son kontrol

Ekstra namespace'ler sadece cert-manager ve cilium-secrets. İkincisi Cilium'un kendisine ait; operator, listener'ın TLS Secret'ını Envoy için oraya kopyalıyor.
Nerede patladı: 4 gerçek hata
1. GatewayClass ACCEPTED Unknown'da kaldı: 7 CRD'den biri eksikti
İlk denememde yedi Gateway API CRD'sinden altısını kurdum; BackendTLSPolicy'nin gerekmediğini sanmıştım. GatewayClass oluştu ama hiç True olmadı, operator log'u da eksik kaynağın adını yazdı. Sadece CRD'yi uygulamak düzeltmedi, çünkü kontrol yalnızca operator açılırken çalışıyor. cilium-operator ve cilium DaemonSet'ini yeniden başlatmak düzeltti.

2. AddressNotAssigned: Gateway waiting for address: IP pool'u yok
Gateway IP'sini LoadBalancer Service'lere IP veren şeyden alıyor; bulutsuz Cilium'da bu LB-IPAM pool'u. Pool'u silip ikinci bir Gateway oluşturdum. Service'i <pending>'de kaldı, Gateway de Programmed=False AddressNotAssigned dedi. Sürpriz diğer Gateway'deydi: pool'u silmek, sorunsuz çalışan shared-gw'nin IP'sini de aldı. Pool'u geri koyunca ikisi de 0.2 saniyede Programmed oldu, ama farklı sırayla: shared-gw .1'den .2'ye kaydı. Canlı bir cluster'da IP pool'u silmeyin.

3. NotAllowedByListeners: etiketsiz namespace'ten gelen route
Gateway sadece gateway-access=true etiketli namespace'lerden route kabul ediyor. Etiketsiz bir namespace açıp route'un bir kopyasını oraya koydum. Gateway'in kendisi hiçbir sorun göstermedi; bağlı route sayısı sadece artmadı. Hata route'un kendi status'undaydı. Bir route hiçbir şey yapmıyorsa önce oraya bakın.

İkinci satır bonus: backend Service demo-b'de değil demo'da duruyor, route bunu da bildiriyor.
4. HTTPS listener'da HTTP/2 yerine HTTP/1.1
HTTPS testim, client HTTP/2 önermesine rağmen HTTP/1.1 200 döndü. Cilium, Gateway listener'larında varsayılan olarak HTTP/2'yi duyurmuyor (ALPN kapalı). gatewayAPI.enableAlpn: true ve operator restart'ından sonra aynı test HTTP/2 200 döndü. Hiçbir şey uyarmıyor; ancak bakarsanız fark ediyorsunuz.

Bir pratik not daha: macOS'ta kind ağı Colima VM'inin içinde, Gateway IP'sine Mac'ten ulaşılamıyor. Lab'daki her istek cluster içindeki küçük bir curl pod'undan gönderildi.
Ne zaman kullanılır, ne zaman kullanılmaz
| Durum | Tercih |
|---|---|
| Cilium zaten network plugin'iniz; host/path yönlendirme, split, header ile canary, TLS sonlandırma lazım | Cilium Gateway API. İkinci proxy yok. |
| Uçta rate limiting, JWT doğrulama, external auth ya da WASM filtreleri lazım | Envoy Gateway (ya da tam özellikli başka bir gateway). HTTPRoute'lar olduğu gibi taşınır; sadece GatewayClass değişir. |
| Cilium kullanmıyorsunuz | Herhangi bir Gateway API implementasyonu; bu yazıdaki route'lar standart. |
| Hâlâ çok sayıda Ingress objeniz var | Route route taşıyın; geçiş sırasında Gateway ve Ingress objeleri aynı cluster'da yaşayabilir. |
Cilium'un kendi Ingress controller'ı da var (ingressController.enabled). Onu kullanmadım: Ingress objesi hâlâ annotation olmadan ağırlık ya da header ifade edemiyor, Cilium dokümanı da yeni kurulumlar için Gateway API'yi öneriyor.
Özet
- Cilium Gateway API, Cilium'un zaten çalıştırdığı Envoy'u ingress olarak kullanmanızı sağlıyor. Ayrı controller yok.
- Ağırlık, header eşleşmesi ve redirect standart bir
HTTPRoute'un alanları; aynı route'lar başka implementasyonlarda da çalışıyor. - Lab'da: tek shared Gateway, 177/23'e düşen bir 90/10 split, header ile canary, HTTP/2 ile HTTPS ve redirect. Tek ekstra kurulum cert-manager.
- Dikkat edilecek dört şey: Cilium'dan önce 7 CRD'nin hepsi, Gateway'den önce bir IP pool'u (ve canlı cluster'da asla silmeyin), route'lar için namespace etiketi, HTTP/2 için
enableAlpn.
Kaynaklar: Cilium dokümanı Gateway API Support, LoadBalancer IP Address Management (LB IPAM) ve L2 Announcements; Kubernetes Gateway API dokümanı (v1.6.1, standard channel); cert-manager dokümanı Annotated Gateway resource.
Seride sıradaki
Bu, Cilium Uçtan Uca serisinin dördüncü yazısı. Sonraki: Sidecar'sız Service Mesh Nedir? Neyi Çözer, Kazanımları ve WireGuard ile Mutual Auth'lu Bir Cilium Lab'ı. Önceki yazı: CiliumNetworkPolicy ile Default-Deny'a Giden Yol: L3/L4, DNS ve L7 HTTP Kuralları.
Bu lab'ın kodu (kind yapılandırması, Cilium values, Gateway ve route dosyaları, cert-manager kurulumu, script'ler ve Makefile) Buy Me a Coffee'deki Lab Access üyeleriyle paylaşılıyor; üye olduktan sonra repo daveti e-postayla geliyor: https://buymeacoffee.com/miraccanyilmaz/membership