Il y a une sorte d’angoisse particulière à regarder un serveur « démarrer » pendant dix minutes pendant que votre pipeline de déploiement expire et que tout le monde fait comme si de rien n’était. Les logs défilent, les ventilateurs tournent, et votre instance est techniquement vivante mais émotionnellement indisponible.
Si vous voulez un démarrage plus rapide, arrêtez de chasser des fantômes. Il y a une liste qui compte : l’ensemble ordonné des choses que vous demandez au système de lancer, et le graphe de dépendances qui impose l’ordre. Nettoyez cette liste, et le démarrage devient rapide. Ignorez-la, et vous continuerez à acheter des instances plus grosses pour exécuter le même script de démarrage lent.
La seule liste : ce que c’est vraiment
Quand on dit « le démarrage prend une éternité », on veut généralement dire une des choses suivantes :
- Temps d’amorçage : kernel + initramfs + init system qui vous amènent à « multi-user » (ou équivalent).
- Temps de disponibilité des services : votre application est « démarrée » mais n’accepte pas encore réellement le trafic.
- Temps de disponibilité du nœud : en Kubernetes/auto-scaling, la machine existe mais n’est pas planifiable ou échoue aux vérifications de santé.
Sur la plupart des distributions Linux modernes, la liste que vous devez nettoyer est visible et modifiable via systemd. Concrètement, il s’agit de :
- L’ensemble des unités activées qui seront tirées par une cible (généralement
multi-user.targetougraphical.target). - Le graphe de dépendances entre elles (Wants/Requires/After/Before, plus les dépendances implicites et la sortie des generators).
- Les timeouts et contraintes d’ordonnancement au niveau des unités qui transforment un « démarrage parallèle » en « attente en série ».
Les systèmes ne démarrent pas lentement parce qu’un service est « lent ». Ils démarrent lentement parce que quelque chose force le service lent à être sur le chemin critique. Vous n’avez pas besoin de plus d’héroïsme ; vous avez besoin de moins de choses sur ce chemin.
Une citation utile à coller sur un post-it :
« L’espoir n’est pas une stratégie. » — idée paraphrasée souvent attribuée aux responsables fiabilité et opérations
Même énergie pour la performance de démarrage : espérer que votre système démarrera plus vite la fois suivante n’est pas un plan. Mesurer et tailler l’est.
Guide de diagnostic rapide
Voici l’ordre que j’utilise quand une instance met du temps à démarrer et que les gens tapent déjà dans le channel d’incident.
Première étape : localiser le bucket temporel (firmware/kernel vs initramfs vs userspace)
- Si la console reste avant « Starting version … systemd », soupçonnez le firmware, l’init du kernel, l’initramfs, la découverte du stockage ou fsck.
- Si systemd démarre rapidement mais « A start job is running… » pendant 90 secondes, soupçonnez des montages, des waits network-online, ou des timeouts.
- Si le démarrage se termine mais que votre application n’est pas prête, soupçonnez des checks de readiness, des migrations, du DNS, des services dépendants ou des limites de débit.
Deuxième étape : identifier la chaîne critique
- Exécutez
systemd-analyze critical-chainet trouvez ce qui est sur la ligne versdefault.target. - Vérifiez avec
systemd-analyze blame, mais ne vous laissez pas tromper par « blame » : quelque chose peut être lent sans être sur le chemin critique.
Troisième étape : confirmer si le retard est une attente ou un travail
- Attente : timeouts, tentatives, vérifications de dépendances, network-online, échecs de montage.
- Travail : démarrage d’unité lié au CPU, fsck lié au disque, manque d’entropie, verrous du gestionnaire de paquets, pulls d’images de conteneur.
Quatrième étape : coupez le graphe, pas les coins
- Retirez les unités inutiles de la cible de démarrage.
- Assouplissez l’ordonnancement (
After=) s’il s’agit de superstition, pas d’une exigence. - Convertissez des dépendances « dures » en dépendances « souples » lorsque c’est sûr (Requires → Wants).
- Corrigez ou masquez ce qui échoue de façon répétée.
Ceci est le playbook. Maintenant, rendons-le concret avec des commandes et des décisions.
Mesurer d’abord : ce que « démarrage lent » signifie vraiment
Les débats sur la vitesse de démarrage sont souvent théologiques. N’argumentez pas ; mesurez. systemd vous donne des données structurées, et le journal vous donne la vérité brute.
Deux définitions rapides qui importent en pratique :
- Temps userspace : c’est là que se situent la plupart de vos réglages : services, montages et logique de dépendance.
- Chemin critique : c’est la chaîne d’unités dont les retards retardent directement l’atteinte de la cible de démarrage.
Note : « démarrage » ne se limite pas à systemd. Si vous avez cloud-init, ignition, des agents de gestion de config, des pulls de runtime de conteneur, ou une appli qui effectue des migrations au démarrage, cela peut écraser le travail de l’init. Le point reste le même : énumérez ce que vous faites au démarrage, puis supprimez ce dont vous n’avez pas besoin.
Et oui, parfois c’est vraiment le stockage. Un seul montage qui attend 90 secondes pour un serveur NFS mort peut faire passer votre application « rapide » pour une patate.
Blague #1 : Le temps de démarrage, c’est comme une réunion intitulée « sync rapide ». Vous n’allez pas l’accélérer en y croyant plus fort.
Tâches pratiques de nettoyage (commandes, sorties, décisions)
Ce ne sont pas des « conseils ». Ce sont des tâches. Exécutez-les, lisez la sortie, et prenez une décision. C’est le travail.
Tâche 1 : Obtenir une répartition haut niveau du démarrage
cr0x@server:~$ systemd-analyze
Startup finished in 3.201s (kernel) + 7.842s (initrd) + 1min 18.331s (userspace) = 1min 29.374s
graphical.target reached after 1min 17.902s in userspace
Ce que cela signifie : Le userspace est le problème : 78 secondes après l’initrd. Kernel/initrd ne sont pas la priorité.
Décision : Restez dans le domaine de systemd : chaîne critique, blame, unités échouées, montages, waits réseau.
Tâche 2 : Trouver ce qui est sur le chemin critique
cr0x@server:~$ systemd-analyze critical-chain
graphical.target @1min 17.902s
└─multi-user.target @1min 17.902s
└─docker.service @52.104s +25.769s
└─network-online.target @51.990s
└─systemd-networkd-wait-online.service @21.411s +30.563s
└─systemd-networkd.service @20.982s +428ms
└─systemd-udevd.service @12.441s +8.512s
└─systemd-tmpfiles-setup-dev.service @11.901s +526ms
Ce que cela signifie : La chaîne est bloquée sur systemd-networkd-wait-online. Ensuite Docker est aussi sur le chemin.
Décision : Décidez si vous avez vraiment besoin que le « réseau soit entièrement en ligne » avant d’atteindre votre cible. La plupart des systèmes n’en ont pas besoin.
Tâche 3 : Voir la liste « blame » sans en faire un culte
cr0x@server:~$ systemd-analyze blame | head -n 15
30.563s systemd-networkd-wait-online.service
25.769s docker.service
10.112s dev-sdb2.device
8.512s systemd-udevd.service
6.902s snapd.service
5.441s cloud-init.service
4.990s apt-daily.service
4.221s systemd-journald.service
3.301s systemd-tmpfiles-setup.service
2.880s systemd-logind.service
Ce que cela signifie : Vous avez plusieurs unités lentes, mais seules celles sur la chaîne critique retardent votre cible de démarrage.
Décision : Corrigez d’abord wait-online (chemin critique), puis revoyez Docker et tout le reste qui vous importe.
Tâche 4 : Lister les unités échouées (souvent la taxe silencieuse au démarrage)
cr0x@server:~$ systemctl --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
● mnt-backup.mount loaded failed failed /mnt/backup
● nfs-client.target loaded failed failed NFS client services
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
Ce que cela signifie : Un montage et la target client NFS ont échoué. Sur certaines configurations, systemd attendra ou réessaiera, coûtant du temps.
Décision : Soit corriger le montage, soit le rendre non bloquant (timeouts, nofail, automount), soit le retirer du démarrage.
Tâche 5 : Inspecter les longues attentes dans le journal pour ce démarrage
cr0x@server:~$ journalctl -b -0 -p warning..alert --no-pager | tail -n 30
Jan 12 10:04:21 server systemd[1]: mnt-backup.mount: Mount process exited, code=exited, status=32/n/a
Jan 12 10:04:21 server systemd[1]: Failed to mount /mnt/backup.
Jan 12 10:04:21 server systemd[1]: Dependency failed for Local File Systems.
Jan 12 10:04:52 server systemd-networkd-wait-online[418]: Timeout occurred while waiting for network connectivity.
Jan 12 10:04:52 server systemd[1]: systemd-networkd-wait-online.service: Failed with result 'timeout'.
Ce que cela signifie : Deux tueurs classiques de démarrage : un échec de montage et un timeout wait-online.
Décision : Corrigez la sémantique du montage et retirez l’exigence wait-online sauf si votre nœud ne peut vraiment pas fonctionner sans.
Tâche 6 : Identifier quelles unités requièrent network-online.target
cr0x@server:~$ systemctl list-dependencies --reverse network-online.target
network-online.target
● └─docker.service
● └─remote-fs.target
● └─myapp.service
Ce que cela signifie : Docker, les systèmes de fichiers distants et votre app tirent network-online. C’est pourquoi l’attente bloque tout.
Décision : Pour chacun : décidez s’il a besoin de network.target (réseau basique) plutôt que network-online.target (configuré, « up »). La plupart des démons doivent tolérer que le réseau arrive peu après.
Tâche 7 : Confirmer qui tire un montage lent et s’il peut être à la demande
cr0x@server:~$ systemctl list-dependencies mnt-backup.mount
mnt-backup.mount
● ├─system.slice
● └─remote-fs-pre.target
Ce que cela signifie : Ce montage est traité comme faisant partie de la configuration des systèmes de fichiers. S’il bloque, il bloque tôt.
Décision : S’il n’est pas requis au démarrage, sortez-le du chemin critique avec un automount ou nofail et des timeouts sensés.
Tâche 8 : Auditer fstab pour des entrées hostiles au démarrage
cr0x@server:~$ cat /etc/fstab
UUID=9bb0c7d9-4f4d-4d56-9b27-2cbd71a7dbd6 / ext4 defaults 0 1
server:/exports/backup /mnt/backup nfs defaults 0 0
Ce que cela signifie : Ce montage NFS n’a ni nofail, ni x-systemd.automount, ni d’options de timeout. Il bloquera volontiers le démarrage en essayant.
Décision : S’il est optionnel au démarrage, rendez-le optionnel. Un modèle pratique :
cr0x@server:~$ sudo sed -i 's#server:/exports/backup /mnt/backup nfs defaults 0 0#server:/exports/backup /mnt/backup nfs nofail,x-systemd.automount,x-systemd.idle-timeout=60,timeo=5,retrans=2 0 0#' /etc/fstab
Suivi de décision : Après édition, validez avec systemctl daemon-reload et un montage de test (tâche suivante). Ne déployez pas de modifications non testées de fstab ; c’est comme ça qu’on obtient une journée « pas de démarrage » à distance.
Tâche 9 : Tester le comportement de montage sans redémarrer
cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart mnt-backup.automount
cr0x@server:~$ ls -la /mnt/backup
total 8
drwxr-xr-x 2 root root 4096 Jan 12 10:06 .
drwxr-xr-x 4 root root 4096 Jan 12 10:06 ..
Ce que cela signifie : Avec automount, le montage se déclenche à l’accès. Si le serveur est down, vous verrez un délai au moment de l’accès, pas au démarrage.
Décision : Pour les systèmes de fichiers distants non essentiels, l’automount est généralement le bon compromis : démarrage rapide, délai contrôlé quand vous y accédez réellement.
Tâche 10 : Supprimer « wait-online » quand c’est de la superstition
cr0x@server:~$ systemctl is-enabled systemd-networkd-wait-online.service
enabled
cr0x@server:~$ sudo systemctl disable systemd-networkd-wait-online.service
Removed "/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service".
Ce que cela signifie : Désactiver wait-online signifie que network-online.target peut encore être atteint par d’autres moyens, mais l’étape explicite « attendre jusqu’à ce que ce soit en ligne » est supprimée.
Décision : Si vous avez des services qui nécessitent vraiment le réseau en ligne avant de démarrer, corrigez ces services, pas tout le démarrage. Préférez une logique de retry dans le service, ou ordonnez uniquement ce service après network-online, pas l’ensemble du système.
Tâche 11 : Trouver les services activés qui ne devraient probablement pas l’être
cr0x@server:~$ systemctl list-unit-files --state=enabled --no-pager | head -n 25
UNIT FILE STATE PRESET
apt-daily.service enabled enabled
apt-daily.timer enabled enabled
cloud-init.service enabled enabled
cloud-init-local.service enabled enabled
cloud-config.service enabled enabled
cloud-final.service enabled enabled
docker.service enabled enabled
snapd.service enabled enabled
ssh.service enabled enabled
systemd-timesyncd.service enabled enabled
Ce que cela signifie : Certains de ces services sont corrects. D’autres sont du ballast. Certains nuisent activement à un temps de démarrage prévisible.
Décision : Pour les serveurs (pas les postes de travail), remettez en question les agents de mise à jour en arrière-plan (apt-daily), snap si vous ne l’utilisez pas, et tout ce qui concerne cloud-init sur des images qui ne sont plus configurées au premier démarrage.
Tâche 12 : Vérifier sur quoi un service attend (lire le fichier d’unité comme un contrat)
cr0x@server:~$ systemctl cat myapp.service
# /etc/systemd/system/myapp.service
[Unit]
Description=My App API
After=network-online.target remote-fs.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml
Restart=on-failure
TimeoutStartSec=120
[Install]
WantedBy=multi-user.target
Ce que cela signifie : Votre application tire explicitement network-online et remote-fs. Si l’un ou l’autre est instable, votre application devient une ancre de démarrage.
Décision : Si l’app peut démarrer sans ces éléments et retenter les connexions, changez pour :
After=network.target(ou supprimez complètement l’ordonnancement)- Retirez
remote-fs.targetsauf si vous avez vraiment besoin de montages distants - Gardez
TimeoutStartSecserré et significatif
Tâche 13 : Rechercher des cycles de dépendance et des impasses d’ordonnancement
cr0x@server:~$ systemd-analyze verify /etc/systemd/system/myapp.service
/etc/systemd/system/myapp.service:8: Unknown lvalue 'TimeoutStartSec' in section 'Service'
Ce que cela signifie : La vérification détecte des erreurs de configuration qui peuvent amener systemd à ignorer des réglages que vous pensiez actifs. Dans cet exemple, vous investiguerez pourquoi (systemd ancien ? faute de frappe ? sections surchargées ?).
Décision : Traitez les avertissements de parsing des unités comme des bugs de production. Corrigez-les. Les configurations mal lues créent des boucles « pourquoi c’est encore lent ? ».
Tâche 14 : Trouver le temps réel passé dans les unités de montage
cr0x@server:~$ systemd-analyze blame | grep -E '\.mount$|remote-fs' | head -n 20
1min 30.002s mnt-backup.mount
12.443s remote-fs.target
Ce que cela signifie : Ce montage à lui seul coûte 90 secondes. Ce n’est pas une « petite optimisation ». C’est un cas où il faut le retirer du démarrage.
Décision : Déplacez-le en automount, raccourcissez le timeout, ajoutez nofail ou supprimez-le entièrement. S’il est requis pour la correction, investissez pour rendre le service distant fiable et rapide.
Tâche 15 : Vérifier si le DNS est la vraie attente réseau cachée
cr0x@server:~$ resolvectl status
Global
Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub
Link 2 (ens5)
Current Scopes: DNS
Protocols: +DefaultRoute
Current DNS Server: 10.0.0.2
DNS Servers: 10.0.0.2 10.0.0.3
Ce que cela signifie : Le DNS semble configuré, mais cela ne prouve pas qu’il est atteignable pendant le démarrage. Beaucoup d’attentes « network-online » sont en réalité des cas où « le DNS n’est pas prêt » déguisés.
Décision : Si vous utilisez un résolveur local ou une dépendance qui n’est pas prête tôt, découplez votre démarrage du DNS en évitant les montages basés sur des noms d’hôtes et en vous assurant que les résolveurs sont disponibles (ou utilisez des IPs quand c’est approprié).
Tâche 16 : Inspecter les retards initramfs (stockage et pilotes)
cr0x@server:~$ dmesg --color=never | grep -E 'EXT4-fs|fsck|timed out|nvme|scsi|link is not ready' | tail -n 25
[ 2.901234] nvme nvme0: I/O 14 QID 0 timeout, reset controller
[ 3.112345] nvme nvme0: reset controller
[ 8.554321] EXT4-fs (nvme0n1p2): recovery complete
Ce que cela signifie : Des timeouts ou resets de stockage au niveau kernel peuvent dominer le démarrage précoce avant que systemd ait son mot à dire.
Décision : Si vous voyez des resets/timeouts de contrôleur, arrêtez de blâmer systemd. Vérifiez la santé du stockage cloud, les pilotes/firmware ou le périphérique sous-jacent. Sur des hôtes physiques, consultez SMART et les journaux du contrôleur.
Tâche 17 : Vérifier la santé des disques et les défaillances en attente (ennuyeux, efficace)
cr0x@server:~$ sudo smartctl -a /dev/sda | egrep -i 'Reallocated|Pending|Uncorrect|Power_On_Hours|SMART overall'
SMART overall-health self-assessment test result: PASSED
Power_On_Hours: 18234
Reallocated_Sector_Ct: 0
Current_Pending_Sector: 0
Offline_Uncorrectable: 0
Ce que cela signifie : Pas de signe évident de défaillance. C’est bon. Ce n’est pas une preuve de performance, mais cela élimine une cause courante de ralentissement : les disques qui réessaient des lectures en prétendant être sains.
Décision : Si les valeurs sont non nulles ou augmentent, planifiez un remplacement et arrêtez de chercher des « optimisations » logicielles pour masquer une défaillance matérielle.
Tâche 18 : Repérer la « taxe fsck » au démarrage
cr0x@server:~$ journalctl -b -0 --no-pager | grep -E 'fsck|clean|recovering|UNEXPECTED' | head -n 20
Jan 12 10:03:11 server systemd-fsck[201]: /dev/nvme0n1p2: clean, 245612/6553600 files, 12541021/26214400 blocks
Ce que cela signifie : Ici fsck est rapide et propre. Si vous voyez plutôt de longues réparations, votre démarrage lent est de la « maintenance système de fichiers », pas du « démarrage de services ».
Décision : Investiguer les arrêts incorrects, les problèmes de stockage et le tuning du système de fichiers. Et arrêtez de redémarrer des machines comme premier geste de dépannage.
Tâche 19 : Trouver les generators qui créent des unités au démarrage
cr0x@server:~$ systemd-analyze unit-paths
/etc/systemd/system.control
/run/systemd/system.control
/run/systemd/transient
/run/systemd/generator.early
/etc/systemd/system
/run/systemd/system
/run/systemd/generator
/usr/local/lib/systemd/system
/usr/lib/systemd/system
/run/systemd/generator.late
Ce que cela signifie : Les generators synthétisent des unités à partir de choses comme fstab, crypttab, la ligne de commande kernel et les configs réseau. Ils peuvent créer des surprises.
Décision : Si vous continuez à obtenir des « montages mystères » ou des targets inattendues, inspectez /run/systemd/generator* après le démarrage pour voir ce qui a été généré et pourquoi.
Tâche 20 : Valider ce qui est réellement activé pour la cible par défaut
cr0x@server:~$ systemctl get-default
graphical.target
cr0x@server:~$ systemctl list-dependencies graphical.target --no-pager | head -n 30
graphical.target
● ├─multi-user.target
● ├─display-manager.service
● └─system.slice
Ce que cela signifie : Si c’est un serveur, graphical.target est suspect. Vous pourriez charger une pile GUI dont vous n’avez pas besoin.
Décision : Sur les serveurs, définissez multi-user.target sauf si vous avez un vrai besoin d’une session graphique.
Blague #2 : Activer tous les services au démarrage « au cas où » revient à emporter un tapis de course en camping. Techniquement possible ; spirituellement incorrect.
Erreurs courantes : symptômes → cause racine → correction
Symptôme : « A start job is running for /mnt/… »
Cause racine : Montage au démarrage qui ne peut pas être satisfait (NFS/CIFS/iSCSI down, DNS incorrect, VPN pas encore up), combiné aux timeouts par défaut et dépendances dures.
Correction : Si optionnel : ajoutez nofail, envisagez x-systemd.automount, raccourcissez les timeouts, ou retirez-le du fstab. Si requis : rendez la dépendance fiable et assurez-vous que le chemin réseau existe tôt.
Symptôme : Le démarrage bloque sur network-online, mais le réseau « fonctionne finalement »
Cause racine : systemd-networkd-wait-online (ou équivalent NetworkManager) attend une condition qui ne survient jamais : délai DHCP, absence de carrier, interface désactivée, ou exigence DNS.
Correction : Désactivez wait-online globalement quand c’est sûr ; plus souvent, retirez Wants=network-online.target des services qui n’en ont pas besoin. Si un service en a besoin, scopez-le à ce service et rendez-le robuste (retries/backoff).
Symptôme : Tout est « lent » après l’installation d’un nouveau paquet ou une mise à jour d’image
Cause racine : Nouvelles unités activées (agents de télémétrie, auto-updaters, scanners de sécurité), nouveaux timers, ou cloud-init qui se relance à chaque démarrage parce que l’état n’a pas été persisté correctement.
Correction : Auditez les unités activées, comparez avec la baseline et désactivez ce dont vous n’avez pas besoin. Rendez cloud-init one-shot à nouveau en corrigeant le comportement des métadonnées/état de l’instance.
Symptôme : systemd-analyze blame montre une unité lente, mais critical-chain ne l’affiche pas
Cause racine : L’unité est lente mais démarre en parallèle ; elle ne bloque pas la cible de démarrage. Les gens la poursuivent quand même parce qu’elle est « en tête de liste ».
Correction : Priorisez la chaîne critique. N’optimisez les unités parallèles que si elles se disputent le CPU/disque et nuisent réellement à la disponibilité ou aux SLOs.
Symptôme : Le service applicatif démarre rapidement mais les checks de santé échouent pendant des minutes
Cause racine : Votre application effectue du « travail de démarrage » après le lancement du processus : migrations, warmup de cache, découverte de dépendances coûteuse, pulls d’images, ou attente d’APIs externes.
Correction : Rendre la readiness explicite. Déplacez le travail lourd hors du chemin chaud. Ajoutez backoff, timeouts et vérifications de dépendances appropriées. Séparez les migrations du démarrage web si vous tenez à la rapidité de boot.
Symptôme : Démarrages aléatoires lents ; parfois rapides, parfois catastrophiques
Cause racine : Dépendances externes (DNS, NTP, service de métadonnées, montages distants), manque d’entropie, ou interfaces réseau instables.
Correction : Supprimez l’ordonnancement dur, ajoutez du caching ou des solutions locales, et utilisez des timeouts qui échouent rapidement. Vérifiez aussi la santé matérielle et la couche de virtualisation.
Symptôme : « Avant c’était rapide ; maintenant c’est lent sur le même hôte »
Cause racine : Overrides d’unités qui s’accumulent, sorties de generators obsolètes, ou renommage de montage/périphérique (ex. étiquettes modifiées) causant des délais de découverte.
Correction : Passez en revue les drop-ins et overrides ; exécutez systemd-delta pour voir ce qui a changé ; épinglez les montages par UUID ; nettoyez les anciennes unités personnalisées.
Symptôme : Le démarrage bloque avant que systemd ne démarre
Cause racine : Initramfs qui attend le périphérique root, timeouts stockage, initramfs cassé, ou régressions de pilotes.
Correction : Utilisez les logs console/dmesg, vérifiez la config initramfs, vérifiez les identifiants du périphérique root, et revenez à un kernel/initramfs antérieur si besoin. systemd n’est pas encore coupable.
Trois mini-récits d’entreprise depuis le terrain
1) L’incident causé par une mauvaise supposition : « Network-online signifie ‘l’internet’ »
Dans une société de taille moyenne, une équipe a standardisé son image de base et ajouté une règle simple : « Démarrer l’API après que le réseau soit en ligne. » Raisonnable, non ? Ils ont mis à jour l’unité avec After=network-online.target et Wants=network-online.target. Ça a passé tous les tests de staging, car le staging avait un DHCP propre et une seule interface.
La production était plus désordonnée. Les instances avaient deux NICs : une pour le trafic interne, une pour un réseau de gestion restreint sans route par défaut par conception. Pendant le démarrage, la logique wait-online de systemd-networkd attendait que les deux liens soient « configurés ». La NIC de gestion ne satisfaisait jamais les conditions que le service attendait. Wait-online a atteint son timeout, et la chaîne de dépendances a retenu l’API.
L’incident n’était pas que l’API était en panne. C’était que l’auto-scaling devenait lent. Les nœuds mettaient trop de temps à rejoindre. Les déploiements avançaient lentement. Quelques basculements régionaux ont empiré la situation parce qu’ils dépendaient d’un remplacement d’instance rapide. Vu de l’extérieur, on aurait dit « la capacité est OK mais rien ne guérit ». Vu de l’intérieur, on avait un démarrage qui refusait de se terminer.
La correction a été résolument peu sexy : changer l’app pour démarrer après network.target, retirer l’exigence wait-online globale, et ajouter de la logique de retry pour les connexions en amont. Ils ont aussi ajusté le service wait-online pour ne se soucier que de l’interface qui importait (quand c’était vraiment nécessaire). L’erreur réelle était de supposer que « en ligne » était une vérité universelle. Sur de vrais réseaux, c’est conditionnel, et vous payez le prix quand vous faites semblant que ce n’est pas le cas.
2) L’optimisation qui a eu l’effet inverse : « Parallélisons tout avec des timeouts agressifs »
Une grande équipe plateforme s’est obsédée sur le temps de démarrage parce qu’elle gérait des milliers de nœuds et voulait accélérer les rolling updates. Ils ont chassé avec systemd-analyze blame et trouvé quelques services longs : logging, métriques et un agent de sécurité. Quelqu’un a proposé une « amélioration simple » : réduire TimeoutStartSec partout et supprimer les contraintes d’ordonnancement pour que tout démarre concurremment.
Le déploiement a semblé excellent pendant un jour. Le démarrage finissait plus vite. Les dashboards étaient verts. Puis les bizarreries ont commencé. L’agent de sécurité échouait parfois à démarrer à cause d’un disque lent ou de contention CPU pendant le boot. systemd le marquait comme échoué, mais le nœud atteignait la cible de démarrage et devenait éligible au trafic. L’équipe conformité l’a remarqué en premier, ce qui n’est jamais le meilleur type de surveillance.
Pire, le pipeline de logs démarrait parfois avant que le DNS ne soit stable, ne parvenait pas à résoudre son endpoint amont, et quittait. Parce qu’il avait été « optimisé » pour un démarrage rapide, sa stratégie de redémarrage était insuffisante. Les nœuds montaient « avec succès » mais sans logs. Quand un incident de production distinct est survenu deux semaines plus tard, la moitié des nœuds avait une télémétrie incomplète. L’analyse des causes profondes s’est transformée en archéologie.
La correction a été de traiter la performance de démarrage comme un compromis SLO, pas une course. Ils ont restauré des timeouts sensés pour les services critiques de sécurité/télémétrie, ajouté des redémarrages robustes avec backoff, et réintroduit l’ordonnancement là où il représentait de véritables dépendances. Ils ont quand même amélioré le temps de démarrage — en retirant le superflu de la liste de démarrage et en corrigeant les montages — mais ont arrêté de tricher en rendant par accident des services importants optionnels.
3) La pratique ennuyeuse mais correcte qui a sauvé la mise : « Baseliner la liste d’unités et faire des diffs »
Une petite fintech avait une règle qui sonnait bureaucratique : chaque release d’image de base produisait un artefact texte listant les unités activées, la target par défaut et les overrides notables. Le processus de release comparait également avec la version précédente. Si un nouveau service était activé, quelqu’un devait expliquer pourquoi.
Un trimestre, une mise à jour OS de routine a introduit en silence un nouveau service d’arrière-plan lié à la gestion de paquets. Ce n’était pas malveillant. Ce n’était même pas incorrect. Mais il prenait parfois des verrous et faisait du travail réseau tôt au démarrage. Sur certains nœuds, il entrait en collision avec la gestion de configuration et retardait des services clés.
Parce que l’équipe disposait de la baseline, elle a immédiatement vu « cette unité est nouvelle et activée ». Ils n’ont pas eu besoin de trois jours de débat sur un changement possible du fournisseur cloud. Ils l’ont simplement désactivée sur les serveurs où elle n’était pas nécessaire au démarrage et déplacé le travail de mise à jour dans une fenêtre de maintenance contrôlée.
Rien de héroïque. Pas de war room. Pas de fan fiction « SRE sauve la journée ». Juste un petit processus qui a empêché la liste de démarrage de croître silencieusement et devenir hostile. C’est le niveau d’ennuyeux auquel vous devriez aspirer.
Faits et contexte historique à utiliser
- Le temps de démarrage était autrefois surtout lié au matériel. Sur les systèmes plus anciens, le BIOS/firmware et les disques rotatifs dominaient. Aujourd’hui, les graphes de dépendances userspace dominent souvent sur les serveurs.
- SysV init était largement séquentiel. Le passage à des systèmes d’init dépendants (pas seulement systemd) a rendu le démarrage parallèle possible, mais a aussi rendu les dépendances mal spécifiées plus coûteuses.
- systemd a introduit l’activation par socket. Les services peuvent démarrer à la demande lorsqu’une connexion arrive, ce qui est l’une des manières les plus propres de les garder hors du chemin critique.
- fstab est plus ancien que la plupart de votre infrastructure. C’est un fichier simple, mais à l’ère systemd il alimente des generators qui peuvent créer des comportements d’unités complexes.
- « En ligne » réseau est ambigu par conception. Carrier up, IP configurée, route par défaut présente, DNS joignable : ce sont des jalons différents, et différents outils définissent « en ligne » différemment.
- Les timeouts par défaut sont souvent conservateurs. Un timeout de montage de 90 secondes pouvait avoir du sens quand les réseaux étaient lents et les serveurs peu nombreux. À grande échelle, c’est un amplificateur d’incident auto-infligé.
- cloud-init a changé la façon dont fonctionne le premier démarrage. Sur les images cloud, une grande partie du « temps de démarrage » est souvent le « temps de configuration de l’instance ». S’il se relance de façon inattendue, le démarrage gonfle.
- Les systèmes de fichiers journalisés ont réduit les longs événements fsck, pas les ont éliminés. Si vous voyez des réparations fréquentes, c’est souvent le symptôme d’arrêts non propres ou d’instabilité du stockage.
- La parallélisation peut augmenter la variance. Quand tout démarre en même temps, la contention transforme le « généralement rapide » en « parfois terrible ». C’est pourquoi penser en termes de chemin critique compte.
Listes de contrôle / plan étape par étape
Phase 1 : Établir une baseline (même jour)
- Capturer la sortie de
systemd-analyze. - Capturer la sortie de
systemd-analyze critical-chainpour la cible par défaut actuelle. - Sauvegarder
systemd-analyze blame(les 50 premières lignes suffisent généralement). - Sauvegarder
systemctl --failedet les warnings/erreurs depuisjournalctl -b.
Objectif : Savoir dans quel bucket vous êtes et quelle unité bloque le démarrage.
Phase 2 : Nettoyer la liste (1–3 jours, selon la politique)
- Retirer les bloqueurs de démarrage : corriger/rendre optionnels les montages distants ; supprimer les waits network-online inutiles ; enlever les targets GUI sur les serveurs.
- Réduire les unités activées : désactiver les services non nécessaires sur les serveurs (ballast desktop, agents inutilisés, timers de mise à jour pendant le boot).
- Simplifier les arêtes de dépendance : supprimer les lignes
After=qui codent la superstition ; convertir Requires en Wants si c’est sûr ; éviter d’inclure remote-fs et network-online sauf si c’est vraiment nécessaire. - Définir des timeouts raisonnables : raccourcir les timeouts de montage pour les ressources optionnelles ; définir
TimeoutStartSecà une valeur réaliste pour échouer rapidement pour les services non critiques.
Objectif : Réduire la longueur du chemin critique et la variance.
Phase 3 : Rendre cela durable (continu)
- Baseliner les unités activées et faire des diffs entre versions d’image.
- Filtrer les nouveaux services activés : exiger une justification dans la revue de changement.
- Tester le temps de démarrage en CI pour les changements d’image de base (même un test smoke basique aide).
- Pour les applis, imposer des sémantiques de readiness : démarré n’est pas prêt.
Objectif : Prévenir les régressions, pas seulement réparer le bazar actuel.
Ce qu’il faut éviter (car ça fait perdre des semaines)
- Désactiver à l’aveugle des services « lents » sans comprendre leur utilité.
- Réduire les timeouts partout pour que le démarrage « paraisse rapide ». C’est juste balayer la fiabilité sous le tapis.
- Poursuivre la première entrée de
blameen ignorantcritical-chain. - Supposer que la partie lente est votre application alors que le système attend le stockage/le réseau.
FAQ
1) Quelle est « la seule liste » si je n’utilise pas systemd ?
C’est toujours le même concept : l’ensemble des actions de démarrage plus leurs contraintes d’ordre. Sur OpenRC, ce sont les runlevels et dépendances ; sur les scripts init, c’est l’ordre des rc. La logique de nettoyage ne change pas : tailler, découpler et retirer les attentes dures.
2) Est-ce que systemd-analyze blame suffit ?
Non. C’est utile, mais ce n’est pas un rapport du chemin critique. Une unité lente qui démarre en parallèle peut ne pas retarder l’atteinte de la cible de démarrage. Utilisez critical-chain pour trouver ce qui bloque.
3) Dois-je désactiver systemd-networkd-wait-online ?
Souvent oui, sur les serveurs. Mais faites-le intentionnellement : vérifiez quels services requièrent network-online.target. Si une seule unité en a besoin, gardez-la scoped à cette unité, pas globalement.
4) Quelle est la façon la plus sûre de gérer les montages NFS/CIFS optionnels ?
Utilisez nofail et x-systemd.automount pour que le démarrage ne bloque pas. Contrôlez ensuite le comportement à l’accès avec des timeouts raisonnables. Optionnel signifie optionnel au démarrage.
5) Mon app a besoin de la base de données. Ça ne veut pas dire qu’elle doit attendre network-online ?
Non. Cela signifie que votre app doit pouvoir gérer « base de données non joignable pour l’instant ». Lancez le processus, retentez les connexions avec backoff, et marquez le service comme ready seulement quand les dépendances sont accessibles.
6) Les conteneurs peuvent-ils ralentir le démarrage même si systemd est rapide ?
Absolument. Les runtimes de conteneurs peuvent tirer des images, configurer des backends de stockage et attendre le réseau. Si votre démarrage inclut « pull d’une image de 2 Go sur chaque nœud », la liste de démarrage inclut ce coût, que vous l’admettiez ou pas.
7) Comment éviter les régressions du temps de démarrage dans le temps ?
Baseliner la liste d’unités activées et faire des diffs par release d’image. Baseliner aussi les métriques de temps de démarrage et alerter sur les régressions comme vous alerteriez sur les régressions de latence.
8) Et si la partie lente est avant systemd ?
Alors le tuning systemd n’aidera pas. Utilisez les logs console et dmesg pour trouver des timeouts de découverte de stockage, des attentes d’initramfs, des bugs de pilotes ou des fsck. Corrigez le périphérique/pilote/config sous-jacent.
9) Changer la target par défaut de graphical à multi-user est-ce un vrai gain ?
Sur les serveurs, oui. Ça supprime toute une classe de services dont vous n’avez pas besoin. Sur les postes de travail, évidemment non. « La bonne target pour le job » est un vrai réglage de performance.
10) Quelle est la différence entre rendre quelque chose rapide et faire en sorte que cela ne bloque pas le démarrage ?
Rapide signifie que ça se termine vite. Ne pas bloquer signifie que ça peut être lent sans retarder la disponibilité. Pour beaucoup de dépendances optionnelles, ne pas bloquer est le meilleur résultat d’ingénierie.
Conclusion : prochaines étapes qui font réellement la différence
Le démarrage lent n’est rarement mystérieux. C’est généralement un graphe de dépendances qui a transformé un démarrage parallèle en attente sérialisée, plus une poignée de timeouts beaucoup trop généreux pour les opérations modernes.
Faites ceci ensuite, dans l’ordre :
- Exécutez le guide de diagnostic rapide et identifiez le bloqueur de la chaîne critique.
- Retirez les bloqueurs de démarrage : les montages distants optionnels deviennent automount/nofail ; wait-online est scoped ou désactivé.
- Émondez les unités activées pour correspondre au rôle du serveur. Si ce n’est pas un serveur applicatif, stockage ou sécurité/télémétrie requis, ce n’est pas dans la liste de démarrage.
- Codifiez une baseline des unités activées et des temps de démarrage, et difftez-la pour chaque changement d’image. La régression est l’état par défaut de l’univers ; il vous faut de la documentation pour combattre la physique.
Si vous nettoyez la liste et la maintenez propre, le démarrage cesse d’être un thriller à suspense. Il devient une procédure ennuyeuse et répétable. En production, l’ennuyeux est une fonctionnalité.