Aller au contenu
Conteneurs & Orchestration medium

Ingress Kubernetes : exposer vos applications HTTP/HTTPS

35 min de lecture

logo kubernetes

Un Ingress expose vos Services HTTP/HTTPS vers l'extérieur du cluster avec du routage par domaine et chemin. Au lieu de créer un LoadBalancer par application, vous centralisez l'entrée du trafic sur un point unique, avec gestion TLS intégrée. Ce guide vous montre comment configurer un Ingress fonctionnel.

  • Comprendre le rôle d'un Ingress et d'un Ingress Controller
  • Créer un Ingress avec ingressClassName
  • Configurer le routage par domaine et par chemin
  • Activer TLS avec cert-manager
  • Débugger les erreurs courantes

Les deux API coexistent dans le même cluster et peuvent être servies par le même contrôleur, elles ne s'excluent pas. La différence tient au périmètre couvert par la spécification : tout ce qu'Ingress ne sait pas exprimer (redirection, réécriture, découpage de trafic) passe par des annotations propriétaires, alors que Gateway API le décrit dans ses propres ressources. Le tableau suivant résume les critères qui pèsent au moment du choix.

CritèreIngressGateway API
StatutStable, gelé (pas d'évolution)Stable, en développement actif
Cas d'usageHTTP/HTTPS simple, routage host/pathHTTP/HTTPS avancé, gRPC, TCP, traffic splitting
PortabilitéDépend fortement des annotations du contrôleurPlus standardisé
Recommandation KubernetesMaintenu pour compatibilitéRecommandé pour nouveaux projets

En résumé : Ingress reste valide pour les cas simples. Pour du routage avancé ou un nouveau projet, préférez Gateway API.

Le trafic n'entre jamais dans un objet Ingress : il entre dans le Service du contrôleur, généralement de type LoadBalancer ou NodePort. Le contrôleur surveille en permanence les objets Ingress de tous les namespaces et régénère sa propre configuration à chaque changement, en quelques secondes. Le routage se fait ensuite en une seule traversée, sans rebond par l'API Kubernetes.

  1. L'utilisateur envoie une requête vers https://mon-app.example.com

  2. L'Ingress Controller intercepte la requête et consulte les règles définies dans les objets Ingress

  3. Le Controller route vers le Service correspondant au host et au path

  4. Le Service distribue aux Pods disponibles

  5. La réponse remonte via le même chemin

  • Cluster Kubernetes fonctionnel (Minikube, Kind, K3s, ou cloud)
  • kubectl configuré pour accéder au cluster
  • Un Ingress Controller installé (voir section suivante)
  • DNS ou /etc/hosts pour résoudre vos domaines de test

Vérifiez votre cluster :

Fenêtre de terminal
kubectl cluster-info

Un cluster peut héberger plusieurs contrôleurs en parallèle, chacun déclarant sa propre IngressClass. C'est ce qui rend une migration progressive possible : les Ingress migrés changent de ingressClassName, les autres continuent de fonctionner. Le tableau ci-dessous donne l'état de maintenance de chaque projet, critère décisif depuis l'archivage de ingress-nginx.

ControllerStatut 2026Points forts
ingress-nginx (projet communautaire)❌ Archivé depuis le 24 mars 2026Le plus répandu historiquement, beaucoup d'exemples, mais plus de correctifs CVE
NGINX Ingress Controller (NGINX Inc., commercial / open source distinct)✅ Activement maintenuProduit F5/NGINX, à ne pas confondre avec ingress-nginx
Traefik✅ Activement maintenuLéger, config dynamique, bon pour microservices, supporte aussi Gateway API
HAProxy Ingress✅ Activement maintenuPerformant, adapté aux charges élevées
Contour✅ Activement maintenuBasé sur Envoy, moderne, supporte Gateway API

Installation avec Helm (Traefik recommandé en 2026)

Section intitulée « Installation avec Helm (Traefik recommandé en 2026) »

Les exemples de ce guide utilisent Traefik comme contrôleur de référence : activement maintenu, livré par défaut sur k3d/k3s, et il supporte aussi Gateway API (chemin de migration cohérent).

Fenêtre de terminal
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install my-ingress traefik/traefik \
--namespace traefik \
--create-namespace

Vérifiez l'installation :

Fenêtre de terminal
kubectl get pods -n traefik
kubectl get svc -n traefik
kubectl get ingressclass

La sortie de kubectl get ingressclass doit afficher traefik, c'est le nom à utiliser dans ingressClassName plus loin.

Un Ingress ne pointe pas vers des Pods mais vers un Service, qui doit donc exister avant lui. Créer l'Ingress en premier ne produit aucune erreur : la ressource est acceptée, le contrôleur renvoie simplement du 503 tant que le backend est absent. On déploie donc l'application, puis le Service, puis l'Ingress.

Le manifeste ci-dessous crée le Deployment et son Service dans le même fichier, séparés par ---. Le port du Service (80) est celui que l'Ingress référencera ; le targetPort est celui qu'écoute le conteneur.

webapp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 2
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
containers:
- name: webapp
image: nginx:1.25.4
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: webapp-service
spec:
selector:
app: webapp
ports:
- protocol: TCP
port: 80
targetPort: 80
Fenêtre de terminal
kubectl apply -f webapp-deployment.yaml

La règle ci-dessous ne répond qu'aux requêtes portant l'en-tête Host: webapp.local : une requête sur l'IP nue tombera en 404.

webapp-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
spec:
ingressClassName: traefik
rules:
- host: webapp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-service
port:
number: 80
Fenêtre de terminal
kubectl apply -f webapp-ingress.yaml

Le test suppose deux choses : connaître l'adresse d'écoute du contrôleur et faire correspondre le nom de domaine à cette adresse, puisque c'est lui qui déclenche la règle.

Récupérez l'adresse du Controller :

Traefik est exposé par k3d via le LoadBalancer intégré, sur les ports 80 et 443 du host.

Fenêtre de terminal
# Vérifier le Service Traefik (namespace kube-system pour k3s)
kubectl get svc -n kube-system traefik

L'IP utile est 127.0.0.1 (le LB k3d le forward localement) ou l'IP du nœud (172.21.x.x).

Configurez la résolution DNS (fichier /etc/hosts) :

Fenêtre de terminal
# Remplacez par l'IP réelle de votre Controller
echo "127.0.0.1 webapp.local" | sudo tee -a /etc/hosts

Testez :

Fenêtre de terminal
curl -H "Host: webapp.local" http://127.0.0.1
# ou, après avoir mis à jour /etc/hosts :
curl http://webapp.local

Un même objet Ingress accepte plusieurs entrées host, chacune avec ses propres chemins. Regrouper les domaines dans une seule ressource garde la configuration lisible, mais tous les domaines partagent alors le même cycle de vie : supprimer l'Ingress coupe tout d'un coup. Sur des applications gérées par des équipes différentes, préférez un Ingress par application, ils peuvent viser le même contrôleur sans conflit.

multi-domain-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-app-ingress
spec:
ingressClassName: traefik
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-service
port:
number: 80
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80

Sous un même domaine, plusieurs chemins peuvent viser des Services distincts, ce qui permet d'exposer une API et son interface web sans sous-domaine dédié. Le chemin est transmis tel quel au backend : /api/users arrive en /api/users sur api-service, sauf réécriture explicite. Le path: / sert de règle par défaut pour tout ce qui ne correspond à aucun préfixe plus long.

path-routing-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-routing
spec:
ingressClassName: traefik
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80

Le champ tls d'un Ingress attend un Secret de type kubernetes.io/tls déjà présent dans le même namespace que l'Ingress. cert-manager automatise la création et le renouvellement de ce Secret : il observe les Ingress annotés, demande le certificat à l'autorité configurée et renouvelle par défaut à deux tiers de la durée de vie, soit environ 30 jours avant l'expiration pour Let's Encrypt.

Le guide dédié cert-manager détaille l'installation, les Issuer et les certificats Let's Encrypt. Installation rapide :

Fenêtre de terminal
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.20.3/cert-manager.yaml

Vérifiez l'installation :

Fenêtre de terminal
kubectl get pods -n cert-manager

Un ClusterIssuer est non namespacé : il sert tous les namespaces du cluster, contrairement à un Issuer. L'email reçoit les avertissements d'expiration de Let's Encrypt et le privateKeySecretRef désigne le Secret où cert-manager stocke la clé du compte ACME, à ne pas confondre avec le certificat lui-même.

cluster-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: votre-email@example.com
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
ingressClassName: traefik
Fenêtre de terminal
kubectl apply -f cluster-issuer.yaml

Le secretName désigne un Secret que vous n'avez pas besoin de créer : cert-manager le remplit après validation du challenge. Le nom de domaine du bloc tls doit être identique à celui de la règle rules, sinon le certificat émis ne couvrira pas le trafic servi.

secure-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: secure-ingress
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: traefik
tls:
- hosts:
- monsite.example.com
secretName: monsite-tls
rules:
- host: monsite.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-service
port:
number: 80
Fenêtre de terminal
kubectl apply -f secure-ingress.yaml
# Vérifier le certificat
kubectl get certificate
kubectl describe certificate monsite-tls

Tout ce que la spécification Ingress ne couvre pas, redirection HTTPS, filtrage d'IP, limites de taille, se règle par des annotations interprétées par le contrôleur. Une annotation inconnue est ignorée en silence : aucune erreur à l'apply, la fonctionnalité ne s'applique simplement jamais. C'est le premier réflexe de diagnostic quand un comportement attendu ne se produit pas après une migration de contrôleur.

Sans cette redirection, le site reste joignable en HTTP clair même quand le bloc tls est présent : activer TLS n'interdit pas le port 80.

Avec Traefik, la redirection HTTPS se configure via un Middleware (CRD Traefik) référencé par annotation :

# Middleware (à créer une fois)
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: redirect-https
spec:
redirectScheme:
scheme: https
permanent: true
---
# Ingress référençant le middleware
metadata:
annotations:
traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd

Le filtrage s'applique à l'IP source vue par le contrôleur : derrière un load balancer cloud qui ne préserve pas l'adresse d'origine, toutes les requêtes arrivent avec l'IP du load balancer et la règle bloque tout ou rien.

# Middleware
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: ip-allowlist
spec:
ipAllowList:
sourceRange:
- 192.168.1.0/24
- 10.0.0.0/8

Avec Traefik, ces réglages sont des EntryPoint options côté contrôleur, pas des annotations Ingress. Configurer dans les values Helm de Traefik :

ports:
web:
transport:
respondingTimeouts:
readTimeout: "60s"
writeTimeout: "60s"
idleTimeout: "180s"

Avec ingress-nginx, les anciennes annotations restent disponibles mais le projet n'est plus maintenu :

metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"

L'authentification basique protège une route par un couple identifiant/mot de passe stocké dans un Secret, sans toucher au code de l'application. Elle transite en clair si vous n'avez pas activé TLS sur la route : réservez-la aux interfaces d'administration déjà servies en HTTPS. Sous Traefik, elle passe par un Middleware référencé depuis l'Ingress, en trois temps.

  1. Créez le Secret avec le couple user/password

    Fenêtre de terminal
    htpasswd -c auth admin
    # Entrez le mot de passe
    kubectl create secret generic basic-auth --from-file=auth
  2. Créez un Middleware Traefik

    basic-auth-middleware.yaml
    apiVersion: traefik.io/v1alpha1
    kind: Middleware
    metadata:
    name: basic-auth
    spec:
    basicAuth:
    secret: basic-auth
    Fenêtre de terminal
    kubectl apply -f basic-auth-middleware.yaml
  3. Référencez le Middleware dans l'Ingress

    auth-ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: auth-ingress
    annotations:
    traefik.ingress.kubernetes.io/router.middlewares: default-basic-auth@kubernetescrd
    spec:
    ingressClassName: traefik
    rules:
    - host: admin.example.com
    http:
    paths:
    - path: /
    pathType: Prefix
    backend:
    service:
    name: admin-service
    port:
    number: 80

Quand l'URL exposée diffère de celle attendue par le backend (par exemple /api/users côté Ingress doit arriver en /users côté Service), il faut un Middleware côté Traefik. Le préfixe retiré n'est pas restitué au backend : une application qui génère des liens absolus renverra des URL sans le /api, et les redirections qu'elle émet casseront. C'est la raison pour laquelle la réécriture se paie souvent en configuration supplémentaire côté application.

rewrite-ingress.yaml
# Middleware de réécriture
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: api-strip
spec:
stripPrefix:
prefixes:
- /api
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rewrite-ingress
annotations:
traefik.ingress.kubernetes.io/router.middlewares: default-api-strip@kubernetescrd
spec:
ingressClassName: traefik
rules:
- host: myapp.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80

Effet : /api/users arrive en /users côté api-service.

Un Ingress qui ne fonctionne pas se diagnostique de l'extérieur vers l'intérieur : contrôleur joignable, règle reconnue, Service peuplé, Pods vivants. Le code HTTP renvoyé indique à quel étage la chaîne se rompt, ce qui évite de relire le YAML alors que le problème est un sélecteur de Service. Les commandes ci-dessous suivent cet ordre.

Le champ ADDRESS reste vide tant qu'aucun contrôleur n'a pris la ressource en charge : c'est le signe d'un ingressClassName erroné ou d'un contrôleur absent.

Fenêtre de terminal
# Liste des Ingress
kubectl get ingress
# Détails d'un Ingress
kubectl describe ingress webapp-ingress
# Adresse assignée ?
kubectl get ingress webapp-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Le contrôleur journalise le rechargement de sa configuration : si votre domaine n'apparaît jamais dans ses logs, il n'a pas retenu la règle et le problème se situe avant le routage.

Fenêtre de terminal
# Identifier le namespace du Controller (Traefik sur k3d/k3s : kube-system)
kubectl get pods -A | grep -iE 'traefik|ingress|haproxy|contour'
# Logs du Controller (adapter le namespace et le nom du deployment)
kubectl logs -n kube-system deploy/traefik --tail=100
# Événements du namespace
kubectl get events -n kube-system --sort-by=.lastTimestamp | tail -20

Le code renvoyé situe la panne : un 404 vient du contrôleur qui n'a trouvé aucune règle, un 502 ou 503 vient du contrôleur qui a trouvé la règle mais pas de backend joignable derrière.

ErreurCause probableSolution
404 Not FoundPas de règle correspondanteVérifiez host, path et Service
502 Bad GatewayService ou Pods inaccessiblesVérifiez endpoints et pods
503 Service UnavailableAucun Pod disponibleVérifiez kubectl get pods
Connection refusedController non exposéVérifiez le Service du Controller

Cette séquence remonte la chaîne maillon par maillon. L'étape des endpoints est celle qui révèle le plus d'erreurs : un Service sans endpoint signifie que son selector ne correspond à aucun label de Pod, et le YAML reste pourtant valide.

  1. L'Ingress existe-t-il ?

    Fenêtre de terminal
    kubectl get ingress webapp-ingress
  2. Le Service existe-t-il ?

    Fenêtre de terminal
    kubectl get svc webapp-service
  3. Le Service a-t-il des endpoints ?

    Fenêtre de terminal
    kubectl get endpoints webapp-service
  4. Les Pods sont-ils Running ?

    Fenêtre de terminal
    kubectl get pods -l app=webapp
  5. Le Controller voit-il l'Ingress ?

    Fenêtre de terminal
    # Adapter selon le contrôleur installé
    kubectl logs -n kube-system deploy/traefik | grep webapp

Ces règles répondent aux deux faiblesses structurelles de l'API Ingress : son absence de valeurs par défaut explicites et sa dépendance aux annotations. Les appliquer dès la première ressource évite d'avoir à démêler le comportement d'un cluster où plusieurs contrôleurs cohabitent.

Ces trois règles portent sur la prévisibilité : savoir quel contrôleur traite quelle ressource, et retrouver l'Ingress d'une application sans grep.

  1. Toujours spécifier ingressClassName, Évite les comportements imprévisibles
  2. Un Ingress par application, Plus facile à maintenir et débugger
  3. Nommage cohérent, <app>-ingress pour identifier facilement

Un Ingress est le point d'entrée public du cluster : ce qui n'y est pas filtré arrive jusqu'aux Pods. Les noms d'annotations cités ci-dessous sont ceux de ingress-nginx ; sous Traefik, les équivalents sont le Middleware ipAllowList et les respondingTimeouts de l'EntryPoint, décrits plus haut.

  1. Activez TLS, Utilisez cert-manager pour automatiser les certificats
  2. Restreignez les IPs, whitelist-source-range pour les routes sensibles
  3. Limitez la taille des requêtes, proxy-body-size pour éviter les abus

Le contrôleur concentre le trafic de toutes les applications exposées : sa panne les coupe toutes à la fois, d'où le besoin d'observabilité dédiée et d'un environnement de pré-production pour valider les annotations avant mise en ligne.

  1. Surveillez les logs du Controller, Configurez la collecte de logs
  2. Monitorez les métriques, La plupart des Controllers exposent des métriques Prometheus
  3. Testez en staging, Les annotations peuvent avoir des effets inattendus

Sept questions pour vérifier les points qui coûtent le plus cher en production : rôle du contrôleur, ingressClassName, pathType et diagnostic des codes d'erreur.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
90% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

ConceptDescription
IngressObjet qui définit les règles de routage HTTP/HTTPS
Ingress ControllerComposant qui implémente réellement le routage
ingressClassNameSpécifie quel Controller gère l'Ingress
rulesDéfinit le routage par host et path
tlsConfigure HTTPS avec un certificat
AnnotationsExtensions spécifiques au Controller (non portables)

Règle d'or : L'API Ingress est stable mais gelée. Pour les cas simples, elle reste parfaitement valide. Pour les besoins avancés ou les nouveaux projets, évaluez Gateway API.

Ces questions reviennent souvent quand on expose des applications web dans Kubernetes. Les réponses ci-dessous reprennent les points clés du guide, rôle de l'Ingress Controller, choix entre Ingress et Gateway API, configuration TLS et diagnostic des erreurs 404.

  • Network Policies : Le filtrage du trafic vers les Pods exposés par l'Ingress Controller.
  • Pod Networking : Le chemin réseau emprunté par une requête entre l'Ingress Controller et le Pod cible.
  • Troubleshooting cluster : La méthode pour remonter la chaîne quand une règle Ingress reste sans effet.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn