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 IP | Her servise bir tane | Hepsine tek tane |
| Alan adına göre yönlendirme | Yok | Var |
Yola göre yönlendirme (/api) | Yok | Var |
| TLS sonlandırma | Servisin kendisi yapar | Merkezî, tek yerden |
| Yeniden yazma, yönlendirme, hız sınırı | Yok | Annotation ile |
| TCP/UDP servisleri | Destekler | HTTP/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öntem | Nasıl çalışır | Ne zaman uygun |
|---|---|---|
| MetalLB | Kümeye yük dengeleyici yeteneği ekler, havuzdan IP dağıtır | Birden fazla düğümlü kendi kümen |
hostNetwork: true | Controller Pod'u doğrudan düğümün 80/443 portlarını dinler | Tek veya iki düğümlü küçük küme |
NodePort + dış proxy | Önde ayrı bir Nginx/HAProxy trafiği düğümlere dağıtır | Zaten 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:
| pathType | Davranış | Örnek |
|---|---|---|
Prefix | Yol öğe öğe önek eşleşmesi | /api → /api/kullanicilar eşleşir |
Exact | Birebir eşleşme | /saglik → yalnızca tam bu yol |
ImplementationSpecific | Controller'ı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:
| Annotation | Ne yapar |
|---|---|
proxy-body-size | Yükleme boyutu sınırı (varsayılan 1 MB, dosya yüklemede mutlaka artır) |
proxy-read-timeout | Arka uçtan yanıt bekleme süresi (uzun süren raporlar için) |
ssl-redirect | HTTP isteklerini HTTPS'e yönlendirir |
backend-protocol | Arka uç HTTPS ya da gRPC konuşuyorsa belirtilir |
rewrite-target | Yolun bir kısmını arka uca iletmeden keser |
limit-rps | Saniye başına istek sınırı |
whitelist-source-range | Yalnı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#
- Controller kurmadan Ingress kaynağı yazmak. En yaygın hata budur ve hiçbir hata mesajı üretmez;
kubectl get ingressnesneyi gösterir amaADDRESSsütunu boş kalır. Öncekubectl get ingressclassile controller'ın varlığını doğrula. backend.service.portalanına konteyner portunu yazmak. Burada yazılması gereken Service'inportdeğeridir. Konteyner 8080'de dinlese bile Service 80'i açıyorsa Ingress'e 80 yazılır.- 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.
pathTypealanını atlamak. Zorunlu bir alandır; yazılmadığında API sunucusu kaynağı reddeder. Çoğu durumda doğru değerPrefix'tir.rewrite-targetile regex kullanırkenpathTypeuyumsuzluğu. Yakalama gruplarıyla yeniden yazma yapıyorsanpathType: ImplementationSpecificgerekir;Prefixile birlikte kullanıldığında yol beklenmedik biçimde iletilir.- Kaynak IP kaybını fark etmemek.
externalTrafficPolicy: Clustervarsayı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. - Sertifika Secret'ını elle silmek.
cert-managertarafı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.