Cloud
Azure Container Apps : diagnostiquer un ingress privé avant de changer les révisions
Construire un runbook opérationnel pour les pannes d'ingress privé Azure Container Apps en séparant DNS, mode d'ingress, routage des révisions, logs applicatifs et preuves de rollback.
Azure Container Apps est souvent utilisé comme point d’accueil pratique pour des API internes, des backends légers ou des services événementiels. La difficulté opérationnelle commence quand un private endpoint, un environnement interne, Application Gateway, le forwarding DNS et le trafic entre révisions se retrouvent sur le même chemin de requête. Un 404, un 502, une réponse vide ou une panne intermittente peut ressembler à un bug applicatif alors que le vrai sujet est un hostname, un mode d’ingress, un routage de révision ou un enregistrement DNS privé.
Le cas d’usage est une API privée hébergée sur Azure Container Apps. Les clients internes appellent un hostname lisible, le trafic peut entrer par Application Gateway, et la container app expose un ingress interne dans un environnement Container Apps. Une nouvelle révision vient d’être déployée, ou un changement private endpoint/DNS vient d’être appliqué. Avant de faire un rollback à l’aveugle ou de modifier les poids de trafic, le runbook doit prouver quelle couche échoue.
Décrire le chemin privé comme un objet d’exploitation
Un chemin privé Container Apps comporte plus de pièces mobiles que le code applicatif ne le laisse penser. L’environnement peut être interne. L’application peut exposer un ingress interne ou externe. Un private endpoint peut être utilisé pour l’environnement. Un domaine personnalisé peut pointer vers Application Gateway ou vers le FQDN de l’environnement Container Apps. Dans l’environnement, le trafic passe par le proxy de la plateforme avant d’atteindre une ou plusieurs révisions.
Client interne
Résout api.internal.example.com
Appelle le hostname privé attendu
Application Gateway éventuelle
Termine TLS ou transmet avec le host header configuré
Applique WAF et health probes
Envoie le trafic vers le chemin Container Apps
Environnement Container Apps
Expose un private endpoint ou un chemin internal load balancer
Résout le domaine d'environnement via DNS privé
Route le trafic via le proxy d'ingress plateforme
Container app
Accepte l'ingress interne sur le target port configuré
Répartit le trafic entre révisions actives
Émet des logs system et console
Dépendances backend
Exigent DNS privé, identité, secrets ou accès managé Cette carte évite la première erreur classique : traiter chaque requête en échec comme une révision cassée. Si le hostname résout encore en public, si les health probes Application Gateway échouent ou si le trafic n’atteint jamais l’environnement Container Apps, changer une révision ne fera qu’ajouter du bruit.
Séparer DNS, ingress et symptômes de révision
Le runbook doit qualifier le symptôme avant toute modification. Un enregistrement DNS manquant n’appelle pas un rollback. Une révision qui crash, oui. Un traffic split qui pointe vers une révision dégradée demande un déplacement contrôlé, pas une exception WAF.
Symptôme
Le hostname résout vers une adresse publique
Vérifier zone DNS privée, lien VNet, règle de forwarding et cible du domaine personnalisé
Application Gateway retourne 502
Vérifier backend health, host header, TLS/SNI et probe path vers Container Apps
La requête atteint Container Apps mais retourne 404
Vérifier ingress type, target port, custom domain binding, path routing et label de révision
La requête est intermittente
Vérifier révisions actives, poids de trafic, redémarrages de replicas et événements de scale
La requête atteint l'app mais une dépendance échoue
Vérifier identité managée, DNS privé, Key Vault ou firewall du service aval La question utile n’est pas seulement : “l’application est-elle up ?”. Elle devient : “ce hostname exact atteint-il l’environnement attendu, la configuration d’ingress attendue et la révision attendue ?”.
Prouver le DNS privé avant de diagnostiquer le conteneur
Pars du même réseau que les vrais clients. Si le runner de diagnostic est hors du chemin privé, il peut produire un résultat propre alors que la production échoue, ou l’inverse. Le premier contrôle doit capturer hostname, chaîne CNAME et adresse finale.
HOSTNAME=api.internal.example.com
nslookup "$HOSTNAME"
dig +short "$HOSTNAME"
a=$(dig +short "$HOSTNAME" | tail -n 1)
case "$a" in
10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.2*|172.30.*|172.31.*|192.168.*)
echo "private_resolution_ok=$a"
;;
*)
echo "unexpected_public_or_empty_resolution=$a"
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, la correction doit rester à la couche DNS ou private endpoint : enregistrements de zone privée, liens VNet, forwarding resolver ou cible du domaine personnalisé. Une nouvelle image de conteneur ne réparera pas un chemin de résolution.
Lire ensemble les logs system et console Container Apps
Container Apps expose deux vues Log Analytics utiles : les logs system pour les événements de plateforme, et les logs console pour stdout/stderr applicatifs. Pendant un incident d’ingress, regarder seulement les logs applicatifs est trop étroit. La plateforme indique peut-être déjà qu’une révision provisionne, se désactive, échoue sur ses probes ou ne reçoit aucun trafic.
let Window = 2h;
let App = "orders-api";
let Env = "aca-prod-weu";
let System =
ContainerAppSystemLogs_CL
| where TimeGenerated > ago(Window)
| where ContainerAppName_s == App or EnvironmentName_s == Env
| project TimeGenerated,
Source="system",
Environment=EnvironmentName_s,
App=ContainerAppName_s,
Revision=RevisionName_s,
Replica="",
Message=Log_s;
let Console =
ContainerAppConsoleLogs_CL
| where TimeGenerated > ago(Window)
| where ContainerAppName_s == App
| project TimeGenerated,
Source="console",
Environment=EnvironmentName_s,
App=ContainerAppName_s,
Revision=RevisionName_s,
Replica=tostring(ContainerGroupName_g),
Message=Log_s;
System
| union Console
| where Message has_any ("ingress", "probe", "revision", "error", "failed", "timeout", "502", "404")
| order by TimeGenerated desc Cette requête donne au responsable d’incident une vue compacte : événements plateforme, noms de révisions, replicas et messages applicatifs dans une même timeline. Elle est volontairement large au départ. Une fois la révision ou la famille d’événements identifiée, on resserre la requête.
Comparer le trafic configuré aux logs observés
Les révisions Container Apps rendent le rollback tentant, mais les poids de trafic doivent être lus avec preuves. Si plusieurs révisions sont actives, un petit pourcentage peut suffire à créer un incident intermittent visible. Si des labels sont utilisés, un appelant peut cibler une révision labellisée même quand le trafic par défaut semble sain.
APP=orders-api
RG=rg-prod-apps
az containerapp ingress show --name "$APP" --resource-group "$RG" --query '{external:external,targetPort:targetPort,transport:transport,traffic:traffic}' --output table
az containerapp revision list --name "$APP" --resource-group "$RG" --query '[].{name:name,active:properties.active,traffic:properties.trafficWeight,created:properties.createdTime}' --output table La comparaison est simple : si les logs montrent des échecs seulement sur une révision et que le trafic pointe dessus, déplace le trafic ou rollback cette révision. Si aucune requête n’atteint une révision, reste sur ingress, DNS ou gateway. Si toutes les révisions journalisent le même 403 aval, la dépendance est un suspect plus crédible.
Garder un rollback petit et observable
Un rollback ne doit pas devenir un contournement silencieux. Avant de déplacer le trafic, capture la révision fautive, les poids actuels, la référence du dernier déploiement et les preuves de diagnostic qui rendent le rollback raisonnable. Après le rollback, garde le même hostname et un header de corrélation pour valider.
APP=orders-api
RG=rg-prod-apps
GOOD_REV=orders-api--000018
BAD_REV=orders-api--000019
az containerapp ingress traffic set --name "$APP" --resource-group "$RG" --revision-weight "$GOOD_REV=100" "$BAD_REV=0"
CORRELATION_ID="ops-$(date +%Y%m%d%H%M%S)"
curl -vk "https://api.internal.example.com/health" -H "x-correlation-id: $CORRELATION_ID"
echo "validate_correlation_id=$CORRELATION_ID" Si le rollback corrige la requête mais que DNS, gateway et ingress n’ont jamais été capturés, l’équipe garde un résultat fragile. Le prochain déploiement peut réintroduire la panne parce que la condition réelle n’a pas été écrite.
Conclusion
L’ingress privé Azure Container Apps n’est exploitable proprement que si le chemin est observable. DNS, private endpoint, mode d’ingress, proxy plateforme, routage des révisions et logs applicatifs doivent être lus avant de choisir une correction.
La règle pratique est directe : ne pas changer le trafic des révisions tant que le trafic n’a pas atteint Container Apps, ne pas modifier DNS tant que le chemin resolver n’est pas prouvé, et ne pas ajouter d’exception gateway sans symptôme gateway visible. Avec cette discipline, un incident Container Apps privé devient un diagnostic borné plutôt qu’un rollback à l’aveugle.