Cloud
Azure AKS : diagnostiquer un ingress privé avant de changer les déploiements
Construire un runbook opérationnel pour les pannes d'ingress privé AKS en séparant DNS, Application Gateway, ingress controller, services Kubernetes, endpoints, readiness des pods et preuves de rollback.
Une application AKS privée peut échouer à plusieurs endroits avant que la requête n’atteigne le conteneur. Le hostname peut encore résoudre publiquement, Application Gateway peut sonder le mauvais chemin, l’ingress controller peut ne pas recevoir la route, le service Kubernetes peut n’avoir aucun endpoint, ou les pods peuvent rester non ready après un déploiement. Vu de l’extérieur, beaucoup de ces situations ressemblent au même 502, timeout ou réponse vide.
Le cas d’usage est une API web interne hébergée sur AKS. Les clients internes appellent api.internal.example.com, le trafic entre par Application Gateway ou un autre edge privé, puis atteint un ingress controller dans le cluster. Une release vient de changer une règle ingress, un selector de service, une readiness probe ou une image de déploiement. Avant de scaler les pods, de modifier le WAF ou de rollback à l’aveugle, le runbook doit prouver où la requête s’arrête.
Dessiner le chemin AKS privé avant de toucher Kubernetes
AKS ajoute une couche cluster entre le réseau privé et le workload. Cette couche n’est utile en exploitation que si elle est observable : DNS, gateway, ingress controller, service, endpoint slices et readiness des pods doivent être lus comme un seul chemin.
Client interne
Résout api.internal.example.com
Appelle le hostname privé attendu
Edge privé
Application Gateway, private load balancer ou reverse proxy interne
Préserve le host header attendu
Exécute health probes et contrôles WAF éventuels
Ingress controller AKS
Reçoit la règle ingress pour le hostname et le chemin
Route le trafic vers un service Kubernetes
Service Kubernetes
Sélectionne les pods via labels
Publie des endpoint slices seulement quand les pods sont ready
Pods
Passent les readiness probes
Émettent des logs applicatifs
Joignent les dépendances privées via DNS, identité et network policy Cette carte évite une erreur opérationnelle fréquente : traiter une panne d’ingress comme un problème d’image. Si aucun endpoint n’existe derrière le service, le déploiement peut être sain mais le selector est faux. Si les probes gateway échouent avant que le controller voie du trafic, changer le pod ne servira à rien.
Séparer les symptômes gateway, ingress et service
La première étape de diagnostic est la qualification. Un problème de DNS privé, de health gateway, de règle ingress manquante et de service Kubernetes vide n’ont pas la même correction.
Symptôme
Le hostname résout vers une adresse publique ou inattendue
Vérifier zone DNS privée, liens VNet, forwarding resolver et cible du domaine personnalisé
Application Gateway retourne 502
Vérifier backend health, host header, TLS/SNI et probe path vers l'ingress controller
Les logs ingress controller ne montrent aucune requête
Vérifier routage gateway, NSG, private load balancer et adresse du service controller
Les logs ingress controller montrent des erreurs de route
Vérifier ingress class, host, path, secret TLS et nom du service backend
Le service Kubernetes n'a aucun endpoint
Vérifier selectors, readiness probes, namespace et labels des pods
Les pods reçoivent le trafic mais une dépendance échoue
Vérifier identité managée, DNS privé, network policy et firewalls aval La question utile n’est pas seulement : “les pods tournent-ils ?”. Elle devient : “le hostname privé exact atteint-il la règle ingress attendue, les endpoints de service et des pods ready ?”.
Prouver DNS et TLS depuis le réseau appelant
Commence depuis le même réseau que l’appelant réel, ou depuis un runner de diagnostic attaché à ce réseau. L’objectif est de capturer hostname, adresse finale et certificat avant d’entrer dans le cluster.
HOSTNAME=api.internal.example.com
nslookup "$HOSTNAME"
dig +short "$HOSTNAME"
ip=$(dig +short "$HOSTNAME" | tail -n 1)
case "$ip" in
10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.2*|172.30.*|172.31.*|192.168.*)
echo "private_resolution_ok=$ip"
;;
*)
echo "unexpected_public_or_empty_resolution=$ip"
exit 2
;;
esac
openssl s_client -connect "$HOSTNAME:443" -servername "$HOSTNAME" </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer Si ce test échoue, reste hors de Kubernetes. Corrige d’abord DNS privé, forwarding, liens de zones, configuration listener gateway ou binding certificat. Le cluster ne peut pas réparer un hostname qui résout au mauvais endroit.
Lire les objets Kubernetes dans l’ordre des dépendances
Dans le cluster, évite de sauter directement aux logs pods. Lis les objets de routage dans le même ordre que le trafic : ingress, service, endpoints, pods et événements récents.
NS=prod
INGRESS=orders-api
SERVICE=orders-api
APP_LABEL=orders-api
kubectl -n "$NS" describe ingress "$INGRESS"
kubectl -n "$NS" get ingress "$INGRESS" -o wide
kubectl -n "$NS" describe service "$SERVICE"
kubectl -n "$NS" get endpointslice -l kubernetes.io/service-name="$SERVICE" -o wide
kubectl -n "$NS" get pods -l app="$APP_LABEL" -o wide
kubectl -n "$NS" describe pods -l app="$APP_LABEL" | egrep -i 'Ready|Readiness|Warning|Failed|Unhealthy|Back-off' Un service sans endpoints signale souvent des labels ou une readiness incorrects. Un ingress qui pointe vers le mauvais service indique un problème de configuration controller. Des pods ready qui retournent des erreurs de dépendance déplacent le diagnostic vers identité, DNS ou services aval.
Corréler les logs ingress controller et pods
L’ingress controller contient souvent l’indice le plus utile : upstream indisponible, backend introuvable, mismatch TLS, timeout, path mismatch ou absence d’endpoints. Lis-le avec les logs applicatifs sur la même fenêtre d’incident.
let Window = 2h;
let Namespace = "prod";
let Host = "api.internal.example.com";
let ControllerLogs =
ContainerLogV2
| where TimeGenerated > ago(Window)
| where KubernetesNamespace has_any ("ingress", "ingress-nginx", "appgw")
| where LogMessage has_any (Host, "upstream", "no endpoints", "502", "timeout", "connect", "service")
| project TimeGenerated, Source="ingress-controller", PodName, KubernetesNamespace, LogMessage;
let AppLogs =
ContainerLogV2
| where TimeGenerated > ago(Window)
| where KubernetesNamespace == Namespace
| where LogMessage has_any ("error", "failed", "timeout", "dependency", "ready", "health")
| project TimeGenerated, Source="application", PodName, KubernetesNamespace, LogMessage;
ControllerLogs
| union AppLogs
| order by TimeGenerated desc La lecture rapide est directe : logs controller sans logs app oriente vers routage, service ou endpoints ; logs app sans erreur controller oriente vers workload ou dépendance ; aucun signal dans les deux vues renvoie vers gateway, DNS ou réseau appelant.
Garder un rollback borné
Le rollback doit cibler la couche qui a changé. Si la règle ingress a changé, restaure l’ingress. Si le selector de service a changé, restaure le selector. Si un déploiement a créé des pods non ready, rollback ce déploiement. Évite un rollback large qui masque la couche cassée.
NS=prod
DEPLOYMENT=orders-api
HOSTNAME=api.internal.example.com
CORRELATION_ID="ops-$(date +%Y%m%d%H%M%S)"
kubectl -n "$NS" rollout history deployment "$DEPLOYMENT"
kubectl -n "$NS" rollout undo deployment "$DEPLOYMENT"
kubectl -n "$NS" rollout status deployment "$DEPLOYMENT" --timeout=180s
curl -vk "https://$HOSTNAME/health" -H "x-correlation-id: $CORRELATION_ID"
echo "validate_correlation_id=$CORRELATION_ID" Si le rollback corrige l’appel, garde les preuves : replica set précédent, référence d’image, état ingress/service, correlation ID et heure de validation. Sans cette trace, le prochain incident repartira sur des hypothèses.
Conclusion
Un ingress privé AKS est fiable seulement si le chemin est lisible du edge réseau jusqu’au pod. DNS, Application Gateway, ingress controller, endpoints de service Kubernetes, readiness et logs applicatifs doivent être séparés avant de choisir une correction.
La règle pratique est simple : ne pas changer les déploiements tant que la requête n’a pas atteint le cluster, ne pas modifier WAF ou gateway tant que le chemin controller n’est pas visible, et ne pas rollback une image quand le service n’a aucun endpoint. Avec cette discipline, un incident AKS privé devient un diagnostic borné plutôt qu’une urgence de déploiement bruyante.