Automation
Azure DevOps : diagnostiquer un agent auto-hébergé avant de relancer la pipeline
Un runbook de production pour qualifier un échec Azure DevOps sur agent auto-hébergé avec disque, workspace, cache, services locaux, identité, logs, nettoyage contrôlé, validation et rollback.
Un job Azure DevOps qui échoue sur un agent auto-hébergé déclenche souvent le même réflexe : cliquer sur rerun. Si l’agent a simplement reçu une erreur transitoire, cela suffit. Si le disque est saturé, si le workspace contient un reste de build, si un cache est corrompu, si Docker garde des layers obsolètes ou si le service local a perdu son identité, la relance rejoue le problème avec un peu plus de bruit.
Le cas d’usage est une équipe produit ou plateforme qui exécute des pipelines CI/CD sur un pool d’agents privés, souvent parce qu’ils ont besoin d’un accès réseau interne, d’outils spécifiques, d’un runner proche d’Azure ou d’une gouvernance plus stricte que les agents hébergés. L’objectif du runbook est de décider s’il faut relancer le job, nettoyer l’agent, le sortir du pool, corriger l’image de base, ou rollbacker un changement récent de pipeline avant de casser une chaîne de livraison complète.
Nommer l’agent comme une dépendance de production
Un agent auto-hébergé n’est pas seulement une machine qui lance des commandes. C’est une dépendance d’exploitation : disque, workspace, runtime, secrets locaux, réseau, identité, version d’agent, outils, caches et droits sur les ressources cibles.
Incident pipeline
Projet Azure DevOps: platform-prod
Pipeline: build-and-deploy-orders
Run: 20260715.2
Stage en échec: package-and-publish
Pool: private-linux-prod
Agent: azdo-agent-prod-03
Dernier run sain connu: 20260714.6
Changement récent: mise à jour image SDK + cache npm activé
Questions avant relance
L'échec est-il lié au code ou à l'agent ?
Le disque, le workspace ou le cache sont-ils saturés ou corrompus ?
L'agent a-t-il gardé des fichiers d'un run précédent ?
Le service agent tourne-t-il avec l'identité attendue ?
Le problème touche-t-il un seul agent ou tout le pool ?
Quel nettoyage est autorisé sans supprimer une preuve utile ? Si le contrat n’est pas écrit, la relance devient un pari. Le but n’est pas d’empêcher toute relance, mais de ne pas rejouer un état local dégradé en production.
Séparer erreur applicative, erreur d’agent et dérive de pool
Commencez par classer l’échec. Une erreur de compilation reproductible sur tous les agents ne se traite pas comme un cache Maven cassé sur une seule machine.
Erreur applicative probable
Même commit échoue sur plusieurs agents
Message cohérent avec test, compilation ou packaging
Workspace propre et dépendances restaurées correctement
Aucun signal disque, permission ou outil manquant
Erreur locale d'agent probable
Un seul agent échoue dans le pool
Logs contenant no space left, permission denied, file locked, checksum mismatch
Cache ou workspace réutilisé entre runs
Outil local différent de la version attendue
Service agent redémarré ou mis à jour récemment
Dérive de pool probable
Plusieurs agents échouent après changement d'image ou bootstrap
Même outil manquant sur les machines du pool
Service connection, proxy, DNS ou firewall modifié
Nouvelle policy de nettoyage ou de cache appliquée partout La décision dépend de cette classification. Relancer sur un autre agent peut être raisonnable pour isoler une machine. Relancer sur le même agent sans preuve ne fait qu’ajouter un run échoué.
Capturer les preuves avant nettoyage
Le nettoyage est utile, mais il détruit souvent la preuve. Avant de supprimer un workspace, capturez les éléments qui permettront d’expliquer la panne et de prévenir le retour du problème.
AGENT_HOME="/opt/azdo-agent"
WORK="/opt/azdo-agent/_work"
RUN_ID="20260715.2"
hostname
whoami
date -u
systemctl status vsts.agent.* --no-pager || true
printf "
Disk usage
"
df -h
printf "
Workspace size
"
du -sh "$WORK"/* 2>/dev/null | sort -h | tail -20
printf "
Recent agent logs
"
find "$AGENT_HOME/_diag" -type f -mtime -2 -maxdepth 1 -print | sort | tail -10
printf "
Large files in workspace
"
find "$WORK" -type f -size +500M -printf "%s %p
" 2>/dev/null | sort -n | tail -20 Associez ces preuves au run Azure DevOps : identifiant du job, agent exact, commit, artefact, étape en échec et heure UTC. Sans cette correspondance, un nettoyage réussi ne prouve pas la cause.
Vérifier disque, workspace et caches
Les échecs les plus banals sont souvent les plus coûteux : disque saturé par des artefacts, cache corrompu, dossier temporaire plein, dépendances restaurées dans un état incomplet, layers Docker jamais purgés.
WORK="/opt/azdo-agent/_work"
# Seuils à adapter au pool.
df -h / /tmp "$WORK"
# Workspaces les plus lourds.
du -xhd 2 "$WORK" 2>/dev/null | sort -h | tail -30
# Caches courants selon les workloads.
du -sh ~/.npm ~/.cache ~/.m2 ~/.nuget ~/.gradle 2>/dev/null || true
# Docker si l'agent construit des images.
docker system df 2>/dev/null || true
# Fichiers récents qui expliquent une croissance brutale.
find "$WORK" -type f -mtime -2 -printf "%TY-%Tm-%Td %TH:%TM %s %p
" 2>/dev/null | sort | tail -50 Un cache n’est pas mauvais par principe. Il devient un incident quand personne ne sait ce qu’il contient, combien il pèse, qui le purge et comment la pipeline se comporte sans lui.
Contrôler l’identité et les services locaux
Un agent peut avoir assez de disque et échouer quand même parce que le service ne tourne plus avec la bonne identité, que les droits sur le workspace ont dérivé, ou qu’un outil local a changé de version.
AGENT_HOME="/opt/azdo-agent"
WORK="/opt/azdo-agent/_work"
systemctl cat vsts.agent.* --no-pager || true
ps -eo user,group,pid,cmd | grep -E "Agent.Listener|Agent.Worker" | grep -v grep || true
stat -c "%U %G %a %n" "$AGENT_HOME" "$WORK"
find "$WORK" -maxdepth 2 -type d -printf "%u %g %m %p
" 2>/dev/null | head -40
node --version 2>/dev/null || true
dotnet --info 2>/dev/null | head -40 || true
docker version 2>/dev/null || true
az version 2>/dev/null || true Si l’agent écrit des fichiers en root pendant une étape Docker puis tente de les nettoyer avec un utilisateur non privilégié, la prochaine relance peut échouer avant même de reconstruire.
Comparer avec un agent sain
Le test le plus utile consiste souvent à comparer l’agent suspect avec un agent sain du même pool. Ne cherchez pas toutes les différences. Cherchez celles qui expliquent le run.
compare:
failing_agent: azdo-agent-prod-03
healthy_agent: azdo-agent-prod-01
same_pool: private-linux-prod
same_pipeline_capabilities: true
checks:
- agent_version
- service_user
- free_disk_percent
- workspace_size
- docker_cache_size
- tool_versions
- proxy_dns_firewall_path
- last_bootstrap_commit
- last_successful_pipeline_run
decision:
same_state: investigate pipeline or artifact
local_drift: quarantine failing agent and clean
pool_drift: rollback bootstrap or image change Cette comparaison évite une erreur fréquente : corriger la pipeline alors qu’un seul agent est sale, ou nettoyer une machine alors que tout le pool a reçu une mauvaise image.
Nettoyer avec un périmètre contrôlé
Le nettoyage doit être explicite. Supprimer tout le disque peut masquer une fuite, casser un outil partagé ou supprimer les logs nécessaires à l’incident.
WORK="/opt/azdo-agent/_work"
# Exemple prudent: sortir l'agent du pool avant nettoyage via Azure DevOps UI/API,
# puis nettoyer les workspaces de jobs terminés après sauvegarde des preuves.
systemctl stop vsts.agent.*
# Adapter le périmètre selon la convention du pool.
find "$WORK" -mindepth 1 -maxdepth 1 -type d -name "[0-9]*" -mtime +2 -print
# Exécuter la suppression seulement après validation opérateur.
# find "$WORK" -mindepth 1 -maxdepth 1 -type d -name "[0-9]*" -mtime +2 -exec rm -rf {} +
# Nettoyage Docker contrôlé si le pool construit des images.
docker system df 2>/dev/null || true
# docker builder prune --filter "until=72h" --force
systemctl start vsts.agent.* Pour un agent de production, préférez souvent sortir l’agent du pool, nettoyer, exécuter un job de validation, puis le remettre en service. Cela évite qu’un job critique tombe sur une machine en cours de réparation.
Valider avant de rerun la vraie pipeline
Une relance de production n’est pas un test de santé de l’agent. Exécutez d’abord un job court qui valide les dépendances nécessaires : checkout, restauration de dépendances, écriture dans le workspace, accès réseau, accès registre, publication d’un artefact de test.
steps:
- checkout: self
clean: true
- script: |
set -euo pipefail
echo "agent=$(Agent.Name)"
df -h
mkdir -p "$(Pipeline.Workspace)/agent-validation"
echo "validation" > "$(Pipeline.Workspace)/agent-validation/probe.txt"
test -s "$(Pipeline.Workspace)/agent-validation/probe.txt"
displayName: Validate workspace and disk
- script: |
set -euo pipefail
node --version || true
dotnet --info | head -20 || true
az version | head -20 || true
displayName: Validate toolchain
- publish: $(Pipeline.Workspace)/agent-validation/probe.txt
artifact: agent-validation
displayName: Publish validation artifact Si ce job échoue, la pipeline applicative n’est pas le bon endroit pour continuer le diagnostic.
Décider relance, quarantaine ou rollback
Terminez par une décision lisible. Le runbook doit produire autre chose qu’un agent nettoyé à la main.
Relancer sur le même agent
Disque sain
Workspace propre
Cache validé ou désactivé temporairement
Service agent et identité conformes
Job de validation réussi
Relancer sur un autre agent
Suspicion locale non bloquante
Besoin de distinguer code et machine
Agent suspect sorti du pool pour investigation
Quarantainer l'agent
Disque ou cache corrompu
Permissions incohérentes
Outils locaux hors version attendue
Logs insuffisants pour autoriser un job critique
Rollbacker le changement de pipeline ou d'image
Plusieurs agents touchés
Échec apparu après bootstrap, cache policy ou mise à jour toolchain
Validation échoue sur un pool sain avant le changement Le bon résultat peut être une relance, mais seulement après avoir prouvé que l’agent ne rejoue pas un état cassé.
Conclusion
Un agent Azure DevOps auto-hébergé donne du contrôle : accès réseau privé, outils maîtrisés, proximité avec les dépendances et gouvernance du pool. Il ajoute aussi une responsabilité d’exploitation. Disque, cache, workspace, identité et bootstrap doivent être traités comme des composants de production.
Avant de relancer une pipeline échouée, qualifiez l’état local, comparez avec un agent sain, nettoyez avec un périmètre documenté et validez avec un job court. La décision finale devient défendable : rerun, quarantaine, correction du pool ou rollback du changement qui a rendu l’agent non fiable.