← blog · 3 Eylül 2026

Gateway API: Ingress'ten Sonra Ne Değişti

Ingress on yıldır aynı üç dört alanı taşıyor, geri kalan her şey controller'a özel bir yorum satırıyla eklendi. Gateway API bu yamalı yapıyı GatewayClass, Gateway ve HTTPRoute olarak üçe bölüyor; hangi sorunu gerçekten çözdüğünü, cross-namespace erişimi neden ayrıca izin gerektirdiğini ve ne zaman hâlâ düz Ingress'in yettiğini anlatıyoruz.

Bir Ingress nesnesini açtığınızda gördüğünüz alanlar oldukça azdır: host, path, backend servis, belki bir TLS bloğu. Gerçek yapılandırmanın büyük kısmı ise annotations altında saklanır ve o anotasyonların anlamı hangi Ingress controller'ı kullandığınıza göre değişir. NGINX Ingress Controller'da nginx.ingress.kubernetes.io/rewrite-target yazan bir kural, Traefik'e geçtiğinizde hiçbir işe yaramaz. Trafiği yüzde bazlı bölmek, bir başlığa göre yönlendirmek ya da TCP/UDP trafiğini yönetmek istediğinizde spesifikasyonun dışına çıkıp controller'ın kendi CRD'sine ya da anotasyon setine geçmek zorunda kalırsınız. Ingress kaynağı hiçbir zaman bunun için tasarlanmadı; HTTP yönlendirmesinin en ortak paydasını standartlaştırdı, gerisini üreticilere bıraktı.

Gateway API bu boşluğu üç ayrı kaynağa bölerek kapatıyor ve bunu yaparken asıl değiştirdiği şey özellik listesinden çok yetki sınırları.

Tek kaynak, üç sorumluluk

Ingress'te tek bir YAML dosyasında hem 'hangi yük dengeleyici kullanılsın' hem 'hangi port ve sertifika dinlensin' hem de 'hangi path hangi servise gitsin' bilgisi iç içe durur. Küçük bir ekipte sorun çıkarmaz, ama platform ekibi ile uygulama ekibi ayrıştığı anda bu iç içelik bir yetki problemine dönüşür: uygulama takımına path kuralı yazma hakkı verirken TLS sertifikasını ya da dinleyici portunu değiştirme hakkını da vermiş olursunuz, çünkü ikisi aynı nesnede.

Gateway API bunu üç kaynağa ayırır ve her birini farklı bir role verir:

GatewayClass altyapı sağlayıcısının tanımladığı, hangi controller'ın bu sınıfı işleteceğini söyleyen küme çapında bir kaynaktır. Gateway platform ekibinin sahip olduğu, dinleyici port, protokol ve TLS sertifikasını tanımlayan kaynaktır. HTTPRoute ise uygulama ekibinin kendi namespace'inde yazdığı, hangi path'in hangi servise gideceğini belirleyen kaynaktır ve bir Gateway'e parentRefs ile bağlanır.

Bu ayrım RBAC ile birebir örtüşür. Uygulama takımına yalnızca HTTPRoute üzerinde yazma izni verirsiniz, Gateway kaynağı platform ekibinde kalır. Sonuç olarak bir uygulama geliştiricisi kendi servisine yeni bir path açabilir ama paylaşılan sertifikayı ya da dinleyici portunu değiştiremez.

Üç kaynağın gerçek hâli

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: ana-gateway
  namespace: platform
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        certificateRefs:
          - name: joker-sertifika
      allowedRoutes:
        namespaces:
          from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: odeme
  namespace: odeme
spec:
  parentRefs:
    - name: ana-gateway
      namespace: platform
  hostnames:
    - "odeme.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: odeme-servisi
          port: 80

GatewayClass bir kere kurulur ve genelde controller'ın kurulum paketiyle birlikte gelir. Gateway platform tarafından, kümedeki uygulama sayısı kadar değil, genelde ortam ya da takım başına bir kez tanımlanır. HTTPRoute ise her uygulamanın kendi namespace'inde yaşar ve status alanındaki conditions üzerinden ilgili Gateway'e gerçekten bağlanıp bağlanamadığını raporlar; kubectl get httproute odeme -o yaml çıktısında Accepted: True görmeden route'un çalıştığını varsaymayın.

Namespace sınırını kasıtlı olarak aşmak

Yukarıdaki örnekte allowedRoutes.namespaces.from: Same yazdım, yani platform namespace'indeki Gateway yalnız kendi namespace'inden route kabul ediyor. Farklı bir namespace'teki HTTPRoute'un bu Gateway'e bağlanabilmesi için from: All ya da from: Selector seçilmesi gerekir. Bu, cross-namespace referansların Gateway API'de varsayılan olarak kapalı olduğu anlamına gelir ve bu bilinçli bir tasarım kararıdır: bir namespace'teki kaynağın başka bir namespace'teki servise erişmesi izole bir kümede tehlikelidir.

Aynı mantık ters yönde de işler. Bir HTTPRoute'un başka bir namespace'teki Service'e backendRefs ile referans vermesi istendiğinde, hedef namespace'te bir ReferenceGrant nesnesi bu izni açıkça vermediği sürece referans reddedilir:

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
  name: route-erisim-izni
  namespace: odeme
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      namespace: platform
  to:
    - group: ""
      kind: Service

Buradaki fark önemli: izni veren taraf her zaman hedef namespace'tir, kaynak namespace değil. Bir servise kimin erişebileceğine o servisin sahibi karar verir, erişmek isteyen taraf değil. Ingress'te bu tür bir sınır yoktu; annotation'larla kurulan cross-namespace backend'ler sessizce çalışırdı ve kimin kime bağlandığı yalnızca dikkatli bir denetimle anlaşılırdı.

Trafik bölme tek bir alanla gelir

Canary dağıtım ya da mavi-yeşil geçiş için Ingress'te controller'a özel bir anotasyon ya da ayrı bir CRD gerekirken, HTTPRoute'ta backendRefs listesindeki her girdiye bir weight yazmak yeterlidir:

  rules:
    - backendRefs:
        - name: odeme-v1
          port: 80
          weight: 90
        - name: odeme-v2
          port: 80
          weight: 10

Bu, hangi implementasyonu kullanırsanız kullanın aynı şekilde çalışır, çünkü spesifikasyonun bir parçasıdır. Değişecek olan sadece dağıtım hızınız: weight değerini elle güncelleyebilir ya da bir Flagger veya Argo Rollouts gibi bir araçla otomatik kademelendirebilirsiniz; ikisi de aynı alanı hedefler.

Göç: hepsini birden değiştirmeyin

Gateway API, Ingress'i devre dışı bırakmaz; ikisi aynı kümede yan yana çalışabilir. Pratik göç yolu şudur: yeni servisleri doğrudan HTTPRoute ile açın, mevcut Ingress kayıtlarına dokunmayın. kubernetes-sigs/ingress2gateway projesi kümenizdeki Ingress nesnelerini tarayıp eşdeğer Gateway ve HTTPRoute taslakları üretir; ama bu taslaklar doğrudan uygulanacak son hâl değil, controller'a özel anotasyonların karşılığını bulamadığı yerlerde boş bırakılan alanlarla gelir ve elle tamamlanması gerekir.

Bir Ingress'i aynı anda HTTPRoute'a çevirip eskisini silmeyin; ikisini bir süre paralel tutup gerçek trafikle doğrulayın, sonra eskisini kaldırın. Aynı host için hem Ingress hem Gateway API üzerinden tanımlanmış kural varsa hangisinin öncelikli olacağı controller'a göre değişir ve bu genelde belgelenmemiş bir davranıştır.

Tuzaklar

Gateway API tek bir implementasyon değil, bir spesifikasyondur; Envoy Gateway, Cilium, Istio, Traefik, NGINX Gateway Fabric gibi birçok controller bunu farklı olgunluk seviyesinde uygular. Standart kanaldaki GatewayClass, Gateway, HTTPRoute ve ReferenceGrant genel olarak kararlı kabul edilir; TCPRoute, UDPRoute ve TLSRoute ise hâlâ deneysel kanalda durur ve her controller bunları desteklemez. Bir özelliği kullanmadan önce seçtiğiniz controller'ın destek matrisine bakmadan spesifikasyonu okumak yeterli değildir.

İkinci tuzak status alanını hiç okumamaktır. Bir HTTPRoute uygulandığında hata vermez; Gateway'e bağlanamıyorsa bunu yalnızca status.parents[].conditions içindeki Accepted ve ResolvedRefs koşullarından öğrenirsiniz. Bu koşulları izlemeyen bir kurulum, trafiğin gerçekte hiç yönlendirilmediği bir durumu 'uygulandı' sanabilir.

Üçüncü tuzak ReferenceGrant'i unutmaktır: cross-namespace bir backend referansı sessizce reddedilir, hata mesajı genelde HTTPRoute tarafında değil status koşullarında görünür ve ilk bakışta 'servis bulunamadı' gibi görünür, oysa servis oradadır, izin eksiktir.

Ne zaman hâlâ Ingress yeterli

Tek namespace'te birkaç servis çalıştıran, platform ile uygulama ekibi ayrımı olmayan, trafik bölme ihtiyacı bulunmayan küçük bir kurulumda Gateway API'ye geçmek ek bir CRD kümesi, ek bir öğrenme eğrisi ve controller seçimi konusunda yeni bir karar getirir. Ingress'in dört alanı bu senaryoda hâlâ yeterlidir. Geçişi haklı çıkaran şey şu üçünden en az ikisinin doğru olmasıdır: birden fazla ekip aynı kümeye route tanımlıyor, düzenli olarak canary ya da ağırlıklı dağıtım yapıyorsunuz, ya da HTTP dışında TCP/gRPC gibi protokolleri de aynı yönetim modeliyle taşımak istiyorsunuz. Bu koşullar yoksa mevcut Ingress kurulumunuzu değiştirmek için acele etmeyin; spesifikasyon olgunlaşmaya devam ediyor ve göç maliyeti her ay biraz daha ucuzluyor.