Le démarrage, du firmware à systemd
Pourquoi
Dans la fiche de serveur que vous avez commencée à la leçon précédente, une ligne est restée vague : « sig-app-1 redémarre correctement ». Camille l'affirmait, et c'était sans doute vrai le jour où elle l'a écrit. Mais depuis, des noyaux ont été installés par les mises à jour automatiques, un paramètre a peut-être été ajouté à la ligne de commande du noyau pour régler un problème oublié, et personne n'a redémarré sig-outils depuis quatre mois. Le jour où la machine redémarrera, pour une mise à jour de sécurité ou parce que Scaleway migre l'hyperviseur, vous découvrirez tout cela d'un coup, sans doute à un moment mal choisi.
Le démarrage est le seul moment de la vie d'un serveur où tout est remis à plat : la configuration écrite sur disque remplace l'état en mémoire. C'est donc à ce moment que se révèlent les écarts entre ce qui tourne et ce qui est réellement configuré : un service démarré à la main mais jamais activé, un montage ajouté en direct mais absent de /etc/fstab, un paramètre du noyau réglé à chaud et jamais rendu persistant. Comprendre la chaîne de démarrage, c'est savoir où regarder quand un maillon casse, et savoir lequel modifier pour obtenir un effet durable.
Cette leçon suit le démarrage dans l'ordre : le firmware, le chargeur d'amorçage, le noyau, l'initramfs, puis systemd jusqu'à la cible finale, et enfin cloud-init, propre aux instances de cloud. Elle vous apprend à observer chaque étape sur une machine qui fonctionne. Réparer une machine qui ne démarre plus est l'objet de la leçon 5 : on ne répare bien que ce que l'on a d'abord vu fonctionner.
Les concepts
La chaîne, vue d'ensemble
Le démarrage est une course de relais : chaque étage charge le suivant en mémoire, lui passe la main, et disparaît (ou presque).
mise sous tension
|
v
[1] firmware (BIOS ou UEFI) initialise le matériel, choisit le disque
|
v
[2] chargeur d'amorçage (GRUB 2) affiche le menu, charge noyau + initramfs
| et leur passe la ligne de commande
v
[3] noyau Linux (vmlinuz) initialise processeurs, mémoire, pilotes
|
v
[4] initramfs (/init) trouve et monte le vrai système de fichiers racine
| switch_root
v
[5] systemd, PID 1 atteint default.target : montages, réseau, services
|
v
[6] cloud-init (instances cloud) configure l'instance au premier démarrage
|
v
invite de connexion, sshd, signalements.serviceChaque étage a sa configuration, ses journaux (ou leur absence) et ses pannes typiques. Le principe à retenir : un étage ne sait rien de la configuration des étages suivants. Le firmware ne lit pas /etc ; GRUB ne lit pas /etc/fstab ; le noyau ne sait pas ce qu'est un service. Chacun reçoit juste assez d'informations de l'étage précédent pour trouver le suivant.
Le firmware : BIOS hérité et UEFI
Le firmware (micrologiciel) est le programme stocké dans la carte mère, ou fourni par l'hyperviseur pour une machine virtuelle, qui s'exécute en premier. Deux familles coexistent.
Le BIOS hérité (legacy BIOS), conçu pour l'IBM PC de 1981, ne sait presque rien des disques : il lit le premier secteur (512 octets, le Master Boot Record) du disque choisi et exécute les 446 premiers octets. Ce minuscule programme ne peut pas lire un système de fichiers ; GRUB y place donc un premier étage qui charge un second étage (core.img) caché juste après le MBR, ou, sur un disque GPT, dans une petite partition dédiée sans système de fichiers, la BIOS boot partition.
L'UEFI (Unified Extensible Firmware Interface), généralisé depuis les années 2010, est un véritable petit système : il sait lire une partition FAT, exécuter des programmes au format PE (.efi), et conserve dans une mémoire non volatile des variables qui décrivent les entrées de démarrage et leur ordre. Il cherche ses programmes dans l'ESP (EFI System Partition) : une partition FAT32 de quelques centaines de mégaoctets, de type GPT EF00, montée sous Linux sur /boot/efi. On y trouve un répertoire par système installé (EFI/ubuntu/, EFI/debian/) et un chemin de secours, EFI/BOOT/BOOTX64.EFI, que le firmware essaie quand aucune entrée enregistrée ne fonctionne.
| BIOS hérité | UEFI | |
|---|---|---|
| Où vit le premier étage | 446 octets du MBR | fichier .efi dans l'ESP |
| Table de partitions | MBR ou GPT (avec BIOS boot partition) | GPT (MBR toléré) |
| Liste des systèmes | aucune, ordre des disques | variables Boot0000, Boot0001, BootOrder |
| Vérification de signature | impossible | Secure Boot |
| Ce que voit Linux | pas de /sys/firmware/efi | /sys/firmware/efi/ présent |
Secure Boot, shim et MOK
Secure Boot est une fonction de l'UEFI : le firmware n'exécute que des programmes signés par une clé présente dans sa base db. Sur la quasi-totalité des machines, cette base contient la clé de Microsoft, et pas celle de Canonical ni de Debian. D'où un intermédiaire : shim, un petit chargeur signé par Microsoft, qui contient à son tour la clé de la distribution. La chaîne de confiance devient :
firmware (clé Microsoft dans db)
-> shimx64.efi signé par Microsoft, embarque la clé Canonical ou Debian
-> grubx64.efi signé par la distribution, vérifié par shim
-> vmlinuz signé par la distribution, vérifié par GRUB via shim
-> modules le noyau refuse les modules non signésLe noyau démarré sous Secure Boot passe en mode lockdown : il refuse les modules non signés et ferme les interfaces qui permettraient à root de modifier le noyau en cours d'exécution. Pour charger un module compilé localement (un pilote DKMS, par exemple), on enrôle sa propre clé, une MOK (Machine Owner Key), avec mokutil --import ; l'enrôlement se confirme au redémarrage suivant, sur la console, dans l'écran bleu de MokManager. Ce détail compte en cloud : sans accès console, une MOK ne peut pas être enrôlée.
GRUB 2
GRUB 2 (GRand Unified Bootloader) est le chargeur d'amorçage d'Ubuntu, de Debian et de Red Hat. Son rôle : afficher éventuellement un menu, puis charger en mémoire un noyau et un initramfs, et leur transmettre une ligne de commande.
Point essentiel : on n'édite jamais grub.cfg à la main. Le fichier /boot/grub/grub.cfg est généré par grub-mkconfig, à partir de deux sources :
/etc/default/grub(et, sur Debian et Ubuntu, les fichiers/etc/default/grub.d/*.cfg) : des variablesCLÉ=valeur, lues comme un script shell ;/etc/grub.d/: des scripts exécutés dans l'ordre de leur nom, dont chacun écrit une partie du menu.10_linuxcherche les noyaux présents dans/bootet produit une entrée par noyau ;30_os-probercherche d'autres systèmes ;40_customaccueille les entrées écrites à la main.
Sur Debian et Ubuntu, la commande update-grub est un raccourci pour grub-mkconfig -o /boot/grub/grub.cfg. Les paquets de noyau l'appellent eux-mêmes à chaque installation ou suppression d'un noyau : c'est ainsi que le nouveau noyau apparaît dans le menu sans intervention. Toute modification manuelle de grub.cfg est donc effacée à la prochaine mise à jour du noyau.
Sur Red Hat, le principe est le même avec d'autres noms : grub2-mkconfig, et surtout grubby pour modifier la ligne de commande, les entrées étant décrites par des fichiers BLS (Boot Loader Specification) dans /boot/loader/entries/.
Les variables que vous rencontrerez, d'après le manuel de GRUB 2.12 :
| Variable | Rôle | Défaut amont |
|---|---|---|
GRUB_DEFAULT | entrée choisie par défaut : numéro (à partir de 0), identifiant, ou saved | 0 |
GRUB_TIMEOUT | secondes avant de démarrer l'entrée par défaut ; 0 démarre sans attendre, -1 attend indéfiniment | 5 |
GRUB_TIMEOUT_STYLE | menu : affiche le menu pendant le délai ; countdown ou hidden : attend sans afficher le menu, qui n'apparaît que si l'on presse Échap, F4 ou maintient Maj | menu |
GRUB_CMDLINE_LINUX | paramètres ajoutés à toutes les entrées Linux, y compris le mode de secours | vide |
GRUB_CMDLINE_LINUX_DEFAULT | paramètres ajoutés seulement aux entrées normales, après les précédents | vide (Debian et Ubuntu y mettent quiet, parfois splash) |
GRUB_DISABLE_RECOVERY | true supprime les entrées « recovery mode » | non défini |
GRUB_TERMINAL | terminal d'entrée et de sortie : console, serial, ou les deux | terminal natif |
Le noyau et sa ligne de commande
GRUB charge le fichier du noyau (/boot/vmlinuz-<version>) et l'initramfs correspondant (/boot/initrd.img-<version>), puis passe au noyau une ligne de commande : une simple chaîne de mots séparés par des espaces. Le noyau en consomme une partie et, selon sa documentation, transmet le reste : un paramètre qu'il ne reconnaît pas et qui ne contient pas de point est passé au programme init, dans son environnement s'il contient un =, en argument sinon. C'est ainsi que systemd reçoit ses propres paramètres (systemd.unit=), et que les modules reçoivent les leurs (nom_du_module.paramètre=valeur).
Les paramètres que vous verrez sur tout serveur :
root=: le système de fichiers racine, presque toujours désigné par un identifiant stable (root=UUID=...,root=PARTUUID=...,root=LABEL=...) plutôt que par un nom de périphérique comme/dev/vda1, qui peut changer d'un démarrage à l'autre.ro: monter la racine en lecture seule au départ. Ce n'est pas l'état final : systemd la remonte en lecture-écriture après la vérification du système de fichiers, d'après/etc/fstab.rwfait l'inverse.quiet: réduit les messages du noyau sur la console ; systemd le comprend aussi et cesse d'afficher l'état des unités. Pratique sur un poste, discutable sur un serveur, où ces messages sont précieux en cas de panne.console=: où le noyau écrit ses messages.console=tty1désigne l'écran virtuel,console=ttyS0,115200le premier port série à 115 200 bauds (le format estvitesse,parité,bits:9600n8par défaut). On peut en donner plusieurs : le noyau écrit sur toutes, et la dernière devient/dev/console, celle où s'affichent les invites interactives (demande de phrase de passe, shell de secours).init=: le programme à lancer à la place de/sbin/init;rdinit=fait de même pour le/initde l'initramfs. Utilisés en dépannage (leçon 5).panic=: comportement après une panique du noyau :panic=10redémarre au bout de dix secondes,0attend indéfiniment, une valeur négative redémarre immédiatement.
La console série mérite une attention particulière en cloud. La « console » que Scaleway propose dans sa console web est une console série (TTY) : elle ne montre que ce qui est écrit sur ttyS0. Si le noyau et systemd n'y écrivent pas, la console reste noire pendant tout le démarrage, et vous ne verrez rien d'une panne. Les images cloud d'Ubuntu règlent cela dans /etc/default/grub.d/50-cloudimg-settings.cfg, avec GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0" et GRUB_TIMEOUT=0.
L'initramfs
Le noyau doit monter le système de fichiers racine, mais il peut lui manquer le pilote pour y accéder (contrôleur NVMe, virtio, RAID logiciel, LVM, chiffrement LUKS) : ces pilotes sont des modules, rangés... sur la racine elle-même. L'initramfs (initial RAM file system) résout cet œuf et cette poule : c'est une archive cpio compressée, chargée en mémoire par GRUB à côté du noyau, qui contient un mini système (un /init, quelques outils, les modules nécessaires). Le noyau la décompresse dans un tmpfs et exécute son /init, qui charge les pilotes, attend que le disque apparaisse, déverrouille et assemble ce qu'il faut, monte la vraie racine sur /root (ou /sysroot), puis exécute switch_root : la racine change, la mémoire de l'initramfs est libérée, et le vrai /sbin/init, c'est-à-dire systemd, démarre avec le PID 1.
Deux générateurs d'initramfs dominent :
| initramfs-tools | dracut | |
|---|---|---|
| Distributions | Debian 13, Ubuntu 24.04 (par défaut) | Red Hat, Fedora, SUSE ; Ubuntu depuis 25.10 ; disponible sur Debian et Ubuntu 24.04 |
/init | script shell avec busybox | systemd lui-même, dans l'initramfs |
| Configuration | /etc/initramfs-tools/initramfs.conf, conf.d/, modules, hooks/ | /etc/dracut.conf, /etc/dracut.conf.d/ |
| Régénérer | update-initramfs -u | dracut -f |
| Lister le contenu | lsinitramfs | lsinitrd |
| Invite en cas d'échec | (initramfs) de busybox | shell d'urgence de systemd |
Le réglage MODULES= d'initramfs.conf vaut most par défaut : l'image embarque la plupart des pilotes de systèmes de fichiers et de disques. C'est plus gros que dep (seulement ce que la machine actuelle utilise), mais l'image reste démarrable si l'on déplace le disque vers une autre machine, ou si Scaleway présente le volume par un autre contrôleur. Sur un serveur, gardez most.
systemd et les cibles
Une fois lancé, systemd ne déroule pas une liste : il calcule un objectif. Cet objectif est une cible (target), une unité qui ne fait rien elle-même et sert de point de rendez-vous. Au démarrage, systemd active default.target et tout ce qu'elle tire par ses dépendances (Wants=, Requires=), puis démarre en parallèle tout ce que les relations d'ordre (After=, Before=) permettent. Ces notions ont été vues dans Services et journaux ; voici les cibles qui jalonnent le démarrage, d'après bootup(7) :
local-fs.target swap.target cryptsetup.target (montages, fsck, udev, sysctl)
\ | /
+------ sysinit.target ---+
|
sockets.target timers.target paths.target
|
basic.target
|
multi-user.target <- serveur : sshd, cron, signalements.service
|
graphical.target <- ajoute un gestionnaire d'affichage, s'il existedefault.target n'est qu'un alias : un lien symbolique vers l'une des cibles finales. Les cibles à connaître :
| Cible | Ce qu'elle contient | Équivalent SysV |
|---|---|---|
emergency.target | un shell root sur la console, rien d'autre : ni montages (la racine reste en lecture seule), ni services | aucun |
rescue.target | le système de base : montages locaux, sysinit.target, puis un shell root ; pas de réseau, pas de services | niveau 1, single user |
multi-user.target | système complet sans interface graphique : réseau, sshd, services | niveaux 2 à 4 |
graphical.target | multi-user.target plus le gestionnaire d'affichage | niveau 5 |
reboot.target, poweroff.target | redémarrage, extinction | 6, 0 |
Les anciens noms runlevel1.target à runlevel5.target existent encore comme alias, et le noyau accepte toujours single, 1 ou 3 sur sa ligne de commande, que systemd traduit. Mais ce sont des souvenirs : on parle de cibles.
Note
Sur les images Ubuntu Server et Debian, systemctl get-default répond souvent graphical.target, même sans aucune interface graphique installée : c'est la valeur par défaut livrée par systemd. Sans gestionnaire d'affichage, cette cible n'ajoute rien à multi-user.target, et le résultat est identique. Le régler explicitement sur multi-user.target rend simplement la fiche du serveur plus honnête.
cloud-init, l'étage propre au cloud
Sur une instance Scaleway, un dernier acteur intervient : cloud-init. Il transforme une image générique, identique pour tous les clients, en votre machine : nom d'hôte, clés SSH, réseau, et les données utilisateur fournies à la création (détaillées dans la leçon sur les instances). Il lit ces informations sur le service de métadonnées de Scaleway, joignable depuis l'instance à l'adresse 169.254.42.42.
cloud-init n'est pas un démon : c'est une série d'unités systemd, accrochées à des moments précis du démarrage. Sa documentation décrit cinq étapes :
| Étape | Unité systemd | Moment | Rôle |
|---|---|---|---|
| Detect | générateur systemd et ds-identify | avant tout | détecte la plateforme ; désactive cloud-init s'il n'en trouve aucune |
| Local | cloud-init-local.service | dès que / est monté en écriture, avant le réseau | trouve les métadonnées locales, écrit la configuration réseau |
| Network | cloud-init.service (Ubuntu 24.04), cloud-init-network.service (Debian 13) | réseau configuré ; bloque sshd et la connexion | interroge les métadonnées, traite les données utilisateur, prépare les disques, crée les utilisateurs et les clés |
| Config | cloud-config.service | ensuite, sans bloquer | modules de configuration (runcmd est préparé ici) |
| Final | cloud-final.service | en toute fin, à la manière de l'ancien rc.local | installation de paquets, scripts utilisateur, message final |
La différence de nom d'unité entre les deux distributions vient d'un changement de la version 24.3 de cloud-init : les étapes, auparavant quatre processus Python distincts, sont désormais servies par un processus unique, cloud-init-main.service, et l'ancienne cloud-init.service a été renommée cloud-init-network.service. Debian 13 (cloud-init 25.1.4) a adopté ce fonctionnement. Ubuntu 24.04, bien que mise à jour vers une version récente, retire ce changement par un correctif (no-single-process.patch) pour ne pas casser les unités qui en dépendent : on y trouve toujours cloud-init.service. Une unité de votre cru qui doit attendre cloud-init ne s'écrit donc pas de la même façon sur sig-app-1 et sur sig-outils.
Comment cloud-init sait-il que c'est le premier démarrage ? Il compare l'identifiant de l'instance fourni par les métadonnées à celui qu'il a mémorisé dans /var/lib/cloud/data/instance-id. S'ils diffèrent (premier démarrage, ou image clonée sur une nouvelle instance), les modules marqués « une fois par instance » s'exécutent ; sinon, seuls les modules « à chaque démarrage » tournent. C'est pourquoi modifier les données utilisateur d'une instance existante ne change, en général, rien à son prochain redémarrage.
En pratique
Les commandes de cette section se lancent sur sig-app-1 (Ubuntu 24.04) et sig-outils (Debian 13). Celles qui ne font que lire sont sans risque. Les sorties montrées sont typiques : elles sont construites d'après la documentation et le format des outils, pas copiées d'une machine réelle, et les valeurs (dates, durées, identifiants) varient d'une machine à l'autre.
UEFI ou BIOS ?
$ test -d /sys/firmware/efi && echo UEFI || echo "BIOS hérité"
Le répertoire /sys/firmware/efi n'existe que si le noyau a été lancé par un firmware UEFI. D'après la documentation Scaleway, le mode de démarrage par défaut est le « local boot » : le noyau et GRUB viennent du volume de l'instance, et les types d'instances récents démarrent en UEFI (un volume d'une ancienne gamme qui ne prend pas en charge l'UEFI ne peut pas démarrer sur un autre type d'instance). D'anciennes gammes démarraient par un noyau fourni par la plateforme (bootscript, désormais abandonné), sans table de partitions ni chargeur sur le disque. Une machine héritée très ancienne peut encore relever de ce second cas : vérifiez, ne supposez pas.
Puis l'état de Secure Boot :
$ mokutil --sb-state
Les réponses possibles sont SecureBoot enabled, SecureBoot disabled, ou EFI variables are not supported on this system sur une machine BIOS. La documentation des instances Scaleway ne décrit pas de réglage Secure Boot : constatez l'état réel et notez-le dans la fiche.
Lire les entrées UEFI
$ sudo efibootmgr -v
efibootmgr lit les variables UEFI exposées par le noyau dans /sys/firmware/efi/efivars. -v (verbose) affiche, pour chaque entrée, le chemin complet du fichier à exécuter. La sortie ressemble à ceci :
BootCurrent: 0001
Timeout: 0 seconds
BootOrder: 0001,0000
Boot0000* UiApp FvVol(7cb8bdc9-f8eb-4f34-aaea-3ee4af6516a1)/FvFile(462caa21-7614-4503-836e-8ab6f4662331)
Boot0001* ubuntu HD(15,GPT,4d3c...,0x2800,0x35000)/File(\EFI\ubuntu\shimx64.efi)Ligne par ligne : BootCurrent est l'entrée qui a servi au démarrage en cours ; BootOrder l'ordre d'essai ; chaque BootXXXX une entrée, l'astérisque signalant qu'elle est active. L'entrée ubuntu désigne la partition 15 du disque GPT et, dans cette partition (l'ESP), le fichier shimx64.efi : la chaîne Secure Boot commence là, même quand Secure Boot est désactivé. Sur Debian, le chemin est \EFI\debian\shimx64.efi.
Vérifiez ensuite que l'ESP est montée et regardez son contenu :
$ findmnt /boot/efi
$ sudo ls -R /boot/efi/EFI
findmnt affiche le périphérique, le type (vfat) et les options du montage. Dans EFI/ubuntu/, vous trouverez shimx64.efi, grubx64.efi, mmx64.efi (MokManager) et un petit grub.cfg, qui ne contient que trois lignes : chercher la partition /boot par son UUID, puis charger le vrai /boot/grub/grub.cfg.
efibootmgr sait aussi modifier : -o 0001,0000 réécrit l'ordre, -n 0000 choisit l'entrée du prochain démarrage seulement. Sur une instance de cloud, abstenez-vous : une erreur rend la machine indémarrable, et seul le mode de secours permettra de corriger.
Lire la configuration de GRUB
$ grep -v '^#' /etc/default/grub | grep -v '^$'
$ ls /etc/default/grub.d/ /etc/grub.d/
Sur une image cloud Ubuntu, la sortie de la première commande ressemble à ceci :
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`( . /etc/os-release; echo ${NAME:-Ubuntu} ) 2>/dev/null || echo Ubuntu`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""Mais ce n'est pas la valeur finale : les fichiers de /etc/default/grub.d/ sont lus après /etc/default/grub et le remplacent. Sur une image cloud, 50-cloudimg-settings.cfg y redéfinit GRUB_CMDLINE_LINUX_DEFAULT et GRUB_TIMEOUT. Modifier /etc/default/grub sans regarder ce répertoire est l'erreur la plus fréquente : la modification est écrasée par un fichier lu ensuite, et rien ne change. Pour savoir ce que GRUB fera vraiment, lisez le fichier généré :
$ sudo grep -E '^\s*(menuentry|submenu|linux)\s' /boot/grub/grub.cfg | head
La sortie ressemble à ceci :
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-0b2f...' {
linux /boot/vmlinuz-6.8.0-85-generic root=PARTUUID=5e1b... ro console=tty1 console=ttyS0
submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-0b2f...' {
menuentry 'Ubuntu, with Linux 6.8.0-85-generic' --class ubuntu ...
linux /boot/vmlinuz-6.8.0-85-generic root=PARTUUID=5e1b... ro console=tty1 console=ttyS0
menuentry 'Ubuntu, with Linux 6.8.0-85-generic (recovery mode)' --class ubuntu ...
linux /boot/vmlinuz-6.8.0-85-generic root=PARTUUID=5e1b... ro recovery nomodeset dis_ucode_ldr
menuentry 'Ubuntu, with Linux 6.8.0-79-generic' --class ubuntu ...Vous y retrouvez l'entrée par défaut, puis le sous-menu « Advanced options » qui liste chaque noyau installé, avec sa variante de secours. C'est dans ce sous-menu que l'on choisit l'ancien noyau quand le nouveau ne démarre pas (leçon 5), d'où l'importance de toujours en conserver au moins deux (leçon 4).
Modifier durablement la ligne de commande
Exemple concret : vous voulez que sig-app-1 affiche sur la console série tous les messages de démarrage, et redémarre seul dix secondes après une panique du noyau au lieu de rester figé. Ne touchez ni à grub.cfg ni au fichier de l'image : ajoutez votre propre fichier, lu après les autres.
$ sudoedit /etc/default/grub.d/90-lyneko.cfg
# Réglages Lyneko pour sig-app-1, voir la fiche du serveur.
# Console série en dernier : c'est elle qui reçoit les invites interactives.
GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200 panic=10"
# Laisser 3 secondes pour intercepter le menu depuis la console série.
GRUB_TIMEOUT_STYLE=countdown
GRUB_TIMEOUT=3
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200"Chaque choix a une raison. quiet disparaît volontairement : sur un serveur, on veut voir les messages. panic=10 évite qu'une panique laisse l'instance figée jusqu'à une intervention humaine ; le service est rétabli plus vite, mais une panique en boucle peut aussi passer inaperçue, d'où la surveillance des redémarrages (journalctl --list-boots). GRUB_TERMINAL="console serial" fait apparaître le menu de GRUB aussi sur la console série de Scaleway : sans cela, il n'existe que sur un écran virtuel que personne ne voit. Trois secondes de délai par démarrage, c'est le prix pour pouvoir choisir un ancien noyau sans passer par le mode de secours.
Régénérez puis vérifiez :
$ sudo update-grub
$ sudo grep -m1 -E '^\s*linux\s' /boot/grub/grub.cfg
update-grub affiche les noyaux qu'il trouve (Found linux image: /boot/vmlinuz-6.8.0-85-generic, puis Found initrd image: ...) et termine par done. La seconde commande doit montrer vos nouveaux paramètres. Ils ne prendront effet qu'au prochain démarrage ; après celui-ci, vérifiez ce que le noyau a réellement reçu :
$ cat /proc/cmdline
Sortie typique :
BOOT_IMAGE=/boot/vmlinuz-6.8.0-85-generic root=PARTUUID=5e1b... ro console=tty1 console=ttyS0,115200 panic=10BOOT_IMAGE= est ajouté par GRUB : le noyau ne le reconnaît pas et le transmet à init, qui l'ignore. /proc/cmdline est la seule vérité : c'est ce que le noyau en cours a reçu, quoi que disent les fichiers.
Tip
Pour un paramètre de module plutôt que du noyau lui-même, la ligne de commande n'est souvent pas le bon endroit : un fichier dans /etc/modprobe.d/ suffit si le module n'est pas nécessaire au démarrage. La leçon 3 traite des modules et des paramètres réglables à chaud.
Inspecter l'initramfs
$ ls -lh /boot/
$ lsinitramfs /boot/initrd.img-$(uname -r) | grep -E 'virtio|nvme|ext4' | head
La première commande montre, pour chaque version, le trio vmlinuz-<version>, initrd.img-<version>, config-<version>, plus les liens vmlinuz et initrd.img vers la version la plus récente. uname -r donne la version du noyau en cours, qui n'est pas forcément la plus récente installée (signe d'un redémarrage en attente). lsinitramfs liste le contenu de l'archive ; on y vérifie qu'un pilote est bien présent. La sortie ressemble à ceci :
usr/lib/modules/6.8.0-85-generic/kernel/drivers/block/virtio_blk.ko.zst
usr/lib/modules/6.8.0-85-generic/kernel/drivers/net/virtio_net.ko.zst
usr/lib/modules/6.8.0-85-generic/kernel/drivers/nvme/host/nvme.ko.zst
usr/lib/modules/6.8.0-85-generic/kernel/fs/ext4/ext4.ko.zstSur un noyau Ubuntu, certains pilotes courants sont compilés directement dans le noyau et n'apparaissent pas comme modules : leur absence de la liste n'est pas une erreur. grep -w virtio_blk /lib/modules/$(uname -r)/modules.builtin lève le doute.
L'initramfs est régénéré automatiquement par les paquets qui en dépendent (nouveau noyau, mise à jour de cryptsetup, lvm2, microcode). Vous le régénérez vous-même après avoir modifié la configuration d'initramfs-tools, ou un fichier qu'il embarque (/etc/modprobe.d/, /etc/crypttab) :
$ sudo update-initramfs -u -k all
-u met à jour une image existante ; -k all le fait pour tous les noyaux installés qui ont déjà une image (sans -k, seul le plus récent est traité). Sur Debian, un peu de patience : c'est l'étape la plus lente d'une mise à jour de noyau.
Sur un système Red Hat, l'équivalent est sudo dracut -f --regenerate-all, et lsinitrd pour lire le contenu.
Cible par défaut et changement de cible
Sortie typique :
$ systemctl get-default
graphical.target
$ sudo systemctl set-default multi-user.target
Removed "/etc/systemd/system/default.target".
Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/multi-user.target.
set-default ne fait que remplacer le lien symbolique /etc/systemd/system/default.target. Il ne change rien à l'état actuel, seulement au prochain démarrage.
Pour changer de cible maintenant, il existe systemctl isolate : il démarre la cible demandée et arrête tout ce qui n'en fait pas partie. sudo systemctl rescue équivaut à isolate rescue.target. Sur un serveur distant, c'est une manière très efficace de se couper l'accès : rescue.target ne contient ni le réseau ni sshd. Cette commande ne se lance que depuis la console série, en connaissance de cause.
Pour un seul démarrage dans une autre cible, on ajoute au menu de GRUB (touche e sur l'entrée, voir leçon 5) le paramètre systemd.unit=rescue.target ou systemd.unit=emergency.target. Rien n'est modifié sur le disque.
Mesurer le démarrage
$ systemd-analyze time
Sortie typique sur une instance Ubuntu démarrée par GRUB :
Startup finished in 3.112s (kernel) + 14.876s (userspace) = 17.989s
graphical.target reached after 14.802s in userspace.La décomposition dépend de ce que systemd peut mesurer. kernel va du lancement du noyau au démarrage de systemd dans le système réel : avec initramfs-tools, le temps passé dans l'initramfs y est compté, car systemd n'y tourne pas. Avec dracut, systemd s'exécute déjà dans l'initramfs et une rubrique (initrd) apparaît. Les rubriques (firmware) et (loader) n'apparaissent que si le chargeur transmet ces mesures à systemd (c'est le cas de systemd-boot, pas de GRUB tel que livré par Debian et Ubuntu). userspace va du démarrage de systemd jusqu'à la cible par défaut.
Qui a pris le plus de temps ?
$ systemd-analyze blame | head
La sortie ressemble à ceci :
8.204s cloud-init.service
3.921s systemd-networkd-wait-online.service
1.487s snapd.seeded.service
1.022s cloud-init-local.service
812ms dev-vda1.device
655ms apt-daily-upgrade.service
...Cette liste trie les unités par durée d'initialisation. La page systemd-analyze(1) prévient qu'elle peut induire en erreur : une unité peut sembler lente simplement parce qu'elle attend une autre unité. Elle n'affiche pas non plus les services Type=simple, considérés comme démarrés dès leur lancement. signalements.service, qui est de ce type, n'y figurera donc jamais, même si Gunicorn met dix secondes à être prêt.
La vraie question est souvent : qu'est-ce qui retarde la cible ?
$ systemd-analyze critical-chain signalements.service
La sortie ressemble à ceci :
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.
signalements.service @14.731s
└─network-online.target @14.702s
└─systemd-networkd-wait-online.service @10.779s +3.921s
└─systemd-networkd.service @10.533s +201ms
└─cloud-init-local.service @9.460s +1.022s
└─systemd-remount-fs.service @1.204s +88ms
└─...On lit cet arbre de haut en bas : @ donne l'instant où l'unité est devenue active depuis le début de l'espace utilisateur, + le temps qu'elle a mis à démarrer. Ici, Signalements attend network-online.target, qui attend que systemd-networkd-wait-online constate que le réseau est configuré : près de quatre secondes, la plus grosse part de la chaîne. Ce n'est pas forcément un problème (Signalements a besoin du réseau pour joindre sig-db), mais c'est là qu'il faut regarder si le démarrage devient lent : une interface déclarée mais jamais configurée fait attendre wait-online jusqu'à son délai maximal, deux minutes par défaut.
Pour une vue d'ensemble :
$ systemd-analyze plot > demarrage-sig-app-1.svg
plot produit une image SVG où chaque unité est une barre sur un axe de temps : on y voit d'un coup d'œil ce qui démarre en parallèle et ce qui attend. Copiez le fichier sur votre poste et ouvrez-le dans un navigateur.
Le journal du démarrage précédent
$ journalctl --list-boots | tail -3
$ journalctl -b -1 -p warning --no-pager | head -40
$ journalctl -b 0 -k --no-pager | head -20
--list-boots affiche un démarrage par ligne, avec son index (0 le démarrage en cours, -1 le précédent), son identifiant et les dates de première et dernière entrée. Un démarrage dont la dernière entrée précède de peu le suivant sans message d'arrêt trahit un arrêt brutal : panique, coupure, extinction forcée depuis la console Scaleway. -b -1 -p warning montre les avertissements et erreurs du démarrage précédent, -b 0 -k les messages du noyau depuis le démarrage en cours (dont la ligne Kernel command line:). Ce n'est possible que si le journal est persistant (voir Services et journaux) ; il l'est par défaut sur Ubuntu et Debian.
Suivre cloud-init
$ cloud-init status --long
La sortie ressemble à ceci :
status: done
extended_status: done
boot_status_code: enabled-by-generator
last_update: Mon, 05 Oct 2026 07:42:18 +0000
detail: DataSourceScaleway
errors: []
recoverable_errors: {}status: done indique que toutes les étapes sont terminées ; running qu'elles sont en cours ; error qu'au moins un module a échoué. detail donne la source de données détectée, ici celle de Scaleway. Dans un script qui doit attendre la fin de cloud-init (par exemple avant de déployer l'application sur une instance neuve), cloud-init status --wait bloque jusqu'à la fin et renvoie un code de sortie non nul en cas d'erreur.
Où cloud-init a-t-il passé son temps, et qu'a-t-il fait ?
$ sudo cloud-init analyze show | head -30
$ sudo less /var/log/cloud-init.log
$ sudo less /var/log/cloud-init-output.log
$ sudo cloud-init query v1.instance_id
analyze show décompose chaque étape module par module ; analyze blame les trie par durée. /var/log/cloud-init.log est le journal détaillé de cloud-init lui-même : la détection de la plateforme, chaque module exécuté ou ignoré, et pourquoi. /var/log/cloud-init-output.log recueille la sortie des commandes lancées (runcmd, scripts utilisateur, installation de paquets) : c'est là qu'on lit l'erreur d'un script de données utilisateur. La dernière commande affiche l'identifiant d'instance auquel cloud-init compare /var/lib/cloud/data/instance-id.
Warning
cloud-init clean efface l'état de cloud-init pour qu'il se comporte, au prochain démarrage, comme sur une instance neuve : régénération des clés d'hôte SSH, réécriture de la configuration réseau, réexécution des données utilisateur. C'est utile pour préparer une image, désastreux sur sig-app-1 en production.
Arrêter et redémarrer proprement
$ sudo systemctl reboot
$ sudo systemctl poweroff
Ces deux commandes demandent à systemd d'atteindre reboot.target ou poweroff.target : les services sont arrêtés dans l'ordre inverse de leurs dépendances (Signalements avant le réseau, le réseau avant le démontage des disques), chacun recevant SIGTERM puis, après son délai, SIGKILL. C'est la seule manière d'arrêter qui laisse à Gunicorn le temps de finir ses requêtes en cours.
Pour prévenir les personnes connectées et laisser un délai :
$ sudo shutdown -r +15 "Redémarrage de sig-app-1 pour le noyau 6.8.0-85, retour estimé dans 5 minutes."
$ shutdown --show
$ sudo shutdown -c
-r demande un redémarrage (sans option, shutdown éteint la machine) ; +15 le planifie dans quinze minutes (on peut aussi écrire 23:30, ou now) ; le texte qui suit est diffusé à tous les terminaux connectés, maintenant puis à intervalles réguliers. D'après shutdown(8), cinq minutes avant l'échéance, le fichier /run/nologin est créé : les nouvelles connexions sont refusées, sauf pour root. --show affiche l'action planifiée, -c l'annule. Sur Ubuntu et Debian, shutdown est fourni par systemd et n'est qu'une autre façon d'appeler systemctl ; systemctl reboot --when="23:30" est l'équivalent direct.
Signalements étant servi par deux machines derrière un répartiteur de charge, le message s'adresse surtout à vos collègues : l'essentiel est de retirer la machine du répartiteur avant le redémarrage, puis de l'y remettre une fois signalements.service actif et sa sonde de santé verte. La coordination des redémarrages entre sig-app-1 et sig-app-2 est détaillée à la leçon 4.
Sous le capot
Comment GRUB trouve le noyau
En UEFI, le firmware lit les variables BootOrder et Boot0001, monte l'ESP et exécute shimx64.efi. shim vérifie et lance grubx64.efi, qui lit le grub.cfg minimal de l'ESP. Ce dernier contient une instruction du type search.fs_uuid <UUID> root : GRUB parcourt les partitions, trouve celle qui porte cet UUID, puis charge /boot/grub/grub.cfg. GRUB embarque ses propres pilotes de systèmes de fichiers (ext4, XFS, Btrfs, LVM) : il lit /boot sans le noyau Linux. C'est aussi pourquoi un /boot sur un système de fichiers que GRUB ne connaît pas, ou chiffré sans précaution, ne démarre pas.
GRUB charge ensuite vmlinuz et l'initramfs en mémoire, place la ligne de commande à un endroit convenu (le protocole de démarrage x86 de Linux), et saute au point d'entrée du noyau. À partir de là, GRUB n'existe plus.
Le fichier /boot/grub/grubenv est le seul endroit où GRUB peut écrire : un bloc de taille fixe (1 024 octets), qui sert à GRUB_DEFAULT=saved (grub-set-default, grub-reboot) et, sur Ubuntu, au mécanisme recordfail : si le démarrage précédent n'est pas allé au bout, Ubuntu affiche le menu au démarrage suivant (délai réglé par GRUB_RECORDFAIL_TIMEOUT, propre à Ubuntu), pour laisser une chance de choisir une autre entrée. sudo grub-editenv list affiche son contenu.
Du noyau au PID 1
Le noyau décompresse l'initramfs dans un tmpfs qui devient sa racine provisoire (rootfs), et exécute /init. Avec initramfs-tools, c'est un script shell : il monte /proc, /sys, /dev et /run, lance udev pour que les périphériques apparaissent, charge les modules, exécute les scripts de scripts/local-top/ (assemblage RAID, LVM, déverrouillage LUKS), attend le périphérique désigné par root=, le monte sur /root, déplace /run et les systèmes de fichiers virtuels, et termine par run-init (l'équivalent de switch_root) vers /sbin/init. Ce dernier est un lien vers /usr/lib/systemd/systemd.
systemd reçoit le PID 1, que le noyau traite de manière particulière : s'il meurt, le noyau panique. C'est pourquoi systemd ne se termine jamais, même pour redémarrer : il passe la main à un autre binaire, systemd-shutdown, qui tue les processus restants, démonte ce qui peut l'être, puis appelle le noyau (reboot(2)).
Le calcul de la transaction
Au démarrage, systemd commence par exécuter ses générateurs : de petits programmes qui traduisent d'autres formats en unités, dans /run/systemd/generator/. systemd-fstab-generator transforme chaque ligne de /etc/fstab en unité .mount (leçon 6) ; le générateur de cloud-init décide si cloud-init doit s'activer. Ensuite, systemd charge toutes les unités, part de default.target, suit récursivement Wants= et Requires=, et construit une transaction : l'ensemble des tâches (jobs) à exécuter, ordonnées par After=/Before=. Il détecte les cycles d'ordre et en casse un en supprimant une tâche non indispensable, avec un message Found ordering cycle dans le journal. Puis il lance en parallèle toutes les tâches dont les prédécesseurs sont terminés.
L'arrêt est une transaction comme les autres
systemctl reboot démarre reboot.target, qui est en conflit (Conflicts=) avec presque toutes les unités. Comme les relations d'ordre s'inversent à l'arrêt, une unité démarrée après une autre est arrêtée avant elle. C'est ce qui garantit que Signalements s'arrête avant que le réseau ne tombe, et que les systèmes de fichiers sont démontés en dernier. Un service qui ignore SIGTERM retarde l'arrêt de son TimeoutStopSec (90 secondes par défaut), ce que l'on voit sur la console sous la forme A stop job is running for ....
Pièges courants
Modifier grub.cfg directement. La modification fonctionne, jusqu'à la prochaine mise à jour du noyau, qui exécute update-grub et l'efface. Le fichier commence d'ailleurs par # DO NOT EDIT THIS FILE. Passez toujours par /etc/default/grub.d/ puis update-grub.
Modifier /etc/default/grub et ne rien voir changer. Un fichier de /etc/default/grub.d/ redéfinit la même variable et est lu après. Lisez ce répertoire, puis vérifiez le résultat dans grub.cfg avant de redémarrer, et dans /proc/cmdline après.
Oublier update-grub. /etc/default/grub n'est lu par personne au démarrage : seul grub.cfg compte. Sans régénération, votre modification n'existe pas.
Une console série muette. Vous ouvrez la console Scaleway pendant un redémarrage et ne voyez rien, ou seulement la fin. Le noyau n'écrit pas sur ttyS0, ou console=ttyS0 n'est pas en dernière position et les invites interactives partent sur l'écran virtuel. À corriger avant d'en avoir besoin.
Un démarrage qui attend deux minutes. Un message A start job is running for Wait for Network to be Configured (1min 30s / 2min) sur la console : systemd-networkd-wait-online attend une interface qui ne sera jamais configurée (une interface déclarée dans netplan mais non branchée, par exemple). systemd-analyze critical-chain le confirme. La correction relève de la configuration réseau (leçon 7).
systemctl isolate rescue.target à distance. La session SSH se fige : sshd et le réseau viennent d'être arrêtés. Seule la console série permet de revenir (systemctl default ramène à la cible par défaut). Même effet avec systemctl emergency.
Croire que set-default agit tout de suite. Il ne fait que changer un lien pour le prochain démarrage.
Une unité qui attend la mauvaise unité cloud-init. Une unité écrite pour Ubuntu avec After=cloud-init.service n'attend rien sur Debian 13, où l'unité équivalente s'appelle cloud-init-network.service : la dépendance vers une unité inexistante est silencieusement ignorée. Pour attendre la fin complète de cloud-init sur les deux, After=cloud-final.service existe partout, ou cloud-init status --wait dans un script.
Supprimer de vieux noyaux à la main. Un rm /boot/vmlinuz-* désynchronise /boot, les paquets et grub.cfg. Les noyaux se retirent avec APT (leçon 4), qui met à jour le menu.
Un /boot ou une ESP pleins. La mise à jour d'un noyau échoue au moment d'écrire l'initramfs, avec un message du type cpio: write error: No space left on device suivi de E: mkinitramfs failure et update-initramfs: failed for /boot/initrd.img-.... Le paquet reste à moitié configuré. df -h /boot /boot/efi, puis retrait des noyaux inutiles avec APT, puis sudo dpkg --configure -a.
Des données utilisateur modifiées sans effet. Vous changez les données utilisateur de l'instance dans la console Scaleway et redémarrez : rien ne se passe. C'est normal, l'identifiant d'instance n'a pas changé et les modules « une fois par instance » ne se rejouent pas. On recrée l'instance, ce qui est d'ailleurs le comportement souhaité (infrastructure immuable).
Sécurité
Qui contrôle le démarrage contrôle la machine. Celui qui peut éditer une entrée de GRUB peut ajouter init=/bin/bash ou systemd.unit=emergency.target et obtenir un shell root sans mot de passe dans certains cas (leçon 5). Sur un serveur physique, c'est l'accès au clavier ; en cloud, c'est l'accès à la console série de Scaleway, donc aux identifiants du projet Scaleway. Ces droits IAM valent un accès root : limitez qui les détient, et activez l'authentification multifacteur sur les comptes de la console.
Le mot de passe de GRUB. Le guide BP-028 de l'ANSSI recommande de protéger le chargeur de démarrage par un mot de passe (recommandation R5) : sans lui, quiconque atteint le menu peut modifier la ligne de commande. On génère un condensat avec grub-mkpasswd-pbkdf2, que l'on déclare dans un script de /etc/grub.d/ avec set superusers et password_pbkdf2. Attention à l'effet de bord : par défaut, toutes les entrées deviennent protégées, y compris le démarrage normal, ce qui bloque un redémarrage sans surveillance ; il faut ajouter --unrestricted aux entrées ordinaires, ce qui demande, sur Debian et Ubuntu, d'adapter le script /etc/grub.d/10_linux (un fichier de configuration du paquet, dont il faudra suivre les évolutions à chaque mise à jour de GRUB). Sur une instance cloud, l'intérêt est réel mais moindre : la console est déjà protégée par l'authentification Scaleway. Pesez le gain face au coût en dépannage.
Secure Boot n'est pas un détail. Il empêche un attaquant devenu root de remplacer GRUB ou le noyau par une version piégée qui survivrait aux réinstallations de paquets (un bootkit), et le mode lockdown l'empêche de charger un module noyau malveillant. Les guides de durcissement, dont celui de l'ANSSI, recommandent de l'activer quand la plateforme le permet. Sur une instance de cloud, la confiance repose en dernier ressort sur l'hyperviseur du fournisseur : c'est l'un des arguments des offres qualifiées SecNumCloud pour les clients publics.
L'initramfs et /boot ne sont pas chiffrés. Même avec un disque chiffré, /boot reste lisible et modifiable par qui accède au disque hors ligne (mode de secours, instantané du volume). Un initramfs modifié peut capturer une phrase de passe. Secure Boot ne signe pas l'initramfs généré localement : c'est une limite connue de la chaîne Debian et Ubuntu.
Les données utilisateur restent lisibles. Tout ce que vous avez passé à cloud-init est conservé sur la machine (/var/lib/cloud/instance/) et reste interrogeable sur le service de métadonnées par tout processus de l'instance. N'y placez aucun secret (mot de passe de base de données, jeton) : un processus compromis de Signalements pourrait le lire.
Le journal du démarrage est une preuve. Un redémarrage inattendu, une ligne de commande du noyau modifiée, un module chargé qui n'a rien à faire là : journalctl -b -1 et /proc/cmdline sont les premiers endroits à examiner après un incident. Ils ne valent que s'ils sont copiés hors de la machine (leçon 12).
En production
Redémarrez régulièrement, volontairement. Un serveur qui n'a pas redémarré depuis un an n'a pas prouvé qu'il sait redémarrer : il a accumulé des modifications jamais testées au démarrage. Un redémarrage planifié, à une heure choisie et une machine à la fois, révèle ces écarts quand vous êtes prêt à les corriger. Avec deux instances derrière un répartiteur, Signalements peut absorber un redémarrage sans interruption de service.
Rendez la console utilisable avant d'en avoir besoin. Vérifiez une fois, machine par machine, que la console série de Scaleway affiche bien le menu de GRUB et les messages du noyau, et qu'un compte capable de s'y connecter existe (la documentation Scaleway rappelle qu'il faut un mot de passe local, la console ne connaît pas les clés SSH). Notez le résultat dans la fiche du serveur.
Mesurez et suivez le temps de démarrage. Il compte quand une instance doit être recréée vite (remplacement après une panne, montée en charge). systemd-analyze time après chaque mise à jour majeure, et une régression de trente secondes se voit tout de suite. Les gros postes habituels sur une instance cloud : l'attente du réseau, cloud-init, et snapd sur Ubuntu.
Gérez la configuration du démarrage comme du code. Les fichiers /etc/default/grub.d/90-lyneko.cfg, la cible par défaut et la configuration d'initramfs-tools se déploient par l'outil d'automatisation (cours Ansible : les fondamentaux), avec update-grub déclenché seulement quand le fichier change. Une machine où quelqu'un a édité le démarrage à la main est un animal de compagnie de plus.
Préférez l'image à la retouche. Sur une flotte, on ne règle pas la ligne de commande de chaque instance après coup : on la règle dans l'image dont les instances sont issues, et cloud-init ne s'occupe plus que de ce qui est propre à chacune. Le démarrage devient plus court et identique partout.
Exercices
1. Lire une ligne de commande (niveau 100). Sur une machine, /proc/cmdline contient : BOOT_IMAGE=/boot/vmlinuz-6.12.48+deb13-amd64 root=UUID=7f3a... ro console=ttyS0,115200 console=tty0 quiet. Expliquez chaque paramètre, et dites sur quelle console apparaîtra une demande de phrase de passe ou un shell de secours.
Solution
BOOT_IMAGE est ajouté par GRUB et indique le noyau chargé (ici un noyau Debian 13) ; le noyau ne le reconnaît pas et le transmet à init. root=UUID=... désigne le système de fichiers racine par son UUID. ro le monte d'abord en lecture seule, systemd le remontera en écriture d'après /etc/fstab. Les deux console= envoient les messages du noyau sur le port série et sur l'écran virtuel. quiet réduit les messages du noyau et l'affichage d'état de systemd.
La dernière console citée devient /dev/console : ici tty0, l'écran virtuel. Une invite interactive n'apparaîtra donc pas sur la console série de Scaleway. Il faut inverser l'ordre : console=tty0 console=ttyS0,115200.
2. Changer le délai de GRUB (niveau 200). Vous voulez que le menu de GRUB de sig-outils reste caché, mais qu'on puisse l'obtenir pendant cinq secondes depuis la console série. Écrivez le fichier, la commande de régénération et la vérification, sans toucher à /etc/default/grub ni à grub.cfg.
Solution
$ sudoedit /etc/default/grub.d/90-lyneko.cfg
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=5
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200"Avec hidden, GRUB attend cinq secondes sans afficher le menu ; Échap, F4 ou Maj maintenue le font apparaître. GRUB_TERMINAL le rend accessible depuis la console série. Puis :
$ sudo update-grub
$ sudo grep -nE 'timeout|terminal_(input|output)|serial' /boot/grub/grub.cfg
On doit y lire set timeout_style=hidden, set timeout=5, et les lignes serial, terminal_input et terminal_output. Vérifiez qu'aucun autre fichier de /etc/default/grub.d/ dont le nom trie après 90- ne redéfinit ces variables. Testez au prochain redémarrage planifié, console série ouverte.
3. Un démarrage lent (niveau 200). Après une intervention de Camille sur la configuration réseau, sig-app-2 met deux minutes de plus à démarrer et Signalements devient disponible en dernier. Quelles commandes lancez-vous, dans quel ordre, et que cherchez-vous ?
Solution
systemd-analyze time: confirme que le temps est passé en userspace, pas dans le noyau.systemd-analyze critical-chain signalements.service: montre la chaîne qui retarde Signalements. On s'attend à voirsystemd-networkd-wait-online.serviceavec un+proche de deux minutes, son délai maximal par défaut.systemd-analyze blame | headen complément, en gardant à l'esprit qu'une unité peut y paraître lente parce qu'elle attend.journalctl -b -u systemd-networkd-wait-online: le message de délai dépassé, etnetworkctl(ounetworkctl status) pour repérer l'interface restée en étatconfiguringoudegraded.
La cause probable : une interface déclarée dans la configuration réseau qui n'obtient jamais d'adresse. La correction (déclarer l'interface comme facultative, ou retirer la déclaration) relève de la leçon 7. Signalements, qui dépend de network-online.target, n'est en cause que par ricochet.
4. Une unité qui dépend de cloud-init (niveau 300). Une unité maison, sig-agent.service, doit démarrer après que cloud-init a créé les utilisateurs et écrit les fichiers des données utilisateur, sur sig-app-1 (Ubuntu 24.04) comme sur sig-outils (Debian 13). Camille avait écrit After=cloud-init.service. Expliquez pourquoi cela fonctionne sur une machine et pas sur l'autre, proposez une écriture portable, et dites comment vérifier l'ordre réellement appliqué.
Solution
Depuis cloud-init 24.3, l'étape network est portée par cloud-init-network.service (avec cloud-init-main.service comme processus unique). Debian 13 (cloud-init 25.1.4) suit ce fonctionnement : cloud-init.service n'y existe pas. Ubuntu 24.04 retire ce changement par un correctif et garde cloud-init.service. Sur Debian, After= vers une unité inexistante est simplement ignoré : sig-agent peut démarrer avant que les utilisateurs existent.
Écriture portable : l'écriture des fichiers (write_files) et la création des utilisateurs ont lieu à l'étape network, mais certaines actions (runcmd, paquets) n'ont lieu qu'à l'étape final. Le plus sûr est de se placer après la dernière étape, qui porte le même nom partout :
[Unit]
After=cloud-final.service
Wants=cloud-final.serviceOn peut aussi citer les deux noms (After=cloud-init.service cloud-init-network.service) si l'on veut démarrer plus tôt, puisqu'un nom absent est ignoré.
Vérification : systemctl show sig-agent -p After liste les dépendances d'ordre comprises par systemd ; après un redémarrage, systemd-analyze critical-chain sig-agent.service montre la chaîne réelle, et journalctl -b -o short-monotonic -u cloud-final -u sig-agent permet de comparer les instants de démarrage.
Récapitulatif
- Le démarrage est une course de relais : firmware (BIOS ou UEFI), GRUB, noyau, initramfs, systemd, puis cloud-init sur une instance de cloud. Chaque étage ne connaît que ce qu'il faut pour lancer le suivant.
/sys/firmware/efiprésent signifie UEFI ;efibootmgr -vlit les entrées de démarrage,mokutil --sb-statel'état de Secure Boot. La chaîne signée est shim, puis GRUB, puis le noyau.- On n'édite jamais
grub.cfg: on ajoute un fichier dans/etc/default/grub.d/, on lanceupdate-grub, on vérifie dansgrub.cfgpuis dans/proc/cmdlineaprès redémarrage. - La ligne de commande porte
root=,ro,quiet,console=(la dernière console reçoit les invites : mettezttyS0en dernier pour la console Scaleway) etpanic=. - L'initramfs monte la vraie racine puis passe la main à systemd ; Debian 13 et Ubuntu 24.04 utilisent initramfs-tools (
lsinitramfs,update-initramfs -u), Red Hat et Ubuntu 25.10 et suivantes dracut. default.targetest un lien vers la cible finale (get-default,set-default) ;rescue.targetmonte le système de base,emergency.targetpresque rien ;isolateà distance coupe l'accès.systemd-analyze time,blame(avec prudence),critical-chainetplotmesurent le démarrage ;journalctl -b -1relit le démarrage précédent.- cloud-init s'exécute en cinq étapes (detect, local, network, config, final), se rejoue « par instance » selon l'identifiant d'instance, et journalise dans
/var/log/cloud-init.loget/var/log/cloud-init-output.log. L'unité de l'étape network s'appellecloud-init.servicesur Ubuntu 24.04 etcloud-init-network.servicesur Debian 13. - On arrête avec
systemctl rebootoushutdown -r +N "message", après avoir retiré la machine du répartiteur.
Pour aller plus loin
- Les pages
bootup(7)etsystemd.special(7): les schémas complets du démarrage, de l'initramfs et de l'arrêt, et la définition de chaque cible. - La documentation du noyau, The kernel's command-line parameters, pour la liste exhaustive des paramètres, et Linux Serial Console pour les consoles série.
- Le manuel de GRUB, chapitre Simple configuration handling, pour toutes les variables de
/etc/default/grub. - La documentation de cloud-init, Boot stages et First boot determination.
- La leçon 5, pour mettre tout cela à l'épreuve sur une machine qui ne démarre plus, et le cours systemd en profondeur, pour les générateurs, les transactions et l'activation par socket.
- La leçon suivante : Le noyau : modules et paramètres.
Sources
- systemd, page de manuel bootup(7)
- systemd, page de manuel systemd.special(7)
- systemd, page de manuel systemd-analyze(1)
- systemd, page de manuel kernel-command-line(7)
- systemd, page de manuel systemctl(1)
- systemd, page de manuel shutdown(8)
- Documentation du noyau Linux, The kernel's command-line parameters (v6.8)
- GNU GRUB Manual 2.12, Simple configuration handling
- initramfs-tools 0.148.4, pages de manuel initramfs.conf(5), update-initramfs(8), lsinitramfs(8)
- cloud-init, documentation : Boot stages
- cloud-init, documentation : Breaking changes (24.3, single process)
- cloud-init, branche ubuntu/noble : correctif no-single-process.patch
- Ubuntu livecd-rootfs : réglages GRUB des images cloud (50-cloudimg-settings.cfg)
- Scaleway, documentation : Use boot modes
- Scaleway, documentation : Use the serial console
- Ubuntu 25.10 passe à dracut par défaut (annonce relayée par OMG! Ubuntu)
- ANSSI, recommandations de configuration d'un système GNU/Linux (BP-028)
- Paquets Debian trixie (systemd, grub-efi-amd64, initramfs-tools, cloud-init, shim-signed)
- Paquets Ubuntu noble (systemd, grub-efi-amd64, initramfs-tools, cloud-init, shim-signed, dracut)