Ingress in Kubernetes: die Anwendung nach außen bringen
1. Übersicht
Wenn du einen Service im Cluster laufen hast, aber externe Benutzer über schöne Domain-Namen wie api.nonladev.com anstelle von durcheinander IP:Port erreichen möchten, ist es Zeit für Ingress. In diesem Artikel erklären wir, was Ingress ist, wie es sich vom Service-Typ LoadBalancer unterscheidet, wie man den Ingress Controller installiert und Ingress-Ressourcen für häufige Szenarien schreibt: pfadbasiertes Routing, hostbasiertes Routing, TLS. Nach dem Lesen kannst du selbst eine Spring-Boot-Anwendung über eine Domain und HTTPS nach außen bringen.
2. Warum brauchen Sie Ingress?
2.1. Probleme mit Service
Der Service-Typ NodePort oder LoadBalancer funktioniert gut, hat aber Einschränkungen:
LoadBalancer: jeder Service benötigt eine eigene externe IP → kostspielig bei mehreren Services (jeder Cloud-LB wird separat berechnet).NodePort: exponiert ungewöhnliche Ports (30000-32767), kein TLS-Termination, kein Routing nach Domain/Pfad.
Angenommen, Sie haben 5 Microservices, die nach außen exponiert werden müssen, dann bedeutet die Verwendung von LoadBalancer 5 Cloud-Load-Balancer und 5 externe IPs. Ingress löst dies, indem es einen Einstiegspunkt verwendet, um Traffic zu mehreren internen Services weiterzuleiten, basierend auf Hostname oder Pfad.
2.2. Was ist Ingress?
Ingress ist ein API-Objekt, das HTTP/HTTPS-Routing-Regeln von außen zu Services im Cluster definiert. Ingress macht selbst nichts — es benötigt einen Ingress Controller (einen Pod, der einen Reverse Proxy wie NGINX, Traefik, HAProxy ausführt), um die Regeln zu lesen und umzusetzen.
Client → Ingress Controller (LoadBalancer/NodePort) → Ingress-Regeln → Service → Pod
Hinweis: Wenn der Cluster noch keinen Ingress Controller installiert hat, hat die Erstellung einer Ingress-Ressource keine Auswirkung — sie ist nur eine Konfiguration, die darauf wartet, dass der Controller sie liest.
3. Installation des Ingress Controllers
Das gebräuchlichste ist ingress-nginx. Installation mit Helm:
<!-- nicht zutreffend — verwende Helm/kubectl, keine Maven-Abhängigkeit -->
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx --create-namespace
Dieser Befehl erstellt den Namespace ingress-nginx, deployed den Ingress Controller zusammen mit einem Service-Typ LoadBalancer, um Traffic von außen zu empfangen. Überprüfung:
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
NAME TYPE EXTERNAL-IP PORT(S)
ingress-nginx-controller LoadBalancer 34.123.45.67 80:31234/TCP,443:31235/TCP
Diese externe IP ist der einzige Einstiegspunkt für alle Ingress-Instanzen im Cluster.
4. Beispiel-Deployment und -Service
Bevor Sie Ingress schreiben, benötigen Sie einen Service zum Weiterleiten. Angenommen, die Anwendung order-service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 2
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: nonladev/order-service:1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
Der Service order-service exponiert Port 80 und leitet an Container-Port 8080 weiter. Beachten Sie, dass dieser Service nicht den Typ LoadBalancer benötigt, die Verwendung von ClusterIP (Standard) ist ausreichend, da der Ingress Controller den Service über das interne Netzwerk aufruft.
5. Einfache Ingress-Ressource — hostbasiertes Routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: api.nonladev.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
Erklärung jedes Teils:
ingressClassName: nginx— gibt an, welcher Controller diese Regel verarbeitet (wichtig, wenn der Cluster mehrere Controller hat).rules.host— nur Traffic mit HeaderHost: api.nonladev.compasst diese Regel.path+pathType: Prefix— jede Anfrage, die mit/beginnt (d. h. alle), wird anorder-service:80weitergeleitet.- Annotation
rewrite-target— spezifisch für ingress-nginx, wird verwendet, um URLs vor der Weiterleitung umzuschreiben (verschiedene Controller haben unterschiedliche Annotationen).
Anwendung und Test:
kubectl apply -f order-ingress.yaml
curl -H "Host: api.nonladev.com" http://34.123.45.67/
{"service":"order-service","status":"UP"}
In einer Produktionsumgebung richten Sie den DNS-Eintrag api.nonladev.com auf die externe IP des Ingress Controllers ein, anstatt den Header Host wie oben zu fälschen.
6. Pfadbasiertes Routing — mehrere Services nutzen die gleiche Domain
Häufiges Szenario: eine Domain, mehrere Services unter verschiedenen Pfaden.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-gateway-ingress
spec:
ingressClassName: nginx
rules:
- host: api.nonladev.com
http:
paths:
- path: /orders
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
- path: /customers
pathType: Prefix
backend:
service:
name: customer-service
port:
number: 80
Anfragen an api.nonladev.com/orders/123 werden an order-service weitergeleitet, während /customers/55 an customer-service weitergeleitet wird. pathType: Prefix bedeutet Präfix-Matching — anders als Exact (muss exakt übereinstimmen) und ImplementationSpecific (der Controller interpretiert es selbst, normalerweise für Regex).
Hinweis: Die Reihenfolge der Pfade beeinflusst nicht das Matching in Ingress v1 — der Controller wählt automatisch den längsten Pfad, der zuerst passt. Schreiben Sie aber Pfade klar auf, ohne Überlappungen, um schwer zu debuggende Fehler zu vermeiden.
7. TLS — HTTPS für Ingress
Für HTTPS benötigen Sie ein Secret mit Zertifikat und Schlüssel, das dann in Ingress referenziert wird.
kubectl create secret tls nonladev-tls \
--cert=tls.crt --key=tls.key
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress-tls
spec:
ingressClassName: nginx
tls:
- hosts:
- api.nonladev.com
secretName: nonladev-tls
rules:
- host: api.nonladev.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
spec.tls erklärt, welcher Host welches Zertifikat verwendet. Der Controller führt automatisch TLS-Termination durch — d. h. er entschlüsselt HTTPS bei Ingress und leitet dann reines HTTP an den internen Service weiter. Ihre Pods müssen nichts über TLS wissen.
In der Praxis verwenden Sie normalerweise cert-manager, um Zertifikate von Let’s Encrypt automatisch anzufordern, anstatt Secrets manuell zu erstellen:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: order-ingress-tls
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts:
- api.nonladev.com
secretName: nonladev-tls
rules:
- host: api.nonladev.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: order-service
port:
number: 80
Die Annotation cluster-issuer fordert cert-manager auf, das Secret nonladev-tls automatisch zu erstellen und zu erneuern — keine weiteren manuellen Schritte nötig.
8. Tests schreiben, um exponierte Endpoints zu überprüfen
Nach der Aktivierung von Ingress können Sie einfache Integrationstests schreiben, um zu überprüfen, dass die Controller-Klasse den Pfad korrekt verarbeitet (Tests auf Spring-Boot-Anwendungsebene, nicht direkt YAML testen):
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderControllerIT {
@Autowired
private TestRestTemplate restTemplate;
@Test
void shouldReturnOrderWhenCalledWithOrdersPrefix() {
ResponseEntity<String> response =
restTemplate.getForEntity("/orders/123", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).contains("orderId");
}
}
Dieser Test stellt sicher, dass die Spring-Boot-Anwendung korrekt auf den Pfad /orders/123 antwortet, den Ingress umschreibt — trennt Fehler im Backend-Code von Fehlern in der Ingress-Konfiguration.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
9. Häufige Fehler
ingressClassNamevergessen: Wenn der Cluster mehrere Ingress Controller hat (z. B. sowohl nginx als auch traefik), ist unklar, welcher Controller die Regel verarbeitet → funktioniert nicht oder wird von beiden falsch verarbeitet.- Falscher Service-Typ: Backend-Service als
LoadBalancerzu belassen ist nicht nötig und verschwendet Ressourcen — nurClusterIPist erforderlich. pathTypeerfüllt nicht die Erwartungen: Die Verwendung vonExact, wennPrefixbenötigt wird, führt zu 404 für Anfragen wie/orders/123, da nur/ordersexakt passt.- DNS nicht konfiguriert: Testen Sie mit
curl -H "Host: ...", bevor Sie das echte DNS einrichten, um nicht auf DNS-Propagierung zu warten. - Falsche Rewrite-Annotation für Controller: Annotationen von ingress-nginx funktionieren nicht mit Traefik oder AWS ALB Ingress Controller — jeder Controller hat seinen eigenen Satz von Annotationen, lesen Sie die entsprechende Dokumentation sorgfältig.
Wann sollten Sie Ingress NICHT verwenden: Wenn Ihre Anwendung ein anderes Protokoll als HTTP/HTTPS verwendet (z. B. Raw-TCP, komplexes gRPC-Streaming oder UDP), unterstützt Standard-Ingress dies nicht gut — betrachten Sie stattdessen
Gateway APIoder Service-TypLoadBalancerdirekt für TCP/UDP.
10. Fazit
Ingress ist eine zentralisierte HTTP/HTTPS-Routing-Schicht, mit der Sie mehrere Services über einen einzigen Einstiegspunkt nach außen exponieren, Load-Balancer-Kosten sparen und Domains/Pfade/TLS leicht verwalten können. Wichtige Punkte zum Merken: Ingress-Ressourcen sind nur Regeln, Sie benötigen einen Ingress Controller, um sie umzusetzen; wählen Sie die richtige ingressClassName und pathType; verwenden Sie cert-manager, um TLS zu automatisieren. Für nicht-HTTP-Anwendungen sollten Sie stattdessen die Gateway API in Betracht ziehen, anstatt Ingress zu erzwingen.