Ingress dans Kubernetes : exposer votre application

1. Aperçu général

Lorsque vous avez un Service qui s’exécute dans votre cluster mais que vous voulez que les utilisateurs externes y accèdent via un beau domaine comme api.nonladev.com au lieu d’une adresse IP:port chaotique, c’est là qu’Ingress entre en jeu. Cet article explique ce qu’est Ingress, comment il diffère d’un Service de type LoadBalancer, comment installer un Ingress Controller et écrire une ressource Ingress pour les cas courants : routing basé sur le chemin, routing basé sur l’hôte, TLS. Une fois que vous l’aurez lu, vous pourrez exposer votre propre application Spring Boot à l’extérieur avec un domaine et HTTPS.

2. Pourquoi avez-vous besoin d’Ingress

2.1. Problèmes avec le Service

Les types de Service NodePort ou LoadBalancer fonctionnent bien, mais ont des limitations :

  • LoadBalancer : chaque Service a besoin de sa propre adresse IP externe → cela coûte cher s’il y a plusieurs services (chaque load balancer cloud est facturé séparément).
  • NodePort : expose un port étrange (30000-32767), pas de terminaison TLS, pas de routage par domaine/chemin.

Supposons que vous ayez 5 microservices à exposer au monde extérieur. Utiliser LoadBalancer signifie 5 load balancers cloud, 5 adresses IP externes. Ingress résout ce problème en utilisant un seul point d’entrée pour router le trafic vers plusieurs Services à l’intérieur, basé sur le nom d’hôte ou le chemin.

2.2. Qu’est-ce qu’Ingress

Ingress est un objet API qui définit les règles de routage HTTP/HTTPS de l’extérieur vers un Service dans le cluster. Ingress ne fait rien par lui-même — il a besoin d’un Ingress Controller (un Pod exécutant un reverse proxy comme NGINX, Traefik, HAProxy) pour lire les règles et les appliquer.

Client → Ingress Controller (LoadBalancer/NodePort) → Ingress rules → Service → Pod

Remarque : Si votre cluster n’a pas encore installé d’Ingress Controller, créer une ressource Ingress ne servira à rien — ce n’est que de la configuration “en attente” que le controller va lire.

3. Installer Ingress Controller

Le plus populaire est ingress-nginx. Installez-le avec Helm :

<!-- non applicable — utiliser Helm/kubectl, pas une dépendance Maven -->
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

Cette commande crée l’espace de noms ingress-nginx, déploie l’Ingress Controller ainsi qu’un Service de type LoadBalancer pour recevoir le trafic de l’extérieur. Vérifiez :

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

Cette adresse IP externe est le point d’entrée unique pour tous les Ingress du cluster.

4. Déploiement et Service d’exemple

Avant d’écrire un Ingress, vous avez besoin d’un Service vers lequel router. Supposons une application 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

Le Service order-service expose le port 80 et le transfère au port 8080 du container. Notez que ce Service n’a pas besoin du type LoadBalancer, utiliser ClusterIP (par défaut) suffit, car l’Ingress Controller l’appellera via le réseau interne.

5. Ressource Ingress basique — routing basé sur l’hôte

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

Explication de chaque partie :

  • ingressClassName: nginx — spécifie quel controller traite cette règle (important quand le cluster a plusieurs controllers).
  • rules.host — seul le trafic avec l’en-tête Host: api.nonladev.com correspondra à cette règle.
  • path + pathType: Prefix — toute requête commençant par / (c’est-à-dire tout) sera transférée à order-service:80.
  • annotation rewrite-target — spécifique à ingress-nginx, utilisée pour réécrire l’URL avant de la transférer (l’annotation varie selon le controller).

Appliquez et testez :

kubectl apply -f order-ingress.yaml
curl -H "Host: api.nonladev.com" http://34.123.45.67/
{"service":"order-service","status":"UP"}

Dans un environnement réel, vous pointez le DNS record api.nonladev.com vers l’adresse IP externe du Controller Ingress, sans avoir besoin du header Host fictif comme ci-dessus.

6. Routing basé sur le chemin — plusieurs services partageant un domaine

Cas d’usage courant : un domaine, plusieurs services selon des chemins différents.

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

Une requête vers api.nonladev.com/orders/123 est routée vers order-service, tandis que /customers/55 est routée vers customer-service. pathType: Prefix signifie une correspondance par préfixe — différent de Exact (doit correspondre exactement) et de ImplementationSpecific (le controller l’interprète comme il le souhaite, souvent pour les regex).

Remarque : L’ordre des chemins n’affecte pas la correspondance dans Ingress v1 — le controller choisit le chemin le plus long qui correspond d’abord. Mais écrivez les chemins clairement, sans chevauchement, pour éviter les bugs difficiles à déboguer.

7. TLS — HTTPS pour Ingress

Pour avoir HTTPS, vous avez besoin d’un Secret contenant le certificat et la clé, puis le référencer dans Ingress.

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 déclare quel certificat utiliser pour quel hôte. Le controller gère automatiquement la terminaison TLS — il décode HTTPS à l’Ingress, puis transfère HTTP pur vers le Service à l’intérieur. Votre Pod n’a pas besoin de savoir quoi que ce soit sur TLS.

En pratique, vous utilisez généralement cert-manager pour demander automatiquement un certificat Let’s Encrypt au lieu de créer le Secret manuellement :

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

L’annotation cluster-issuer demande à cert-manager de créer et renouveler automatiquement le Secret nonladev-tls — aucune intervention manuelle supplémentaire n’est nécessaire.

8. Écrire des tests pour vérifier l’endpoint après exposition

Une fois qu’Ingress fonctionne, vous pouvez écrire un test d’intégration simple pour vérifier que votre classe controller traite correctement le chemin (testez au niveau de l’application Spring Boot, pas directement le YAML) :

@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");
    }
}

Ce test s’assure que votre application Spring Boot répond correctement au chemin /orders/123 qu’Ingress réécrira vers elle — en séparant les erreurs du code backend de celles de la configuration Ingress.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

9. Erreurs courantes

  • Oublier ingressClassName : si votre cluster a plusieurs Ingress Controllers (par exemple nginx et traefik), Ingress ne sait pas quel controller traiter → cela ne fonctionne pas ou est traité par erreur par les deux.
  • Type de Service incorrect : laisser le Service backend en LoadBalancer est inutile, gaspille les ressources — ClusterIP suffit.
  • pathType ne correspond pas aux attentes : utiliser Exact quand vous aviez besoin de Prefix cause des erreurs 404 sur les sous-chemins (/orders/123) puisque seul /orders correspond exactement.
  • DNS non configuré : testez avec curl -H "Host: ..." avant de configurer le vrai DNS, pour éviter de perdre du temps à attendre la propagation DNS.
  • Annotation rewrite incorrecte pour le controller : l’annotation ingress-nginx ne s’applique pas à Traefik ou AWS ALB Ingress Controller — chaque controller a son propre ensemble d’annotations, lisez attentivement la documentation correspondante.

Quand ne PAS utiliser Ingress : si votre application utilise un protocole autre que HTTP/HTTPS (par exemple TCP brut, streaming gRPC complexe, ou UDP), Ingress standard ne le supporte pas bien — envisagez Gateway API ou un Service de type LoadBalancer directement pour TCP/UDP.

10. Conclusion

Ingress est une couche de routage HTTP/HTTPS centralisée qui vous aide à exposer plusieurs Services vers l’extérieur via un unique point d’entrée, économisant les coûts de LoadBalancer et simplifiant la gestion des domaines/chemins/TLS. Les points clés à retenir : une ressource Ingress est juste une règle, il faut un Ingress Controller pour l’appliquer ; choisissez le correct ingressClassName et pathType ; utilisez cert-manager pour automatiser TLS. Pour les applications non-HTTP pures, envisagez Gateway API au lieu de forcer l’utilisation d’Ingress.

kubernetesingressnetworkingdevopsnginx