Cloud

Azure App Service : diagnostiquer les échecs Health Check avant de redémarrer les instances

Un runbook de production pour séparer endpoint de santé défectueux, instance dégradée, redirection, authentification et panne de dépendance avant de redémarrer ou modifier Health Check.

10 sept. 2026 azureapp-servicehealth-checkavailabilityobservabilityazure-monitorautomationrunbookrollbackproduction

Un Azure App Service reste joignable alors que Health Check déclare une ou plusieurs instances unhealthy. Le trafic se concentre sur les workers restants, la latence augmente, ou la plateforme sort régulièrement la même instance de la rotation. Redémarrer l’application peut effacer le symptôme, mais aussi l’état du processus et la chronologie nécessaires pour distinguer un worker défaillant d’un mauvais contrat de santé.

Le cas fil rouge est une API de production répartie sur plusieurs instances App Service. Health Check appelle /health/ready, qui vérifie la base de données et une dépendance de messaging. Après une release, quelques instances échouent, puis toute l’application renvoie par intermittence des réponses hors 2xx. Ce runbook doit produire une décision : corriger l’endpoint, isoler une instance, rollbacker l’application ou restaurer la configuration Health Check précédente sans masquer la panne d’une dépendance partagée.

Figer le contrat de santé et la fenêtre d’incident

Health Check pilote le trafic ; ce n’est pas seulement une URL de monitoring. Avant de modifier le chemin ou le seuil d’échec, documentez ce que promet l’endpoint.

yaml incident-health-app-service.yml
incident: inc-20260910-006
app: app-orders-prod
slot: production
plan: asp-orders-prod
region: westeurope
instances_attendues: 4
health_path: /health/ready
premiere_instance_unhealthy_utc: 2026-09-10T14:12:00Z
release: orders-api-2026.09.10.3

contrat_sante:
statut_healthy: 200-299
anonyme_ou_authentifie_par_plateforme: explicite
controles:
  - processus_ready
  - lecture_base_de_donnees
  - connexion_service_bus
exclusions:
  - api_reporting_non_critique
  - ecriture_metier

a_preserver_avant_action:
- configuration_health_check
- metrique_par_instance
- logs_applicatifs_et_dependances
- chronologie_deploiements_et_configuration
- memoire_threads_et_redemarrages_processus
- revision_precedente_et_commande_rollback

Ne commencez pas par augmenter le seuil d’échec. Un seuil supérieur retarde l’exclusion ; il ne rend pas l’endpoint plus représentatif. Notez aussi si le site utilise une ou plusieurs instances. Avec une seule instance, Health Check peut signaler la panne mais ne peut pas rerouter le trafic vers un autre worker sain.

Lire la configuration réellement déployée

Capturez la configuration du site et les deux paramètres qui contrôlent l’exclusion des workers. App Service appelle le chemin configuré sur chaque instance à une minute d’intervalle. Une réponse hors 200-299, un timeout, une demande d’authentification ou une redirection peuvent créer un écart entre la vue plateforme et un test manuel.

bash 01-configuration-health-check.sh
set -eu

RG="rg-app-prod"
APP="app-orders-prod"

az webapp config show \
--resource-group "$RG" \
--name "$APP" \
--query '{healthCheckPath:healthCheckPath,alwaysOn:alwaysOn,http20Enabled:http20Enabled,ftpsState:ftpsState}' \
--output json

az webapp config appsettings list \
--resource-group "$RG" \
--name "$APP" \
--query "[?name=='WEBSITE_HEALTHCHECK_MAXPINGFAILURES' || name=='WEBSITE_HEALTHCHECK_MAXUNHEALTHYWORKERPERCENT'].{name:name,value:value}" \
--output table

Conservez aussi le comportement des slots dans la capture. La configuration Health Check est échangée pendant un slot swap ; production et staging doivent donc employer des chemins et une sémantique compatibles. Sinon, le swap peut promouvoir un bon code avec un contrat de probe invalide à destination.

Séparer échec de probe et panne d’instance

Testez l’endpoint par le chemin public ou privé réel, puis corrélez le résultat avec les preuves par instance. Une requête cliente réussie prouve seulement qu’un worker sain a répondu. Un échec global pointe vers l’endpoint ou une dépendance commune ; l’échec d’une seule instance oriente davantage vers le processus local, le filesystem, la mémoire ou l’état du worker.

text classes-echec-health.txt
Une instance unhealthy
Comparer dimension Instance, redemarrages, memoire, threads et logs locaux
Verifier que release et warm-up ont termine sur ce worker
Preserver les diagnostics avant redemarrage ou remplacement

Toutes les instances unhealthy ensemble
Verifier code de l’endpoint, dependance partagee, DNS, identite et configuration
Ne pas choisir le remplacement des workers comme premiere correction
La plateforme evite de retirer toutes les instances simultanement

Le test manuel retourne 200, Health Check echoue
Verifier comportement du hostname par defaut, redirections et authentification
Confirmer que le test manuel utilise exactement le chemin configure
Comparer HTTPS Only et les redirections applicatives

L’endpoint est vert alors que les utilisateurs echouent
La probe est trop superficielle ou contourne la dependance en panne
Ajouter une lecture representative sans transformer health en transaction
Separer clairement liveness et readiness

L’endpoint doit rester peu coûteux et déterministe. Il doit prouver que l’instance peut servir la classe de requêtes représentée par l’application, sans créer de données, consommer de messages ni échouer à cause d’un service analytique optionnel.

Vérifier explicitement redirections et authentification

App Service Health Check attend un statut 200-299 et ne suit pas les redirections. Une redirection du hostname par défaut vers un domaine personnalisé, une redirection HTTPS applicative ou un challenge de connexion peuvent déclarer tous les workers en échec alors qu’un navigateur finit par afficher une page verte.

bash 02-rejouer-contrat-health.sh
set -eu

DEFAULT_HOST="app-orders-prod.azurewebsites.net"
CUSTOM_HOST="orders.example.com"
PATH_TO_TEST="/health/ready"

curl --silent --show-error --output /dev/null \
--write-out 'default status=%{http_code} redirect=%{redirect_url} time=%{time_total}\n' \
"https://$DEFAULT_HOST$PATH_TO_TEST"

curl --silent --show-error --output /dev/null \
--write-out 'custom status=%{http_code} redirect=%{redirect_url} time=%{time_total}\n' \
"https://$CUSTOM_HOST$PATH_TO_TEST"

Si App Service Authentication protège l’application, vérifiez son intégration supportée avec Health Check. Si l’application porte son propre mécanisme d’authentification, le chemin doit autoriser la requête plateforme ou valider le token interne documenté. Ne résolvez pas l’incident en exposant un endpoint de diagnostic bavard qui révèle les dépendances, des secrets ou la topologie.

Corréler santé, runtime et dépendances

Lisez HealthCheckStatus avec la dimension Instance, puis comparez la même fenêtre avec requêtes, exceptions, dépendances en échec, mémoire et redémarrages. Le statut Health Check n’apparaît qu’après atteinte du seuil d’échecs configuré ; conservez donc les événements applicatifs antérieurs.

kusto 03-correlation-health-check-instance.kql
let StartTime = datetime(2026-09-10T14:00:00Z);
let EndTime = datetime(2026-09-10T15:00:00Z);
let AppResource = "app-orders-prod";
AzureMetrics
| where TimeGenerated between (StartTime .. EndTime)
| where Resource =~ AppResource
| where MetricName in ("HealthCheckStatus", "Http5xx", "MemoryWorkingSet", "Requests")
| extend Instance = tostring(column_ifexists("Instance", "not-exported"))
| summarize Average=avg(Average), Maximum=max(Maximum), Total=sum(Total) by bin(TimeGenerated, 5m), MetricName, Instance
| order by TimeGenerated asc, Instance asc

La forme des tables et dimensions peut varier selon le chemin de diagnostic retenu. Conservez l’export brut des métriques si la projection Log Analytics ne porte pas la dimension d’instance. Corrélez ensuite la télémétrie applicative : durée de l’endpoint, dépendance en erreur, révision, role instance et type d’exception.

Décider si une dépendance appartient à la readiness

Un endpoint de santé peut provoquer une panne auto-infligée s’il échoue sur une dépendance dégradée mais non critique. Il peut aussi rester vert alors que l’application a perdu la base nécessaire à toutes les requêtes. Classez chaque contrôle selon son impact utilisateur et son mode de récupération.

yaml politique-dependances-health.yml
dependances:
base_principale:
  critique: true
  probe: lecture_bornee
  timeout_ms: 500
  unhealthy_on: echecs_repetes

service_bus:
  critique_pour: commandes_en_ecriture
  probe: connexion_ou_lecture_management
  timeout_ms: 500
  mode_degrade: lectures_ok_nouvelles_commandes_refusees

api_reporting:
  critique: false
  probe: telemetrie_uniquement
  unhealthy_on: jamais_seule

regles_endpoint:
- aucune_ecriture_metier
- aucun_secret_ou_topologie_dans_reponse
- budget_total_inferieur_au_timeout_plateforme
- cache_uniquement_si_staleness_visible
- raison_dependance_et_instance_dans_logs_internes

Quand la dépendance partagée est la cause, retirer des workers ne fait que concentrer le trafic sur les instances restantes. Préférez un mode dégradé borné, un circuit breaker ou la restauration de la dépendance lorsque le contrat métier le permet. Ne modifiez la sémantique de la probe que si le contrat actuel est manifestement incorrect.

Choisir une correction avec chemin de retour

Évitez d’empiler redémarrage, modification du seuil et réécriture de l’endpoint dans le même incident. Choisissez l’action minimale qui teste l’hypothèse prouvée.

text decision-health-check.txt
Corriger l’endpoint
Redirection, authentification ou mauvais statut explique l’echec plateforme
Politique de dependance trop large ou budget de timeout invalide
Valider sur un slot avant d’appliquer en production

Isoler ou redemarrer une instance
Echec lie a un worker et diagnostics preserves
Capacite mesuree suffisante sur les autres instances
Validation post-redemarrage capable d’identifier instance et revision

Rollbacker l’application
Echec commence avec une release et suit la nouvelle revision
Endpoint et erreurs metier regressent ensemble
Revision et configuration precedentes connues saines

Restaurer la configuration Health Check precedente
Chemin ou seuil modifie independamment de la release
Ancien chemin toujours representatif et securise
Rollback ne masque pas une panne applicative reelle

Bloquer toute nouvelle action
Tous les workers echouent sur une dependance partagee
Capacite restante inconnue
Logs incapables de separer probe et panne applicative

Une modification de configuration Health Check redémarre l’application. Traitez donc son rollback comme une action de production : utilisez un slot de staging si possible, capturez les paramètres avant et après, et ne changez pas le chemin uniquement pour faire taire la métrique.

Valider sur plusieurs cycles de probe

Un unique 200 ne prouve pas la récupération. Maintenez le candidat sur plusieurs cycles d’une minute et sous trafic normal. Vérifiez que toutes les instances attendues sont saines, que le trafic est distribué, que les erreurs de dépendance restent bornées et que l’endpoint détecte toujours un cas négatif volontaire dans un environnement sûr.

text gates-validation-health-check.txt
Conserver la correction
HealthCheckStatus stable sur chaque instance attendue
Taux d’erreur utilisateur et latence revenus a la baseline
Endpoint dans son budget de reponse
Aucun loop de redemarrage ou d’exclusion
Echec d’une dependance critique rend toujours readiness negative
Echec d’une dependance optionnelle ne retire plus de capacite saine

Rollbacker ou maintenir le blocage
Seule la requete synthetique est verte
Metrique amelioree mais erreurs utilisateur persistantes
Une instance sort regulierement de la rotation
Workers restants proches de leurs limites
Endpoint expose des details sensibles
Contrat de probe different entre production et staging

Conclusion

App Service Health Check n’est utile que si son endpoint représente la décision de trafic que la plateforme doit prendre. Quand des workers passent unhealthy, figez le contrat, lisez la configuration déployée, séparez panne locale et dépendance partagée, puis vérifiez redirections et authentification avant tout redémarrage.

La décision finale doit rester étroite et observable : corriger l’endpoint, isoler un worker prouvé défaillant, restaurer la configuration précédente, rollbacker la release ou maintenir un mode dégradé contrôlé pendant la récupération de la dépendance. Le service n’est rétabli que lorsque la métrique plateforme et le chemin utilisateur convergent sur plusieurs cycles de probe.