E-NO
Guide technique 7 min de lecture

Erreurs Kubernetes Ingress : guide pratique de dépannage avec commandes réelles

calendar_today Publié : 2026-07-10
update Dernière mise à jour : 2026-07-24
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Erreurs Kubernetes Ingress : guide pratique de dépannage avec commandes réelles ».

Introduction

Ingress achemine le trafic HTTP(S) externe vers des Services à l’intérieur de votre cluster, mais la ressource Ingress seule n’expose rien. Une requête qui fonctionne traverse plusieurs couches qui doivent toutes être saines. La plupart des erreurs Kubernetes Ingress ne viennent pas d’un simple champ YAML isolé ; ce sont des pannes le long du chemin de requête à travers DNS, équilibreurs de charge, contrôleurs, Services, endpoints et Pods applicatifs.

Dépannez en testant chaque saut dans l’ordre, pas en modifiant des manifestes au hasard.

Client
  |
 DNS
  |
IP externe / Load Balancer
  |
Service du contrôleur Ingress
  |
Pod du contrôleur Ingress
  |
Règle Ingress
  |
Service applicatif
  |
EndpointSlice
  |
Pod applicatif

Ce que vous allez apprendre :

  • Comment vérifier chaque couche avec des commandes concrètes.
  • Comment diagnostiquer les erreurs Kubernetes Ingress 404/502/503/504 et TLS.
  • Comment séparer l’API Ingress de l’implémentation du contrôleur.

Concept clé : un Ingress est une configuration consommée par un contrôleur Ingress. Créer une ressource Ingress n’installe ni ne configure de contrôleur.

Construire un exemple minimal fonctionnel

Enregistrez le fichier suivant sous example.yaml. Il crée un namespace, un Deployment HTTP d’écho simple, un Service ClusterIP et un Ingress avec routage par hôte sur le chemin "/" en pathType: Prefix. Adaptez <namespace> et <host>.

apiVersion: v1
kind: Namespace
metadata:
  name: <namespace>
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo
  namespace: <namespace>
spec:
  replicas: 2
  selector:
    matchLabels:
      app: echo
  template:
    metadata:
      labels:
        app: echo
    spec:
      containers:
        - name: echo
          image: hashicorp/http-echo:0.2.3
          args: ["-text=ok"]
          ports:
            - containerPort: 5678
---
apiVersion: v1
kind: Service
metadata:
  name: echo-svc
  namespace: <namespace>
spec:
  selector:
    app: echo
  ports:
    - name: http
      port: 80
      targetPort: 5678
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: echo
  namespace: <namespace>
spec:
  ingressClassName: nginx
  rules:
    - host: <host>
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: echo-svc
                port:
                  number: 80

Appliquez et inspectez :

kubectl apply -f example.yaml
kubectl get pods,svc,ingress -n <namespace>
kubectl describe ingress echo -n <namespace>

Signes de bonne santé :

  • Pods Ready=1/1 et STATUS=Running.
  • Le Service a une ClusterIP stable et un mapping 80 -> 5678.
  • L’Ingress affiche une ADDRESS (IP externe ou nom d’hôte) après son approvisionnement par le contrôleur.

Commencez par le chemin de requête

Utilisez ce tableau express pour tester chaque couche de manière délibérée.

CoucheSymptôme typiqueCommande de diagnosticSuccès attenduCorrectif probable
DNSL’hôte ne se résout pas<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">dig +short <host></code>Renvoie une IP ou un nom d’hôte LBCréer/ajuster un enregistrement A/AAAA/CNAME
Load Balancer externeConnexion refusée/timeout<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">curl -v http://<host>/</code>Connexion TCP réussieApprovisionner le LB, ouvrir pare-feu/SG, attendre l’approvisionnement
Service du contrôleurADDRESS vide dans l’Ingress<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get svc -A</code>Le Service du contrôleur a une EXTERNAL-IP ou un NodePortConfigurer le type de Service, corriger l’intégration cloud/LB
Pods du contrôleur503/timeout<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get pods -A</code>Pods du contrôleur Running/ReadyInstaller/réparer le contrôleur
IngressClassIngress ignoré<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get ingressclass</code>La classe correspondante existe et est par défaut ou nommée dans le specRenseigner correctement <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">spec.ingressClassName</code>
Ressource Ingress404 du backend par défaut<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl describe ingress</code>Accepté, règles listées, pas d’erreursCorriger hôte/chemin, annotations, classe
Service backend502/503<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get svc <svc> -o yaml</code>Port/sélecteur correctsCorriger nom/port/sélecteur
EndpointSlice503/504<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get endpointslice -l kubernetes.io/service-name=<svc> -n <ns></code>Adresses avec Ready=trueCorriger le sélecteur, readiness des Pods
Pods applicatifs502/504<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl describe pod <pod></code>Ready, écoute sur 0.0.0.0Corriger probes, adresse d’écoute, arguments du conteneur
TLSAvertissements navigateur<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">openssl s_client -connect <host>:443 -servername <host></code>Certificat correspondant à l’hôte, non expiréCorriger Secret, SAN, chaîne
Réponse de l’app404 applicatif<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">curl -v -H "Host: <host>" http://<ingress-ip>/</code>En-têtes/corps de l’app attendusCorriger routes ou réécritures de l’app

Erreur 1 : aucun contrôleur Ingress n’est installé

Un objet Ingress n’est qu’une configuration. Sans contrôleur, rien n’écoute.

kubectl get pods -A | grep -E "ingress|traefik|haproxy|alb|gateway"
kubectl get deployments -A | grep -E "ingress|traefik|haproxy|alb|gateway"
kubectl get ingressclass

Cherchez ingress-nginx, Traefik, HAProxy ou le contrôleur de votre fournisseur cloud. L’installation diffère selon bare metal, minikube/kind, Kubernetes managé et machines virtuelles. Utilisez la méthode documentée de votre plateforme.

Erreur 2 : IngressClass manquante ou incorrecte

Le contrôleur qui traite votre Ingress est choisi par spec.ingressClassName ou par l’IngressClass par défaut du cluster.

kubectl get ingressclass
kubectl describe ingressclass <class-name>
kubectl get ingress echo -n <namespace> -o yaml

Exemple de spec :

spec:
  ingressClassName: nginx

Utilisez le nom de classe annoncé par votre contrôleur ; les noms sont spécifiques à l’implémentation.

Erreur 3 : l’Ingress n’a pas d’adresse externe

kubectl get ingress -A affiche une ADDRESS vide lorsque :

  • Aucun contrôleur ne gère la ressource.
  • Le Service du contrôleur n’a pas d’EXTERNAL-IP (<pending>).
  • L’équilibreur de charge est encore en cours d’approvisionnement ou n’est pas pris en charge par votre infra.
  • L’intégration LoadBalancer sur bare metal (p. ex. MetalLB) est absente/mal configurée.
  • Le contrôleur est exposé via NodePort à la place.

Vérifiez :

kubectl get svc -A
kubectl describe svc <controller-service> -n <controller-namespace>
kubectl get events -A --sort-by=.metadata.creationTimestamp

Si EXTERNAL-IP est <pending>, résolvez d’abord le problème du Service ou de l’infrastructure.

Erreur 4 : le DNS ne pointe pas vers l’endpoint Ingress

Validez DNS et le routage par hôte :

dig +short <host>
nslookup <host>
curl -v http://<host>/

Pour contourner le DNS tout en conservant l’en-tête Host :

curl -v --resolve <host>:80:<ingress-ip> http://<host>/
curl -vk --resolve <host>:443:<ingress-ip> https://<host>/

--resolve prouve que l’Ingress et le backend fonctionnent même si le DNS public est erroné.

Erreur 5 : le backend par défaut renvoie 404

Un 404 généré par le contrôleur signifie généralement que l’hôte ou le chemin ne correspond à aucune règle, ou que le mauvais contrôleur a traité la requête.

curl -v -H "Host: <host>" http://<ingress-ip>/
kubectl describe ingress <name> -n <namespace>
kubectl get ingress <name> -n <namespace> -o yaml

Faites la différence :

  • 404 Ingress : les en-têtes incluent souvent des identifiants propres au contrôleur (p. ex. nginx). Corrigez hôte/chemin, classe ou annotations.
  • 404 applicatif : la requête est arrivée à votre app ; adaptez le routage applicatif.

Erreur 6 : correspondance de chemin et réécritures

  • pathType: Prefix correspond à /api et /api/v1.
  • pathType: Exact correspond au chemin littéralement.
  • ImplementationSpecific dépend du contrôleur et n’est pas portable.

Exemple standard sans réécriture :

paths:
  - path: /
    pathType: Prefix
    backend:
      service:
        name: echo-svc
        port:
          number: 80

Exemple spécifique à ingress-nginx (non portable) pour réécriture :

metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /

N’appliquez pas des annotations nginx à Traefik, HAProxy ou aux contrôleurs cloud.

Erreur 7 : mauvais nom ou port de Service

Le backend Ingress doit référencer le port du Service, pas le containerPort du Pod.

backend:
  service:
    name: api-service
    port:
      number: 8080

Vérifiez les correspondances et les noms :

kubectl get svc <service-name> -n <namespace> -o yaml
kubectl describe svc <service-name> -n <namespace>
kubectl get deployment <deployment-name> -n <namespace> -o yaml

Service.port mappe vers Service.targetPort, qui mappe vers le containerPort (ou un port nommé) dans le Pod.

Erreur 8 : le Service n’a pas d’endpoints

Un Service peut exister avec zéro endpoint prêt. Confirmez :

kubectl get endpoints <service-name> -n <namespace>
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name>
kubectl describe svc <service-name> -n <namespace>
kubectl get pods -n <namespace> --show-labels

Causes courantes :

  • Le sélecteur ne correspond pas aux labels des Pods.
  • Les Pods ne sont pas Ready (probes en échec).
  • Les Pods se terminent ou sont dans un autre namespace.

Alignez les sélecteurs avec les labels ; l’Ingress ne peut pas référencer des Services d’un autre namespace via le backend standard.

Erreur 9 : Pods en exécution mais non Ready

Running ne signifie pas routable. Inspectez les probes et les logs :

kubectl get pods -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>

Exemple de readiness probe :

readinessProbe:
  httpGet:
    path: /healthz
    port: 5678
  initialDelaySeconds: 2
  periodSeconds: 5

Assurez-vous que l’app écoute sur 0.0.0.0, pas sur 127.0.0.1.

Erreurs 10–12 : 502, 503, 504

  • 502 Bad Gateway : souvent targetPort erroné, backend qui refuse la connexion, confusion HTTP vs HTTPS.
  • 503 Service Unavailable : aucun endpoint prêt, Service backend manquant ou erreurs de rechargement du contrôleur.
  • 504 Gateway Timeout : application lente, dépendances en latence, NetworkPolicy bloquante ou délais d’expiration du contrôleur trop courts.

Testez le Service depuis le cluster pour isoler Ingress vs backend :

kubectl run curl-test --rm -it --restart=Never \
  --image=curlimages/curl -n <namespace> -- \
  curl -v http://<service-name>:<port>/

Si ce test réussit mais échoue via l’Ingress, concentrez-vous sur le contrôleur, les règles de routage ou la configuration protocole/TLS.

Erreurs TLS : Secrets et certificats

TLS requiert un Secret de type kubernetes.io/tls dans le même namespace que l’Ingress. Les hôtes doivent correspondre aux SAN du certificat.

spec:
  tls:
    - hosts:
        - app.example.com
      secretName: app-example-tls

Validez :

kubectl get secret app-example-tls -n <namespace>
kubectl describe ingress <name> -n <namespace>
openssl s_client -connect <host>:443 -servername <host> | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

Vérifiez l’expiration, la complétude de la chaîne et le nom d’hôte correct.

Ça marche en port-forward mais pas via Ingress

kubectl port-forward deployment/<deployment> 8080:<container-port> prouve que le Pod écoute et répond. kubectl port-forward service/<service> 8080:<service-port> prouve que le Service route vers des endpoints. Si les deux fonctionnent mais pas la route publique, concentrez-vous sur le contrôleur, le DNS, TLS ou le réseau externe.

Logs du contrôleur et configuration générée

Identifiez les Pods du contrôleur de manière générique :

kubectl get pods -A -l app.kubernetes.io/component=controller

Ensuite, inspectez les logs dans le bon namespace. Exemple (ingress-nginx uniquement) :

kubectl -n ingress-nginx logs deploy/ingress-nginx-controller

Cherchez des erreurs d’admission, des rechargements de configuration et des messages de santé des upstreams.

Un flux de dépannage discipliné

  1. Confirmer le DNS : dig +short <host>.
  2. Confirmer l’accessibilité externe : curl -v http(s)://<host>/.
  3. Contrôleur installé et Ready : kubectl get deployments,pods -A.
  4. IngressClass correcte : kubectl get ingressclass et spec.ingressClassName de l’Ingress.
  5. Inspecter l’Ingress et les événements : kubectl describe ingress.
  6. Tester hôte/chemin : curl -v -H "Host: <host>" http://<ingress-ip>/.
  7. Vérifier nom et port du Service : kubectl describe svc.
  8. EndpointSlices en Ready : kubectl get endpointslice.
  9. Tester dans le cluster : kubectl run ... curl http://<svc>:<port>/.
  10. Consulter les logs du contrôleur.
  11. Consulter les logs et probes de l’application.
  12. Valider le Secret TLS et le nom d’hôte du certificat.
  13. Examiner NetworkPolicies/pare-feu.
  14. Re-tester depuis l’extérieur.

Incident pratique de bout en bout

Symptôme (exemple de sortie) :

  • curl -v https://app.example.com/ renvoie 503.

Éléments observés :

kubectl get ingress echo -n demo
# ADDRESS renseignée ; règles OK
kubectl get svc echo-svc -n demo
# Port 80 -> 5678
kubectl get endpointslice -n demo -l kubernetes.io/service-name=echo-svc
# Aucun endpoint listé
kubectl get deploy echo -n demo -o yaml | grep labels -A2
# Pods du Deployment labellisés app=echo-app (décalage !)

Cause racine : le sélecteur du Service app=echo ne correspond pas au label des Pods app=echo-app, donc zéro endpoint prêt.

Correctif (aligner les labels) :

spec:
  selector:
    matchLabels:
      app: echo
  template:
    metadata:
      labels:
        app: echo

Validation :

kubectl apply -f deployment.yaml
kubectl get endpointslice -n demo -l kubernetes.io/service-name=echo-svc
# Des endpoints sont maintenant présents
curl -v https://app.example.com/
# 200 OK

Prévention : alertez sur les Services sans endpoints prêts ; validez les sélecteurs en CI ; testez les routes après déploiement.

Tableau de décision express

SymptômeCouche la plus probablePremière commandeCause fréquenteProchaine action
Échec DNSDNS<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">dig +short <host></code>Enregistrement manquant/obsolèteCorriger A/AAAA/CNAME
Connexion refuséeLB/Service<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">curl -v http://<host>/</code>LB non prêt, pare-feuVérifier LB, ouvrir les ports
TimeoutLB/Contrôleur/App<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">curl -v</code> + logs du contrôleurNetworkPolicy, app lenteTester le Service en cluster
404 contrôleurRègle Ingress<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl describe ingress</code>Hôte/chemin non concordantsCorriger règle/pathType
404 applicatifApp<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">curl -v</code> + en-têtesRoute app manquanteCorriger routes applicatives
502BackendCurl en cluster vers ServiceMauvais targetPort/protocoleAligner ports/protocoles
503Endpoints<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get endpointslice</code>Aucun endpoint prêtCorriger sélecteur/probes
504App/dépendancesLogs/metrics appBackend lentOptimiser ou ajuster timeouts
Alerte TLSTLS<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">openssl s_client ...</code>Nom/expiry/chaîneCorriger Secret/certificat
Mauvais certificatTLS/SNI<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">openssl s_client -servername</code>Hôte non concordantFournir un cert par hôte
Boucle de redirectionProxy/app<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">curl -IL</code>Protocole/en-têtesFaire confiance à X-Forwarded-Proto, corriger redirs
Adresse externe videInfra<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">kubectl get svc -A</code>LB en pendingConfigurer LB/NodePort
OK par IP seulementRègle Ingress<code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">curl --resolve</code>Hôte non concordantCorriger règles d’hôte

Ingress versus Gateway API

Ingress reste largement utilisé. Gateway API offre un routage plus riche et une meilleure séparation des rôles, mais nécessite toujours un contrôleur compatible et la même discipline de dépannage à travers DNS, Services, EndpointSlices, Pods et TLS. Migrer n’élimine pas ces fondamentaux.

Liste de contrôle finale de dépannage

  • Contrôleur installé et Pods en Ready
  • Service du contrôleur joignable (EXTERNAL-IP/NodePort)
  • spec.ingressClassName correct
  • DNS résout vers l’endpoint Ingress
  • Règles d’hôte et de chemin correctes, bon pathType
  • Nom et port du Service corrects
  • Sélecteur du Service correspondant aux labels des Pods
  • EndpointSlices contenant des adresses en Ready
  • Application à l’écoute sur 0.0.0.0
  • Secret TLS présent dans le même namespace ; certificat valide et correspondant au nom d’hôte
  • NetworkPolicy/pare-feu autorisant contrôleur <-> Pods et externe <-> contrôleur
  • Logs du contrôleur et de l’application examinés

Conclusion

La plupart des erreurs Kubernetes Ingress ne sont pas des fautes de frappe YAML ; ce sont des maillons rompus sur le chemin de la requête. Commencez par le DNS et l’endpoint externe, poursuivez via le contrôleur et les règles Ingress, et terminez au niveau du Service, des EndpointSlices et des Pods. Distinguez les 404 du contrôleur des 404 applicatifs, et validez TLS sans deviner. Des correctifs fiables viennent de l’isolation de la couche en échec, de la preuve de chaque saut avec des commandes, puis seulement des changements de configuration.

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO