
Votre VM Incus apparaît RUNNING dans incus list, mais incus exec et SSH ne répondent plus ? Quand l'agent invité est mort, c'est que l'OS de la VM n'a pas fini de booter : elle est très probablement bloquée en emergency mode. La réponse courte : on ne passe plus par incus exec (qui exige l'agent), on capture la console série avec incus console, et si cela ne suffit pas, on monte le disque de la VM depuis l'hôte pour lire son journal systemd hors-ligne. Ce guide déroule ce diagnostic de bout en bout, jusqu'à un cas réel où un durcissement a briqué le boot EFI.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Distinguer un agent mort d'un simple souci SSH : pourquoi une VM
RUNNINGreste injoignable. - Capturer la console série d'une VM qui ne répond plus, malgré l'absence de vrai TTY.
- Monter le disque d'une VM stoppée depuis l'hôte (ZFS, dir, qcow2) pour lire son journal.
- Lire le journalctl hors-ligne d'un boot échoué avec
journalctl -D. - Analyser un cas réel où un sysctl de durcissement a cassé le montage
/boot/efi. - Mettre en place les filets de sécurité : snapshots, journald persistant, break-glass root.
Prérequis
Section intitulée « Prérequis »- Un hôte Incus avec au moins une VM (pas un conteneur).
- Un accès root sur l'hôte (les opérations de montage disque l'exigent).
- Des notions de systemd (cibles, unités) et de partitionnement Linux.
Le symptôme : VM RUNNING mais injoignable
Section intitulée « Le symptôme : VM RUNNING mais injoignable »Vous redémarrez une VM, puis plus rien. incus list la montre pourtant bien démarrée :
incus list <vm># +------+---------+------+------+-----------------+-----------+# | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |# +------+---------+------+------+-----------------+-----------+# | <vm> | RUNNING | | | VIRTUAL-MACHINE | 0 |# +------+---------+------+------+-----------------+-----------+Notez l'absence d'adresse IPv4 : l'OS n'a pas configuré son réseau. Une tentative d'exécution confirme le diagnostic :
incus exec <vm> -- whoami# Error: VM agent isn't currently runningLe RUNNING d'Incus signifie seulement que QEMU fait tourner la machine. Il ne dit rien sur l'état du système invité. Ici, l'agent (incus-agent) n'a jamais démarré : l'OS s'est arrêté en cours de route. Ce n'est pas un problème SSH, c'est un boot qui n'aboutit pas (brick ou hang).
Pourquoi les réflexes habituels échouent sur une VM
Section intitulée « Pourquoi les réflexes habituels échouent sur une VM »Sur un conteneur Incus, le dépannage est direct. Sur une VM, plusieurs commandes habituelles tombent à plat, car elles supposent un invité fonctionnel ou un vrai terminal.
| Commande | Sur une VM bloquée | Pourquoi |
|---|---|---|
incus exec <vm> | VM agent isn't currently running | exige l'agent, donc un OS booté |
incus console <vm> --show-log | log série vide ou partiel | le tampon série n'est pas peuplé comme le log d'un conteneur |
incus info <vm> --show-log | peu exploitable pour une VM | pas le détail du boot systemd |
incus console <vm> en pipe | inappropriate ioctl for device | pas de vrai TTY dans un pipe |
L'incus exec est mort avec l'agent. Le --show-log, très utile pour un conteneur, ne donne pas le journal interne du boot d'une VM : il faut donc une autre approche. Et rediriger incus console dans un pipe échoue, car la commande réclame un pseudo-terminal.
Niveau 1 : capturer la console série
Section intitulée « Niveau 1 : capturer la console série »Quand vous voulez simplement voir l'écran de la VM (le message d'erreur du boot), attachez la console série. Le piège : incus console exige un pseudo-terminal, donc une redirection naïve échoue. On force un pty avec script :
timeout 14 script -qec 'incus console <vm>' /dev/null </dev/null 2>&1 | tail -45script -qec '...' /dev/nullexécute la commande dans un pty sans enregistrer de fichier (-qsilencieux,-epropage le code de sortie,-clance la commande).timeout 14coupe au bout de 14 secondes : assez pour capturer l'écran courant.tail -45ne garde que les dernières lignes, là où s'affiche l'état final.
Ce que vous lirez, selon la panne :
You are in emergency mode. After logging in, type "journalctl -xb" to viewsystem logs, "systemctl reboot" to reboot, or "exit" to continue bootup.ou un start job qui ne se termine pas :
[*** ] A start job is running for /boot/efi (1min 30s / no limit)ou encore un kernel panic. Pour détacher la console interactive proprement, tapez Ctrl+a puis q.
Niveau 2 : lire le journal hors-ligne en montant le disque
Section intitulée « Niveau 2 : lire le journal hors-ligne en montant le disque »C'est le bon réflexe. Plutôt que de lutter avec une console aveugle, on stoppe la VM, on monte son disque depuis l'hôte et on lit son journal systemd tranquillement. La marche à suivre dépend du backend de stockage.
Identifiez d'abord le driver :
incus storage list# +---------+--------+-------------+---------+# | NAME | DRIVER | DESCRIPTION | USED BY |# +---------+--------+-------------+---------+# | default | zfs | | 12 |# +---------+--------+-------------+---------+Sur ZFS, le disque de la VM est un zvol. Une fois la VM stoppée, ce zvol est en volmode=none : aucun device /dev/zdN n'est exposé. On l'expose, on lit ses partitions avec kpartx, puis on monte la racine en lecture seule :
incus stop <vm> --force
# Identifier le zvol du disque (suffixe .block)zfs list -t volume | grep <vm>Z=<pool>/virtual-machines/<vm>.block
# Exposer le zvol comme device blocsudo zfs set volmode=dev "$Z"
# kpartx cree les mappings de partitions (/dev/mapper/zd0p1, zd0p2...)sudo kpartx -av /dev/zd0
# Monter la racine en lecture seule (p2 = ext4 racine, p1 = EFI vfat)sudo mkdir -p /mnt/vmsudo mount -o ro /dev/mapper/zd0p2 /mnt/vmAprès diagnostic, nettoyez dans l'ordre inverse :
sudo umount /mnt/vmsudo kpartx -d /dev/zd0sudo zfs set volmode=none "$Z"Sur le backend dir, le disque est une image raw (root.img). On l'attache à un loop device avec scan des partitions (-P) :
incus stop <vm> --force
IMG=/var/lib/incus/storage-pools/default/virtual-machines/<vm>/root.imgsudo losetup -fP "$IMG"losetup -j "$IMG" # retrouver le loopN attribue (ex. /dev/loop0)
sudo mkdir -p /mnt/vmsudo mount -o ro /dev/loop0p2 /mnt/vmNettoyage :
sudo umount /mnt/vmsudo losetup -d /dev/loop0Pour une image qcow2, on passe par le Network Block Device :
incus stop <vm> --force
sudo modprobe nbd max_part=8sudo qemu-nbd --connect=/dev/nbd0 <image>.qcow2
sudo mkdir -p /mnt/vmsudo mount -o ro /dev/nbd0p2 /mnt/vmNettoyage :
sudo umount /mnt/vmsudo qemu-nbd -d /dev/nbd0Une fois la racine montée, lisez le journal du boot échoué. Sur un disque monté, le « boot courant » n'est pas forcément le dernier : listez les boots, puis ciblez l'offset voulu.
# Lister les boots enregistressudo journalctl -D /mnt/vm/var/log/journal --list-boots# IDX BOOT ID FIRST ENTRY LAST ENTRY# -1 a1b2... 2026-06-29 09:14 2026-06-29 09:31# 0 c3d4... 2026-06-29 09:32 2026-06-29 09:32 <- le boot echoue
# Lire les erreurs de ce bootsudo journalctl -D /mnt/vm/var/log/journal -b 0 -p err --no-pager
# Trouver la cause directementsudo journalctl -D /mnt/vm/var/log/journal -b 0 --no-pager \ | grep -iE 'Dependency failed|Failed to mount|emergency'Le grep final remonte presque toujours la chaîne de causalité : une unité qui échoue, une dépendance non satisfaite, puis la bascule en emergency.
Étude de cas : un durcissement qui brique le boot EFI
Section intitulée « Étude de cas : un durcissement qui brique le boot EFI »Voici un cas réel, reproductible, qui illustre toute la chaîne. Le journal hors-ligne révèle ceci :
systemd[1]: Mounting boot-efi.mount - /boot/efi...mount[420]: mount: /boot/efi: unknown filesystem type 'vfat'.systemd[1]: boot-efi.mount: Mount process exited, code=exited, status=32systemd[1]: Failed to mount boot-efi.mount - /boot/efi.systemd[1]: Dependency failed for local-fs.target - Local File Systems.systemd[1]: Reached target emergency.target - Emergency Mode.La racine du problème : un durcissement avait posé kernel.modules_disabled=1 via un drop-in /etc/sysctl.d/. Or ce sysctl est un interrupteur à sens unique : une fois à 1, plus aucun module noyau ne peut être chargé, et on ne peut pas revenir à 0 sans reboot.
systemd applique les sysctl très tôt au boot, via systemd-sysctl. Son ordonnancement par rapport au montage de /boot/efi n'est pas garanti : les deux convergent vers sysinit.target sans ordre mutuel strict. Si kernel.modules_disabled=1 est appliqué avant que le montage de /boot/efi ne déclenche le chargement du module vfat, et si ce module n'est pas déjà chargé, alors le montage échoue. Pas de vfat, pas d'EFI montée, local-fs.target en échec, et bascule en emergency mode.
Récupération et filet de sécurité
Section intitulée « Récupération et filet de sécurité »Avant toute opération risquée sur une VM, prenez un snapshot. C'est votre marche arrière :
# Avant un changement de boot risqueincus snapshot create <vm> avant-durcissement
# Revenir en arriere si la VM ne boote plusincus snapshot restore <vm> avant-durcissementCôté accès, ne verrouillez jamais root sans laisser une voie de secours. L'emergency mode est précisément le moment où vous en avez besoin :
- un compte de récupération local avec mot de passe,
- ou un mot de passe GRUB documenté pour éditer la ligne de commande noyau au boot.
Prévention : la checklist
Section intitulée « Prévention : la checklist »Le meilleur debug est celui qu'on n'a pas à faire. Trois réflexes évitent la majorité de ces blocages :
-
Journald persistant dès le départ
Sur vos VM de lab, activez
Storage=persistent(ou créez/var/log/journal/) dès la création. Sans cela, le journal du boot échoué part en fumée au reboot. -
Tester les changements de boot sur une VM jetable
Tout ce qui touche au boot (
/etc/fstab, ligne de commande noyau, sysctl à sens unique) se teste sur une VM jetable protégée par un snapshot, jamais directement sur une machine qui compte. -
Trouver le fautif par la trace, pas par reboots à l'aveugle
Privilégiez le dry-run de votre configuration (état convergé sans reboot) pour repérer un changement dangereux avant qu'il ne brique le boot, plutôt que d'enchaîner les redémarrages au hasard.
À retenir
Section intitulée « À retenir »- Une VM
RUNNINGsans agent n'a pas fini de booter : ce n'est pas un souci SSH. incus execexige l'agent ; sur une VM bloquée, il renvoieVM agent isn't currently running.- Pour une VM,
--show-logdonne un log série souvent vide : on capture la console série (incus console, détacher avec Ctrl+a q), forcée dans un pty viascript. - Le bon réflexe : stopper la VM, monter son disque depuis l'hôte (ZFS via
volmode=dev+kpartx, dir vialosetup -fP, qcow2 viaqemu-nbd) et lire le journal avecjournalctl -D. volmode=devmasque les partitions du zvol, d'où le recours à kpartx.- Un sysctl à sens unique comme
kernel.modules_disabled=1posé trop tôt peut casser un montage (/boot/efienvfat) et provoquer l'emergency mode. - Snapshots, journald persistant et break-glass root sont vos trois filets de sécurité.
FAQ : questions fréquentes sur le debug d'une VM Incus
Section intitulée « FAQ : questions fréquentes sur le debug d'une VM Incus »L'agent invité est mort
incus exec <vm> s'appuie sur l'incus-agent qui tourne dans la VM. Cet agent ne démarre qu'une fois l'OS invité suffisamment avancé dans son boot.Si la VM est bloquée au boot (emergency mode, start job figé, kernel panic), l'agent n'a jamais démarré :incus exec <vm> -- whoami
# Error: VM agent isn't currently running
Le statut RUNNING d'incus list signifie seulement que QEMU exécute la machine, pas que l'OS invité fonctionne. Ce n'est donc pas un souci de sshd ou de réseau : la VM est restée en amont du boot. Le message Failed to connect to lxd-agent que vous croiserez parfois est de la terminologie LXD, pas Incus.Monter le disque, puis journalctl -D
Quand l'agent est mort, on lit le journal hors-ligne, depuis l'hôte :incus stop <vm> --force
# Exposer + monter le disque (cas ZFS)
sudo zfs set volmode=dev <pool>/virtual-machines/<vm>.block
sudo kpartx -av /dev/zd0
sudo mount -o ro /dev/mapper/zd0p2 /mnt/vm
# Lire le journal du boot echoue
sudo journalctl -D /mnt/vm/var/log/journal --list-boots
sudo journalctl -D /mnt/vm/var/log/journal -b 0 -p err --no-pager
L'option -D (ou --directory) pointe journalctl vers un répertoire de journaux externe. Condition indispensable : le journal de la VM doit être persistant (Storage=persistent), sinon il était en RAM et a disparu au reboot.Peu utile sur une VM
Pour un conteneur,incus console <nom> --show-log affiche le journal de la console, très pratique.Sur une VM, ce log série est souvent vide ou partiel : le tampon série n'est pas peuplé comme le journal d'un conteneur, et vous n'y trouverez pas le détail du boot systemd.Pour une VM, attachez plutôt la console série interactive :incus console <vm>
# Detacher : Ctrl+a puis q
Elle reste disponible même si l'agent ne tourne pas, ce qui permet de voir l'écran d'emergency mode. Mais sans scrollback : pour le détail complet et reproductible, basculez sur le journal hors-ligne (journalctl -D).volmode=dev puis kpartx
Sur ZFS, le disque d'une VM est un zvol. VM stoppée, il est envolmode=none : aucun device exposé.incus stop <vm> --force
Z=<pool>/virtual-machines/<vm>.block
sudo zfs set volmode=dev "$Z" # cree /dev/zd0
sudo kpartx -av /dev/zd0 # cree /dev/mapper/zd0p2
sudo mount -o ro /dev/mapper/zd0p2 /mnt/vm
Point clé : volmode=dev expose /dev/zd0 mais masque ses partitions, d'où le recours à kpartx (partprobe ne suffit pas toujours).Nettoyez dans l'ordre inverse :sudo umount /mnt/vm
sudo kpartx -d /dev/zd0
sudo zfs set volmode=none "$Z"
Un montage qui échoue
Le emergency mode est déclenché quandlocal-fs.target échoue, généralement à cause d'un montage impossible : /etc/fstab erroné, partition absente, ou filesystem qui ne peut pas se monter.Un cas concret et reproductible : un durcissement pose kernel.modules_disabled=1 via sysctl.d. Ce sysctl est un interrupteur à sens unique ; appliqué tôt au boot, il empêche le chargement du module vfat, ce qui casse le montage de /boot/efi :mount: /boot/efi: unknown filesystem type 'vfat'.
Dependency failed for local-fs.target.
Reached target emergency.target.
Le journal hors-ligne (journalctl -D ... | grep -iE 'Dependency failed|Failed to mount') révèle la chaîne de causalité exacte. Un sysctl à sens unique doit être appliqué tard, pas dans un drop-in de boot.