Infrastructure

Azure VMSS : diagnostiquer une boucle de réparations automatiques avant de changer l'action

Un runbook de production pour séparer signal de santé, grace period, état du service, modèle VMSS et données locales avant de modifier Replace, Reimage ou Restart.

12 sept. 2026 azurevmssvirtual-machine-scale-setsautomatic-repairsapplication-healthobservabilityautomationinfrastructurerunbookvalidationrollbackproduction

Un Azure Virtual Machine Scale Set remplace régulièrement une instance déclarée unhealthy. La nouvelle VM démarre, rejoint le pool, puis est remplacée à son tour. La capacité utile diminue et l’équipe propose de passer l’action automatique de Replace à Restart, d’allonger la grace period ou de désactiver les réparations.

Ces changements peuvent arrêter la boucle sans corriger sa cause. Le signal de santé peut tester un endpoint erroné, le modèle VMSS peut recréer la panne, ou l’application peut avoir besoin de plus de temps que la période accordée. Le cas d’usage est un pool de workers stateless avec l’Application Health extension et une policy de réparation Replace. Le runbook doit préserver la capacité, identifier la cause reproductible, valider un canari, puis décider de reprendre, suspendre ou rollbacker.

Figer la boucle et son impact

Commencez par une chronologie par instance. Une réparation automatique est une conséquence ; l’événement initial est la transition de santé.

yaml vmss-repair-incident.yml
incident:
window_utc: 2026-09-12T08:00:00Z/2026-09-12T10:00:00Z
scale_set: vmss-workers-prod
expected_capacity: 20
useful_capacity: 15
health_source: application-health-extension
repair_action: Replace
grace_period: PT30M

capture_per_instance:
- instance_id
- model_version
- provisioning_time
- health_transitions
- repair_start_and_end
- application_release
- last_completed_work

hard_stops:
- useful-capacity-below-service-floor
- repair-removes-non-reconstructible-data
- repeated-replacement-of-the-same-capacity-slot

Fixez aussi un plancher de capacité. Les réparations s’effectuent par lots bornés, mais un pool qui recrée des instances durablement unhealthy peut rester dégradé. Si la marge disparaît, suspendez la réparation automatique de façon tracée avant qu’elle ne consomme la capacité nécessaire au diagnostic.

Capturer la policy et l’état du service

Lisez la configuration déployée, pas seulement le template IaC. Vérifiez l’action, la grace period, la source de santé et l’état du service d’orchestration.

bash 01-capture-vmss-repair-state.sh
SUBSCRIPTION="<subscription-id>"
RG="rg-compute-prod"
VMSS="vmss-workers-prod"

az account set --subscription "$SUBSCRIPTION"

az vmss show \
--resource-group "$RG" \
--name "$VMSS" \
--query "{capacity:sku.capacity,upgradePolicy:upgradePolicy,automaticRepairsPolicy:automaticRepairsPolicy,orchestrationServices:orchestrationServices,extensions:virtualMachineProfile.extensionProfile.extensions}" \
--output json > vmss-repair-state.json

az vmss list-instances \
--resource-group "$RG" \
--name "$VMSS" \
--expand instanceView \
--query "[].{id:instanceId,latestModel:latestModelApplied,provisioning:provisioningState,health:instanceView.vmHealth.status.statuses[0].displayStatus}" \
--output table

Un service Suspended explique pourquoi une instance unhealthy n’est plus réparée ; le réactiver sans comprendre les échecs ne fait que relancer la boucle. Une instance en grace period n’est pas encore éligible à la réparation. Cette période commence après une opération de changement d’état et doit couvrir le démarrage réel, le warm-up et l’enregistrement dans les dépendances.

Qualifier le signal de santé

Un VMSS utilise soit l’Application Health extension, soit une health probe Load Balancer comme source de santé pour les réparations automatiques. Prouvez le signal configuré et rejouez exactement son contrat sur une instance saine et une instance affectée.

text health-contract-review.txt
Application Health contract
Protocol, port and request path are explicit
Endpoint is reachable locally from the extension
Healthy response matches the selected binary or rich mode
Warm-up can report Initializing when rich states are enabled
Timeout is below the probe interval
Endpoint does not depend on a non-critical remote service

Negative controls
Stopped application becomes Unhealthy
Wrong path never reports Healthy
New instance remains non-eligible during initialization
Healthy status correlates with one useful workload transaction

Avec les états binaires, une réponse autre que 200 ou un endpoint inaccessible devient unhealthy. Avec les rich health states, distinguez Initializing, Unknown et Unhealthy au lieu de traiter chaque absence de Healthy comme une panne identique. Une extension mal configurée et une application réellement en erreur peuvent produire le même signal ; les logs locaux doivent les séparer.

Prouver ce que l’action détruit ou conserve

Replace, Reimage et Restart n’ont pas le même rayon d’impact. Replace supprime l’instance et en crée une depuis le modèle VMSS courant. L’identifiant, l’IP privée et les disques de l’instance ne doivent pas être supposés conservés. Reimage conserve l’instance et ses disques de données managés, mais reconstruit le disque OS. Restart conserve les disques et ne corrige pas un modèle ou un OS durablement défectueux.

yaml repair-action-contract.yml
Replace:
use_when: instance-is-disposable-and-current-model-is-known-good
verify: [externalized-state, ip-consumers, model-version, bootstrap-idempotence]

Reimage:
use_when: os-state-is-disposable-but-instance-identity-must-remain
verify: [data-disk-contract, bootstrap-after-reimage, extension-order]

Restart:
use_when: failure-is-transient-and-process-recovers-after-boot
verify: [restart-evidence, recurrence-window, service-autostart]

never_assume:
- local-state-survives-replace
- restart-fixes-model-drift
- reimage-preserves-os-disk-changes
- replacement-reuses-private-ip

Si chaque VM de remplacement applique le même modèle défectueux, Replace est un reproducteur de panne. Comparez la version du modèle, les extensions, l’image, le cloud-init et les paramètres applicatifs entre la dernière instance saine et les remplacements.

Séparer grace period, bootstrap et dérive du modèle

Mesurez le temps réel entre la fin du provisioning et le premier signal sain. Ne rallongez pas la grace period sur la seule intuition.

text repair-loop-classification.txt
Healthy just after grace period expires
Grace period is shorter than measured startup and warm-up.

Never healthy, same error on every replacement
Current VMSS model, image, extension or bootstrap likely reproduces the fault.

Healthy then unhealthy under load
Diagnose application saturation, dependency failure or health endpoint design.

Healthy locally, Unknown in instance view
Diagnose Application Health extension configuration and reporting path.

One instance repeatedly unhealthy, model identical
Compare host, zone, attached resources and instance-specific initialization.

Conservez la distribution, pas seulement la moyenne : P50, P95 et maximum du temps de readiness sur plusieurs créations. La grace period peut ensuite couvrir le P95 avec une marge explicitée. Une valeur trop longue retarde une vraie réparation ; une valeur trop courte transforme un démarrage normal en remplacement.

Tester un canari sans relancer la flotte

Suspendez les réparations si nécessaire, corrigez une seule cause et créez ou réimagez une instance canari. N’appliquez pas simultanément une nouvelle image, une nouvelle extension et une nouvelle action de réparation.

text vmss-repair-canary-gates.txt
Canary scope
One instance on the candidate model
Automatic repair remains suspended or isolated
Same health contract as production
No local state required for recovery

Promotion gates
Provisioning completes once
Health progresses through expected states
Readiness occurs inside the justified grace period
One useful workload transaction completes
Instance remains healthy across the recurrence window
Reapplying the model produces no drift

Refusal gates
Broken health path stays unhealthy
Failed bootstrap does not enter service
Capacity floor remains respected

La fenêtre de récurrence doit couvrir le déclencheur observé : premier job, pic de charge, rotation de secret ou redémarrage. Une instance healthy pendant deux minutes ne valide pas une panne qui revenait toutes les heures.

Décider reprise, suspension ou rollback

Ne changez l’action de réparation que si le mode de panne et le contrat de données le justifient.

yaml vmss-repair-decision.yml
resume:
when:
- health-contract-is-proven
- current-model-creates-a-healthy-canary
- grace-period-covers-measured-readiness
- repair-action-matches-state-contract
action: resume-and-observe-one-repair-batch

suspend:
when:
- useful-capacity-is-at-risk
- service-state-was-suspended-after-repeated-failures
- replacement-reproduces-the-fault
action: preserve-instances-and-fix-model-first

rollback:
when:
- candidate-model-or-extension-breaks-health
- replacement-loses-required-state
- recurrence-window-fails
action:
- restore-last-known-good-model
- keep-automatic-repairs-suspended
- recreate-one-canary
- resume-only-after-positive-and-negative-tests

Après reprise, observez un lot complet et vérifiez que le nombre d’instances saines revient à la capacité attendue. Réconciliez ensuite l’IaC : une suspension manuelle ou une ancienne image laissée hors code peut recréer la boucle au prochain déploiement.

Conclusion

Une boucle de réparations VMSS n’est pas d’abord un choix entre Replace, Reimage et Restart. C’est un désaccord entre un signal de santé, un temps de démarrage, un modèle de machine et un contrat de persistance.

La reprise est sûre quand le canari issu du modèle courant devient sain dans une grace period mesurée, traite une transaction utile, échoue correctement au témoin négatif et survit à la fenêtre de récurrence. Si le remplacement reproduit la panne ou menace la capacité, suspendez la policy, restaurez le dernier modèle sain et ne relancez les réparations qu’après validation du nouveau canari.