Docker & DevOps

    Kubernetes Ingress Controller Kurulumu

    Tek giriş noktasından alan adı ve yol bazlı yönlendirme kuran Ingress rehberi.

    10 dk okuma Güncellendi: 25 Ağustos 2026

    Kümende üç servis var ve üçünü de dışarı açman gerekiyor. Her birine ayrı bir LoadBalancer Service tanımlarsan üç ayrı genel IP, üç ayrı sertifika ve üç ayrı yapılandırma noktası elde edersin — üstelik bulut sağlayıcısı her yük dengeleyici için ayrı ücret keser. Kubernetes Ingress controller kurulumu tam olarak bu dağınıklığı toplamak içindir: tek bir giriş noktası, tek bir genel IP ve alan adı ile yol bazlı yönlendirme kuralları.

    Bu rehberde Ingress kaynağı ile Ingress controller arasındaki (çok kişinin takıldığı) farkı, ingress-nginx kurulumunu, ilk yönlendirme kuralını yazmayı, Let's Encrypt ile otomatik TLS'i, en çok kullanılan açıklama (annotation) ayarlarını ve kendi sunucularında kurulmuş bir kümede genel IP alamama sorununu adım adım ele alacağım. Pod, Deployment ve Service kavramlarını henüz oturtmadıysan önce Kubernetes Pod, Deployment ve Service yazısını okumanı öneririm; Ingress bunların üzerine kurulur.

    Ingress Nedir, Service Neden Yetmiyor#

    Service katman 4'te çalışır: bir IP ve porta gelen trafiği Pod'lara dağıtır, ama HTTP'nin içine bakmaz. Hangi alan adına istek geldiğini, yolun /api mi /panel mi olduğunu bilmez. Bu yüzden firmaniz.com ve panel.firmaniz.com adreslerini aynı IP üzerinden farklı servislere yönlendirmek Service ile mümkün değildir.

    Ingress katman 7'de çalışır ve tam olarak bunu yapar. Bir Ingress kaynağı şunları tanımlar: hangi host, hangi yol, hangi Service ve hangi TLS sertifikası. Klasik bir sunucudaki Nginx sanal host yapılandırmasının Kubernetes karşılığı diyebilirsin — nitekim en yaygın Ingress controller'ı gerçekten Nginx üzerine kuruludur. Nginx ile Apache arasındaki farkları merak ediyorsan Apache ve Nginx karşılaştırması yazısı bu konuda iyi bir arka plan sunar.

    Karşılaştırma tablosu meseleyi netleştiriyor:

    İhtiyaçService (LoadBalancer)Ingress
    Servis başına genel IPHer servise bir taneHepsine tek tane
    Alan adına göre yönlendirmeYokVar
    Yola göre yönlendirme (/api)YokVar
    TLS sonlandırmaServisin kendisi yaparMerkezî, tek yerden
    Yeniden yazma, yönlendirme, hız sınırıYokAnnotation ile
    TCP/UDP servisleriDesteklerHTTP/HTTPS odaklı

    En Kritik Ayrım: Kaynak ve Controller#

    Yeni başlayanların neredeyse tamamı aynı yerde takılır: Ingress kaynağını yazarlar, kubectl apply ederler, kubectl get ingress çıktısında nesneyi görürler ama hiçbir şey çalışmaz. Sebep şudur: Ingress kaynağı sadece bir kural beyanıdır; o kuralları uygulayan bir controller kurulu değilse hiçbir şey olmaz.

    Kubernetes, Deployment ve Service için gerekli denetleyicileri kutudan çıkar hâlde getirir, ama Ingress için getirmez. Controller'ı sen kurarsın ve seçenekler arasında ingress-nginx, Traefik, HAProxy ve Contour gibi alternatifler vardır. Kurulu olup olmadığını şöyle kontrol edersin:

    # Kümede tanımlı ingress sınıfları
    kubectl get ingressclass
    # NAME    CONTROLLER                    AGE
    # nginx   k8s.io/ingress-nginx          5m
    
    # Controller Pod'ları çalışıyor mu
    kubectl get pods -n ingress-nginx
    

    Bu komut boş dönüyorsa controller yok demektir ve yazacağın hiçbir Ingress kuralı işlemez.

    ingress-nginx Kurulumu#

    En yaygın seçenek ingress-nginx. Kurulumun en temiz yolu Helm'dir; Helm'e yabancıysan Helm ile Kubernetes uygulama kurulumu yazısı temel kullanımı anlatıyor.

    # Depoyu ekle ve güncelle
    helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    helm repo update
    
    # Kendi ad alanına kur
    helm install ingress-nginx ingress-nginx/ingress-nginx \
      --namespace ingress-nginx --create-namespace \
      --set controller.service.externalTrafficPolicy=Local \
      --set controller.config.use-forwarded-headers="true"
    
    # Kurulumu doğrula
    kubectl -n ingress-nginx get pods
    kubectl -n ingress-nginx get svc ingress-nginx-controller
    

    Buradaki externalTrafficPolicy=Local ayarı önemlidir: varsayılan Cluster modunda kaynak IP adresi düğümler arası yönlendirme sırasında kaybolur ve uygulaman bütün ziyaretçileri aynı IP'den geliyormuş gibi görür. Bu, hız sınırlama ve coğrafi analizden log kayıtlarına kadar her şeyi bozar.

    Servis çıktısında EXTERNAL-IP sütununda bir adres görüyorsan kurulum tamamdır:

    kubectl -n ingress-nginx get svc ingress-nginx-controller
    # NAME                       TYPE           EXTERNAL-IP     PORT(S)
    # ingress-nginx-controller   LoadBalancer   185.12.34.56    80:31234/TCP,443:31892/TCP
    

    Alan adının DNS A kaydını bu IP'ye yönlendirmen gerekir. Alan adı tarafında bir düzenleme yapman gerekiyorsa alan adı panelinden A kaydını güncelleyebilirsin.

    Kendi Sunucularında: EXTERNAL-IP Neden Pending Kalıyor#

    Bulut sağlayıcısında LoadBalancer tipi bir Service oluşturduğunda sağlayıcı otomatik olarak bir yük dengeleyici oluşturur ve IP atar. Kendi sunucularında (bare-metal) kurduğun bir kümede böyle bir bileşen yoktur, dolayısıyla EXTERNAL-IP sonsuza kadar pending kalır. Bu bir hata değil, eksik bir bileşendir. Üç çözüm yolu var:

    YöntemNasıl çalışırNe zaman uygun
    MetalLBKümeye yük dengeleyici yeteneği ekler, havuzdan IP dağıtırBirden fazla düğümlü kendi kümen
    hostNetwork: trueController Pod'u doğrudan düğümün 80/443 portlarını dinlerTek veya iki düğümlü küçük küme
    NodePort + dış proxyÖnde ayrı bir Nginx/HAProxy trafiği düğümlere dağıtırZaten bir yük dengeleyicin varsa

    Tek düğümlü bir kurulumda en pratik yöntem hostNetwork'tür:

    helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
      --namespace ingress-nginx --create-namespace \
      --set controller.hostNetwork=true \
      --set controller.service.type=ClusterIP \
      --set controller.dnsPolicy=ClusterFirstWithHostNet
    

    Bu yapılandırmada dnsPolicy satırını atlarsan controller küme içi DNS'i çözemez ve arka uç servislerini bulamaz — kurulumu doğru görünen ama 503 dönen bir sistem elde edersin. Düğümün 80 ve 443 portlarının başka bir servis tarafından (örneğin sunucuda zaten çalışan bir Nginx) kullanılmadığından da emin ol.

    İlk Ingress Kuralını Yazmak#

    Controller hazır olduğuna göre artık kural yazabilirsin. İki servisi tek alan adı altında farklı yollara bağlayan bir örnek:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: firmaniz-web
      annotations:
        nginx.ingress.kubernetes.io/proxy-body-size: "32m"
    spec:
      ingressClassName: nginx
      rules:
        - host: firmaniz.com
          http:
            paths:
              - path: /api
                pathType: Prefix
                backend:
                  service:
                    name: api        # Service adı
                    port:
                      number: 80     # Service portu (targetPort değil)
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: web
                    port:
                      number: 80
    

    Dikkat edilecek üç nokta var. Birincisi, ingressClassName alanı yazılmalıdır; kümede birden fazla controller varsa hangisinin bu kuralı sahipleneceğini belirler. İkincisi, backend.service.port.number alanı Service'in portudur, Pod'un konteyner portu değil. Üçüncüsü, pathType alanı zorunludur:

    pathTypeDavranışÖrnek
    PrefixYol öğe öğe önek eşleşmesi/api/api/kullanicilar eşleşir
    ExactBirebir eşleşme/saglik → yalnızca tam bu yol
    ImplementationSpecificController'ın kendi kuralıRegex kullanımı gerektiğinde

    Uygulayıp doğrulama:

    kubectl apply -f ingress.yaml
    kubectl get ingress firmaniz-web
    # NAME           CLASS   HOSTS          ADDRESS         PORTS
    # firmaniz-web   nginx   firmaniz.com   185.12.34.56    80
    
    # Kural gerçekten arka uca bağlandı mı
    kubectl describe ingress firmaniz-web | tail -n 20
    
    # DNS'i beklemeden test et
    curl -H "Host: firmaniz.com" http://185.12.34.56/api/saglik
    

    describe çıktısında arka ucun karşısında <error: endpoints not found> yazıyorsa Service ya yok ya da hiçbir hazır Pod'a sahip değildir.

    TLS: Let's Encrypt ile Otomatik Sertifika#

    Sertifikayı Ingress'te sonlandırmak, her servise ayrı ayrı sertifika kurmaktan çok daha yönetilebilirdir. Kubernetes'te bunun standart yolu cert-manager'dır: sertifikayı alır, Secret olarak yazar ve süresi dolmadan yeniler.

    helm repo add jetstack https://charts.jetstack.io
    helm repo update
    helm install cert-manager jetstack/cert-manager \
      --namespace cert-manager --create-namespace \
      --set crds.enabled=true
    

    Ardından bir sertifika sağlayıcısı (issuer) tanımlarsın:

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt-prod
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email: [email protected]
        privateKeySecretRef:
          name: letsencrypt-prod-hesap
        solvers:
          - http01:
              ingress:
                ingressClassName: nginx
    

    Ingress kaynağına iki satır eklediğinde sertifika otomatik gelir:

    metadata:
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt-prod
        nginx.ingress.kubernetes.io/ssl-redirect: "true"
    spec:
      tls:
        - hosts:
            - firmaniz.com
          secretName: firmaniz-com-tls   # cert-manager bu Secret'ı kendisi oluşturur
    

    HTTP-01 doğrulaması, Let's Encrypt sunucularının senin alan adına 80 portundan ulaşabilmesini gerektirir. Alan adının DNS'i controller IP'sine bakmıyorsa ya da 80 portu güvenlik duvarında kapalıysa sertifika hiç gelmez. Sertifika sürecini izlemek için:

    kubectl get certificate
    kubectl describe certificate firmaniz-com-tls | tail -n 15
    kubectl get challenges -A
    

    Kendi kümeni kurmak yerine hazır bir sertifika çözümü arıyorsan SSL sertifikası sayfamızdaki seçenekler klasik sunucu kurulumları için doğrudan kullanılabilir.

    En Çok Kullanılan Annotation Ayarları#

    ingress-nginx davranışının çoğu annotation ile ayarlanır. Sık ihtiyaç duyduklarım:

    AnnotationNe yapar
    proxy-body-sizeYükleme boyutu sınırı (varsayılan 1 MB, dosya yüklemede mutlaka artır)
    proxy-read-timeoutArka uçtan yanıt bekleme süresi (uzun süren raporlar için)
    ssl-redirectHTTP isteklerini HTTPS'e yönlendirir
    backend-protocolArka uç HTTPS ya da gRPC konuşuyorsa belirtilir
    rewrite-targetYolun bir kısmını arka uca iletmeden keser
    limit-rpsSaniye başına istek sınırı
    whitelist-source-rangeYalnızca belirli IP bloklarına izin verir

    En sık karşılaşılan ve teşhisi zor hata proxy-body-size kaynaklıdır: kullanıcı 5 MB'lık bir görsel yükler, tarayıcıda 413 Request Entity Too Large görür, ama uygulama loglarında hiçbir kayıt yoktur — çünkü istek arka uca hiç ulaşmamıştır. Yönetim paneli olan her uygulamada bu değeri baştan makul bir seviyeye çekmek iyi bir alışkanlıktır.

    Hız sınırı ve IP kısıtlaması Ingress katmanında faydalıdır ama uygulama katmanı saldırılarına karşı tam bir çözüm değildir; ciddi hacimli trafiği önde emmek için DDoS koruma ve WAF katmanları farklı bir tehdit sınıfını karşılar.

    Sık Yapılan Hatalar ve Tuzaklar#

    1. Controller kurmadan Ingress kaynağı yazmak. En yaygın hata budur ve hiçbir hata mesajı üretmez; kubectl get ingress nesneyi gösterir ama ADDRESS sütunu boş kalır. Önce kubectl get ingressclass ile controller'ın varlığını doğrula.
    2. backend.service.port alanına konteyner portunu yazmak. Burada yazılması gereken Service'in port değeridir. Konteyner 8080'de dinlese bile Service 80'i açıyorsa Ingress'e 80 yazılır.
    3. Servisi farklı bir ad alanında aramak. Ingress yalnızca kendi ad alanındaki Service'lere yönlendirebilir. Uygulaman başka bir ad alanındaysa Ingress kaynağını da oraya koyman gerekir.
    4. pathType alanını atlamak. Zorunlu bir alandır; yazılmadığında API sunucusu kaynağı reddeder. Çoğu durumda doğru değer Prefix'tir.
    5. rewrite-target ile regex kullanırken pathType uyumsuzluğu. Yakalama gruplarıyla yeniden yazma yapıyorsan pathType: ImplementationSpecific gerekir; Prefix ile birlikte kullanıldığında yol beklenmedik biçimde iletilir.
    6. Kaynak IP kaybını fark etmemek. externalTrafficPolicy: Cluster varsayılanında uygulaman tüm istekleri düğüm IP'sinden geliyormuş gibi görür. Hız sınırı, coğrafi kural ve dolandırıcılık kontrolleri sessizce anlamsızlaşır.
    7. Sertifika Secret'ını elle silmek. cert-manager tarafından yönetilen TLS Secret'ını silersen sertifika yeniden istenir; sık tekrarlarsan Let's Encrypt oran sınırına takılır ve saatlerce sertifika alamazsın.

    Sıkça Sorulan Sorular#

    Ingress kurdum ama site açılmıyor, nereden başlamalıyım#

    Sırayla dört şeyi kontrol et: kubectl get ingressclass ile controller'ın gerçekten kurulu olduğunu, kubectl -n ingress-nginx get svc ile bir dış IP alındığını, alan adının DNS A kaydının bu IP'ye baktığını ve kubectl describe ingress çıktısında arka ucun uç noktalarının dolu olduğunu doğrula. Sorunların büyük çoğunluğu bu dördünden birinde çıkar.

    Bir kümede birden fazla Ingress controller çalışabilir mi#

    Evet, çalışabilir ve gerçek senaryolarda sık görülür; örneğin biri iç trafiğe, diğeri dışa açık trafiğe hizmet eder. Bu durumda her Ingress kaynağında ingressClassName alanını yazmak zorunludur, aksi hâlde kuralı hangi controller'ın sahipleneceği belirsiz kalır ve iki controller aynı kuralı işlemeye çalışabilir.

    Ingress ile LoadBalancer Service arasındaki fark nedir#

    LoadBalancer tipi Service, tek bir servisi bir IP üzerinden dışa açar ve HTTP içeriğine bakmaz. Ingress ise katman 7'de çalışır: aynı IP üzerinden alan adına ve yola göre farklı servislere yönlendirme yapar, TLS sonlandırır, yeniden yazma ve hız sınırı gibi kuralları uygular. Pratikte Ingress controller'ın kendisi bir LoadBalancer Service kullanır; fark, arkasında onlarca servisi tek noktadan yönetebilmesidir.

    Let's Encrypt sertifikası gelmiyor, sebebi ne olabilir#

    En sık sebep, doğrulama isteğinin alan adına ulaşamamasıdır: DNS kaydı controller IP'sine bakmıyordur ya da 80 portu güvenlik duvarında kapalıdır. kubectl get challenges -A komutu bekleyen doğrulamaları ve hata mesajını gösterir. İkinci sık sebep, test sırasında üretim sunucusunun oran sınırına takılmaktır; deneme yaparken Let's Encrypt'in staging sunucusunu kullanmak bunu önler.

    Kendi sunucumda EXTERNAL-IP pending kalıyor, ne yapmalıyım#

    Bare-metal kümelerde bulut sağlayıcısının yük dengeleyici bileşeni bulunmadığı için bu beklenen bir durumdur. Birden fazla düğümün varsa MetalLB kurarak kümeye IP dağıtma yeteneği kazandırabilirsin. Tek düğümlü küçük kurulumlarda ise controller'ı hostNetwork: true ile çalıştırmak en pratik yoldur; bu durumda dnsPolicy: ClusterFirstWithHostNet ayarını da vermeyi unutma.

    Dosya yüklerken 413 hatası alıyorum, nasıl çözerim#

    Bu hata Ingress controller'ın varsayılan istek gövdesi sınırından kaynaklanır. İlgili Ingress kaynağına nginx.ingress.kubernetes.io/proxy-body-size: "32m" gibi bir annotation ekleyerek sınırı yükseltebilirsin. Ayarı tüm küme için varsayılan yapmak istersen controller'ın ConfigMap'inde proxy-body-size değerini değiştirmen yeterlidir; ConfigMap kullanımı için ilgili rehbere bakabilirsin.

    Kapanış#

    Ingress, Kubernetes'te dışa açılan her şeyin tek kapısıdır ve doğru kurulduğunda hem maliyet hem yönetim yükü ciddi biçimde düşer. Aklında kalması gereken dört şey: Ingress kaynağı tek başına bir şey yapmaz, mutlaka bir controller kur; ingressClassName alanını her zaman yaz; sertifikayı cert-manager ile otomatikleştir ve elle yenileme yükünden kurtul; kendi sunucularında EXTERNAL-IP beklemede kalıyorsa eksik olan MetalLB ya da hostNetwork yapılandırmasıdır. Bir sorunda ilk bakılacak yer her zaman kubectl describe ingress çıktısıdır.

    Kubernetes altyapını kurarken ya da dışa açtığın servisleri güvenceye alırken Clou.TR tarafında destek alabilirsin. Küme düğümleri için bulut sunucu ve VDS paketlerimizi inceleyebilir, kurulum ve işletme yükünü devretmek istersen sunucu yönetimi hizmetimize göz atabilir, sertifika ve uygulama katmanı koruması için SSL ve WAF çözümlerimizi değerlendirebilirsin.

    KubernetesIngressNginx

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.