Networking

Azure Load Balancer : diagnostiquer une health probe avant de changer le backend pool

Un runbook de production pour qualifier un backend Azure Load Balancer unhealthy avec probe, NSG, routage, logs, configuration de pool, validation et rollback avant de modifier la règle ou redéployer.

09 juil. 2026 azureload-balancerhealth-probebackend-poolnetworkingnsgudrobservabilitykqlrunbookrollbackproduction

Un backend Azure Load Balancer marqué unhealthy déclenche souvent les mauvais réflexes : retirer une VM du pool, changer le port de probe, ouvrir un NSG largement, redéployer le service ou déplacer le trafic vers une autre instance. Ces actions peuvent rétablir un test ponctuel, mais elles masquent parfois une rupture plus simple : probe envoyée sur le mauvais port, service qui écoute seulement en localhost, route de retour asymétrique, firewall local, règle NSG trop stricte ou instance qui ne sert plus le même chemin applicatif.

Le cas d’usage est une application interne exposée par Azure Standard Load Balancer, avec plusieurs VM ou appliances dans un backend pool, des subnets contrôlés par NSG et parfois des UDR vers Azure Firewall ou une NVA. Le symptôme est clair : une ou plusieurs instances sortent du pool, les connexions deviennent intermittentes ou une bascule ne reçoit plus de trafic. L’objectif du runbook est de prouver si la panne vient de la probe, de l’application, du réseau ou du pool avant de changer la règle de répartition.

Figer le flux de santé avant toute correction

Commencez par nommer le contrat de santé. Une health probe n’est pas un détail de configuration : c’est le signal qui décide si une instance peut recevoir du trafic.

text load-balancer-health-contract.txt
Contrat de sante Load Balancer
Load balancer: lb-prod-internal
Frontend IP: 10.20.4.10
Backend pool: pool-orders-api
Instances: vm-orders-01, vm-orders-02, vm-orders-03
Rule: tcp-443-orders
Probe: tcp-8080-health ou http-/healthz
Intervalle et seuil: 5s / 2 echecs
Subnet backend: snet-app-prod
Chemin attendu: LB -> backend private IP -> service local -> reponse probe
Changement recent: deploiement app, NSG, route table, image VM, extension ou firewall local

Preuves requises avant changement
Configuration complete LB, rule, probe et backend pool
Etat backend par instance
Ecoute locale du service sur le port probe
NSG effectifs et routes effectives sur la NIC backend
Logs applicatifs ou systeme pendant la fenetre de probe
Test depuis une VM du meme subnet ou un runner d'exploitation
Plan de rollback de la probe, du pool ou du deploiement

Si l’équipe ne sait pas expliquer pourquoi la probe utilise ce port et ce chemin, elle ne doit pas encore l’assouplir. Une probe trop permissive peut remettre dans le pool une instance qui accepte TCP mais ne sert plus correctement l’application.

Capturer la configuration réelle du Load Balancer

Le portail donne une vue utile, mais le diagnostic doit partir d’un snapshot relisible. Capturez la règle, la probe, le backend pool et les associations NIC avant toute modification.

bash 01-load-balancer-snapshot.sh
RESOURCE_GROUP="rg-network-prod"
LOAD_BALANCER="lb-prod-internal"

az network lb show --resource-group "$RESOURCE_GROUP" --name "$LOAD_BALANCER" --query "{frontend:frontendIPConfigurations[].{name:name,ip:privateIPAddress},rules:loadBalancingRules[].{name:name,frontendPort:frontendPort,backendPort:backendPort,protocol:protocol,probe:probe.id,backendPool:backendAddressPool.id},probes:probes[].{name:name,protocol:protocol,port:port,requestPath:requestPath,interval:intervalInSeconds,threshold:numberOfProbes},pools:backendAddressPools[].{name:name,backendIPConfigurations:backendIPConfigurations[].id}}" --output json

az network lb address-pool show --resource-group "$RESOURCE_GROUP" --lb-name "$LOAD_BALANCER" --name "pool-orders-api" --output json

Vérifiez ensuite si toutes les instances attendues sont réellement associées au pool. Un backend unhealthy n’est pas toujours une probe en échec : il peut aussi être une NIC retirée, une association déplacée par IaC, ou un pool différent de celui utilisé par la règle active.

Distinguer probe TCP et probe HTTP

Une probe TCP valide seulement qu’une socket accepte la connexion. Une probe HTTP valide un code de réponse sur un chemin. Les deux n’ont pas le même niveau de confiance.

text probe-semantics.txt
Probe TCP
Valide: port ouvert et handshake TCP possible
Ne valide pas: dependances applicatives, readiness metier, code HTTP, authentification
Risque: remettre dans le pool un service bloque mais port ouvert

Probe HTTP
Valide: endpoint HTTP repond avec un statut accepte par la probe
Ne valide pas toujours: dependances profondes, file de messages, base aval
Risque: retirer du pool une instance saine si /healthz depend d'un service externe instable

Questions avant changement
La probe mesure-t-elle la readiness ou seulement la connectivite ?
Le chemin /healthz a-t-il change avec le dernier deploiement ?
Le service ecoute-t-il sur toutes les interfaces ou seulement 127.0.0.1 ?
Le port probe est-il identique au backendPort de la rule ?
Une authentification, redirection ou host header bloque-t-il la probe ?

Changer une probe HTTP en TCP peut calmer l’incident tout en remettant du trafic sur une instance incapable de traiter les requêtes. Le changement doit être une décision de contournement documentée, pas une correction automatique.

Prouver que le service écoute localement

Avant d’ouvrir le réseau, vérifiez l’instance. Beaucoup de probes échouent parce que le processus n’écoute plus, écoute sur le mauvais port, ou n’expose le health endpoint que sur localhost.

bash 02-backend-local-checks.sh
# Sur chaque backend concerne
sudo ss -lntp | grep -E ':8080|:443'

curl -sv --max-time 3 http://127.0.0.1:8080/healthz
curl -sv --max-time 3 http://$(hostname -I | awk '{print $1}'):8080/healthz

systemctl status orders-api --no-pager
journalctl -u orders-api --since "30 minutes ago" --no-pager | tail -100

Si 127.0.0.1 répond mais pas l’adresse privée de la VM, la panne n’est pas le Load Balancer. Elle est dans le binding applicatif, le firewall local ou la configuration du service. Si le service répond localement mais pas depuis le subnet, passez au réseau.

Vérifier NSG, routes et firewall local

Les probes Azure Load Balancer arrivent depuis l’infrastructure Azure et doivent être autorisées jusqu’au backend. Sur Standard Load Balancer, les NSG doivent permettre explicitement le trafic attendu, y compris la sonde depuis le service tag AzureLoadBalancer quand il est utilisé dans la politique.

bash 03-nsg-routes-backend.sh
BACKEND_NIC="nic-vm-orders-01"
BACKEND_RG="rg-prod-app"
PROBE_PORT="8080"

az network nic list-effective-nsg --resource-group "$BACKEND_RG" --name "$BACKEND_NIC" --output table

az network nic show-effective-route-table --resource-group "$BACKEND_RG" --name "$BACKEND_NIC" --output table

az network watcher test-ip-flow --resource-group "$BACKEND_RG" --vm "vm-orders-01" --direction Inbound --protocol TCP --local 10.20.5.14 "$PROBE_PORT" --remote 168.63.129.16 65503 --output json

Traitez 168.63.129.16 comme une indication opérationnelle utile pour tester certains chemins Azure, pas comme une preuve unique. La décision doit combiner NSG effectif, routes effectives, firewall local et réponse applicative. Si une UDR force un chemin de retour inattendu vers une NVA, la probe peut échouer même si le port est ouvert.

Lire les métriques et les logs comme une chronologie

Une health probe unhealthy doit être replacée dans le temps. L’important n’est pas seulement l’état actuel, mais le moment où il a changé par rapport à un déploiement, une règle NSG, une rotation d’image ou une mise à jour système.

kusto 04-load-balancer-probe-evidence.kql
let StartTime = datetime(2026-07-09T08:00:00Z);
let EndTime = datetime(2026-07-09T09:00:00Z);
AzureMetrics
| where TimeGenerated between (StartTime .. EndTime)
| where ResourceProvider =~ "MICROSOFT.NETWORK"
| where MetricName in ("DipAvailability", "VipAvailability", "HealthProbeStatus")
| project TimeGenerated, Resource, MetricName, Average, Minimum, Maximum, backendIPAddress_s=tostring(Tags["BackendIPAddress"]), frontendIPAddress_s=tostring(Tags["FrontendIPAddress"])
| order by TimeGenerated asc

Complétez avec les logs applicatifs, les journaux système, les changements Azure Activity Log et les éventuels logs d’appliance. Une probe qui tombe exactement au moment d’un déploiement applicatif n’appelle pas la même correction qu’une probe qui tombe au moment d’une association NSG.

Tester depuis le chemin le plus proche

Le Load Balancer n’est pas toujours testable directement depuis l’extérieur du chemin de production. Utilisez une VM d’exploitation dans le même VNet ou subnet proche pour reproduire ce que la probe attend : port, protocole, chemin HTTP et adresse privée backend.

bash 05-controlled-replay.sh
BACKEND_IP="10.20.5.14"
PROBE_PORT="8080"
FRONTEND_IP="10.20.4.10"

# Tester le backend directement depuis une VM d'exploitation du VNet.
nc -vz "$BACKEND_IP" "$PROBE_PORT"
curl -sv --max-time 3 "http://${BACKEND_IP}:${PROBE_PORT}/healthz"

# Tester ensuite le frontend avec le port applicatif.
nc -vz "$FRONTEND_IP" 443
curl -skv --max-time 5 "https://orders.internal.example/healthz" -H "x-correlation-id: lb-health-20260709-01"

Si le backend répond depuis une VM du même subnet mais reste unhealthy côté LB, revenez à la configuration de probe, au pool et aux règles. Si le backend ne répond pas depuis le VNet, le Load Balancer ne fait que révéler une panne plus basse.

Décider correction, retrait, rollback ou blocage

La correction doit être liée à la preuve. Gardez une décision explicite pour éviter les changements empilés pendant l’incident.

text load-balancer-decision.txt
Corriger la probe
Le service expose un nouveau chemin de health valide
Le port probe historique ne correspond plus au service voulu
La probe actuelle depend d'une dependance externe instable
Le changement est teste sur une instance avant generalisation
Le rollback de la probe est documente

Corriger le backend
Le service n'ecoute pas sur l'adresse privee
Le firewall local bloque le port probe
Le processus est en erreur ou retourne un code non accepte
Le dernier deploiement a casse /healthz

Corriger le reseau
NSG effectif bloque le trafic probe ou backend
UDR ou appliance casse le chemin retour
Association NIC, subnet ou pool a derive
Les routes effectives ne correspondent plus au chemin attendu

Retirer temporairement une instance
Une seule VM est malade
Les autres backends sont sains et dimensionnes
Le retrait est trace et reversible
Le proprietaire applicatif valide l'impact capacite

Rollbacker
L'incident commence apres un changement probe, rule, NSG, UDR, pool ou release applicative
Le retour a l'etat precedent restaure la health probe en test
Le changement correctif augmente le risque pour d'autres flux

Bloquer le changement
Aucune preuve locale du service n'existe
Les backends ne sont pas identifies individuellement
Le plan propose ouvre un NSG trop largement
La probe serait rendue moins stricte sans validation applicative

Cette décision évite de transformer un incident de health check en modification permanente de sécurité ou de routage.

Valider après correction et préparer le retour arrière

La validation ne s’arrête pas au passage à healthy. Il faut vérifier que le trafic applicatif revient, que la capacité est cohérente et que la correction ne rend pas la probe muette.

text post-fix-validation.txt
Validation post-correction
Chaque backend attendu redevient healthy avec son adresse IP identifiee
Le frontend repond sur le port applicatif
Les logs applicatifs montrent des requetes reelles sur toutes les instances saines
Les metriques DipAvailability et VipAvailability restent stables
Aucun NSG ou firewall local temporaire ne reste ouvert sans expiration
Le changement IaC correspondant est aligne avec l'etat corrige
La note d'incident conserve configuration initiale, preuve, decision et rollback

Rollback incomplet quand
Une instance a ete retiree du pool sans ticket de retour
La probe a ete affaiblie sans test applicatif
Le port ouvert pour diagnostic reste autorise
Les routes effectives n'ont pas ete reverifiees apres correction
L'IaC recreera l'ancienne configuration au prochain deploiement

Si l’infrastructure est gérée par Terraform, Bicep ou un pipeline, la correction manuelle doit être répercutée dans le code ou explicitement rollbackée. Sinon, la prochaine livraison peut remettre la probe ou le pool dans l’état incident.

Conclusion

Un backend Load Balancer unhealthy n’est pas une invitation à modifier la règle de répartition au hasard. C’est un signal à qualifier : configuration du pool, sémantique de probe, service local, NSG, routes, logs et replay contrôlé.

La bonne sortie d’incident tient en une décision traçable : corriger la probe, corriger le backend, corriger le réseau, retirer temporairement une instance, rollbacker le changement récent ou bloquer l’action faute de preuve. Cette discipline garde le Load Balancer comme un mécanisme d’exploitation fiable, pas comme une boîte noire que l’on ajuste pendant la panne.