Cilium Gateway API Nedir? Neyi Çözer, Kazanımları ve Ayrı Ingress Controller Olmadan Bir Lab

Cilium Gateway API nedir, neyi çözer, ne kazandırır? kind'da lab: tek shared Gateway, 90/10 split (177/23), cert-manager ile HTTPS ve 4 gerçek hata.

Yazan: Mirac Can Yılmaz 9 dk okuma
Cilium Gateway API Nedir? Neyi Çözer, Kazanımları ve Ayrı Ingress Controller Olmadan Bir Lab - platform-mühendisliği yazısının kapak görseli

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?

Diyagram: önce, Cilium'un Envoy'u ve yanında canary kuralları annotation olan ayrı bir ingress-nginx; sonra, Gateway ve HTTPRoute ile tek bir cilium-envoy DaemonSet ve 90/10 weight alanı. Altta tek bir istek: client, LB-IPAM pool'undan gelen Gateway IP'si, isteği node'daki Envoy'a yönlendiren Cilium agent, HTTPRoute kuralları, podinfo v1 ve v2

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.

make up: GatewayClass cilium ACCEPTED True; platform namespace'indeki shared Gateway 172.20.250.1 adresiyle PROGRAMMED True; LoadBalancer Service'i aynı external IP'ye sahip

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:

  1. podinfo.lab.local host'u v1'e gidiyor.
  2. 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.
  3. x-canary: always header'ı taşıyan istekler v2'ye, geri kalan her şey v1'e. Test eden kişi yeni sürüme bilerek böyle ulaşıyor.

Üç route: ilk isteğe podinfo-v1 cevap veriyor; 90/10'da 200 istek 177 v1 ve 23 v2 olarak sayıldı; x-canary header'ı ile cevap v2, header'sız v1

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.

podinfo-lab-local-tls sertifikası Ready ve Secret'ı var; HTTPS v1'den HTTP/2 200 dönüyor; 80 portunda düz HTTP 301 Moved Permanently ve location https://podinfo.lab.local:443/ dönüyor

Son kontrol

make verify: GatewayClass True, shared-gw Programmed, iki route, 80 ve 443 portlu tek LoadBalancer Service, cilium-envoy 3/3 hazır; ekstra namespace'ler sadece cert-manager ve cilium-secrets

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.

İlk deneme: GatewayClass ACCEPTED Unknown; operator log'u Required GatewayAPI resources are not found, backendtlspolicies.gateway.networking.k8s.io not found diyor; çözüm: CRD'yi uygula ve operator'ı yeniden başlat

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.

Pool silindi: gw-b ve shared-gw ikisi de PROGRAMMED False, iki Service'in EXTERNAL-IP'si pending; gw-b koşulu AddressNotAssigned; pool geri geldi, gw-b 0.2 sn'de programmed, artık gw-b 172.20.250.1, shared-gw 172.20.250.2

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.

demo-b namespace'indeki route kopyası: Gateway'de hâlâ listener başına bir bağlı route var; route Accepted=False NotAllowedByListeners, namespace kısıtlaması nedeniyle bağlanamıyor, ve podinfo-v1 için BackendNotFound diyor

İ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.

enableAlpn false iken HTTPS testi HTTP/1.1 200 OK dönüyor; true yapıp operator'ı yeniden başlatınca HTTP/2 200 dönüyor

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

İnsanın en büyük hatalarından biri de doğru zamanı yanlış kişilerle doldurmaktır.
Charles Bukowski