Explication des cibles Systemd : Gérer efficacement les états de démarrage et les niveaux d'exécution

Comprenez les cibles systemd, les équivalents des niveaux d'exécution, les états de démarrage par défaut, les modes isoler, rescue et graphique.

Explication des cibles Systemd : Gérer efficacement les états de démarrage et les niveaux d'exécution

Les cibles systemd sont des états système nommés. Une cible peut représenter un démarrage normal de serveur, un bureau graphique, un shell de secours, un arrêt, ou un groupe personnalisé de services que vous souhaitez démarrer ensemble. Si vous venez d'anciens systèmes Linux, les cibles sont le remplacement systemd des parties des niveaux d'exécution que les gens utilisaient réellement, mais elles sont plus flexibles car elles sont construites à partir de dépendances au lieu de simples chiffres.

Vous rencontrez généralement des cibles lorsqu'un serveur démarre dans le mauvais mode, qu'un gestionnaire d'affichage de bureau ne démarre pas, ou qu'un guide de récupération vous dit d'entrer rescue.target. Connaître quelques commandes rend ces situations beaucoup moins mystérieuses.

L'évolution des niveaux d'exécution aux cibles Systemd

Historiquement, les systèmes Linux utilisaient un concept appelé niveaux d'exécution pour définir l'état de fonctionnement du système pendant le démarrage et l'exécution. Un niveau d'exécution était un identifiant numérique (0-6) qui dictait quels services étaient démarrés ou arrêtés. Par exemple, le niveau d'exécution 3 signifiait généralement un mode texte multi-utilisateur, tandis que le niveau d'exécution 5 indiquait un environnement multi-utilisateur graphique. Ce système, bien que fonctionnel, présentait des limitations :

  • Rigidité : Les niveaux d'exécution étaient souvent définis de manière fixe ou spécifique à une distribution, rendant difficile la personnalisation de l'ensemble exact des services actifs pour un état donné.
  • Dépendances implicites : Les dépendances entre services étaient souvent gérées indirectement via les affectations de niveaux d'exécution, entraînant des conflits potentiels ou des services manquants.
  • Manque de granularité : Le système numérique manquait de clarté descriptive, rendant plus difficile la compréhension de l'état prévu du système.

Les cibles systemd répondent à ces limitations en offrant une approche plus explicite, basée sur les dépendances et descriptive. Au lieu de chiffres abstraits, les cibles ont des noms significatifs (par exemple, multi-user.target, graphical.target) qui indiquent clairement l'état système prévu. Les dépendances sont explicitement définies dans les fichiers unitaires, garantissant que tous les composants nécessaires sont démarrés dans le bon ordre.

La correspondance approximative ressemble à ceci sur de nombreux systèmes systemd :

Niveau d'exécution traditionnel Équivalent systemd courant Signification
0 poweroff.target Arrêter et éteindre
1 rescue.target Mode de secours mono-utilisateur
3 multi-user.target Mode texte/serveur multi-utilisateur
5 graphical.target Mode multi-utilisateur plus connexion graphique
6 reboot.target Redémarrer

Considérez cela comme une aide à la traduction, pas comme une loi. Le comportement des niveaux d'exécution variait selon les distributions, et les cibles systemd peuvent exprimer des relations que les anciens niveaux d'exécution ne pouvaient pas.

Comprendre les cibles Systemd

Une cible systemd est elle-même un type d'unité. Lorsqu'une unité cible est activée, systemd tente d'activer toutes les unités qui sont répertoriées comme dépendances dans le fichier unitaire de cette cible. Cela crée un effet en cascade, garantissant que tous les services, périphériques et autres composants nécessaires sont mis en ligne pour atteindre l'état système souhaité.

Caractéristiques clés des cibles Systemd :

  • Gestion des dépendances : Les cibles définissent quelles autres unités doivent être actives pour que la cible soit considérée comme atteinte. C'est le cœur de leur puissance.
  • Points de synchronisation : Elles agissent comme des points de synchronisation pendant le processus de démarrage. Le système ne passera à l'étape suivante que lorsque la cible actuelle sera entièrement initialisée.
  • Nommage descriptif : Les cibles sont nommées de manière descriptive, ce qui facilite la compréhension de l'état prévu du système (par exemple, rescue.target, poweroff.target).

Les cibles n'exécutent généralement pas de code de longue durée elles-mêmes. Elles regroupent d'autres unités. Vous pouvez inspecter ce regroupement avec :

systemctl list-dependencies multi-user.target
systemctl list-dependencies graphical.target

C'est un bon moyen de répondre à la question : "Pourquoi ce service démarre-t-il au démarrage ?" Si l'unité apparaît dans l'arbre des dépendances pour la cible par défaut, elle est attirée quelque part.

Cibles Systemd courantes

Systemd est livré avec un ensemble de cibles prédéfinies conçues pour couvrir les états système courants. Comprendre celles-ci est essentiel pour gérer votre système.

multi-user.target

C'est l'une des cibles les plus fondamentales. Elle représente un système multi-utilisateur entièrement fonctionnel avec réseau activé mais sans gestionnaire de connexion graphique ni environnement de bureau. C'est généralement la cible par défaut pour les serveurs.

  • Objectif : Fournir un environnement stable pour exécuter des services et permettre à plusieurs utilisateurs de se connecter via des consoles textuelles ou SSH.
  • Dépendances : Inclut généralement des unités pour le réseau, les services système et les invites de connexion console.

Pour les serveurs sans tête, multi-user.target est généralement le bon choix par défaut. Il vous donne SSH et les services normaux sans dépenser de ressources pour un gestionnaire d'affichage.

graphical.target

Cette cible représente un système multi-utilisateur entièrement fonctionnel avec un environnement de bureau graphique prêt pour l'interaction utilisateur. Elle est généralement une dépendance de multi-user.target et ajoute les composants nécessaires pour une session graphique.

  • Objectif : Lancer un gestionnaire d'affichage graphique (comme GDM, LightDM, SDDM) et l'environnement de bureau associé.
  • Dépendances : Attire généralement le comportement de multi-user.target et ajoute des unités pour un gestionnaire d'affichage et des composants de session graphique.

Si une station de travail démarre sur un écran noir mais que SSH fonctionne toujours, comparez ceci :

systemctl get-default
systemctl status display-manager.service
journalctl -u display-manager.service -b

La cible par défaut vous indique ce que le système a essayé d'atteindre. Les journaux du gestionnaire d'affichage vous disent pourquoi la couche graphique s'est ou ne s'est pas levée.

rescue.target

Cette cible fournit un environnement minimal mono-utilisateur. Elle est principalement utilisée pour la maintenance et la récupération du système. Elle met en place le système de base et un shell root mais ne démarre généralement pas le réseau ni les services multi-utilisateurs.

  • Objectif : Fournir un environnement sûr pour que les administrateurs système effectuent des tâches de maintenance sans interférence d'autres services.
  • Dépendances : Ensemble minimal de composants système essentiels et un shell root. Le réseau n'est souvent pas disponible à moins que vous ne le démarriez manuellement.

emergency.target

C'est encore plus minimal que rescue.target. Elle met le système en place avec un seul système de fichiers en lecture seule et un shell root. Elle est destinée aux situations d'urgence graves où même les services de base pourraient poser problème.

  • Objectif : Pour la récupération critique du système lorsque même rescue.target pourrait ne pas être approprié.
  • Dépendances : Uniquement les composants système les plus essentiels et un shell root. Le système de fichiers racine peut être monté en lecture seule en fonction de la panne et de la distribution.

reboot.target, poweroff.target, halt.target

Ce sont des cibles spéciales utilisées pour arrêter ou redémarrer le système. Lorsque systemd active l'une de ces cibles, il arrête tous les services en cours d'exécution, puis effectue l'action spécifiée (redémarrage, extinction ou arrêt).

  • Objectif : Arrêter ou redémarrer le système en douceur.
  • Dépendances : Elles dépendent généralement des services qui doivent être arrêtés avant que le système puisse être éteint.

Gérer les cibles Systemd

Systemd fournit plusieurs outils en ligne de commande pour interagir avec les cibles. L'outil principal est systemctl.

Afficher les cibles actuelle et par défaut

Pour voir sur quelle cible le système fonctionne actuellement et sur quelle cible il démarre par défaut, utilisez :

systemctl status

Cette commande fournit une mine d'informations, y compris la cible active. Pour interroger spécifiquement la cible par défaut :

systemctl get-default

Pour voir toutes les cibles disponibles :

systemctl list-unit-files --type=target

Pour voir les unités cibles actives, utilisez :

systemctl list-units --type=target

La différence est la même qu'avec les services : list-unit-files montre les fichiers cibles que systemd connaît, tandis que list-units montre les cibles actuellement chargées ou actives dans le système en cours d'exécution.

Changer la cible par défaut

Si vous souhaitez que votre système démarre sur une cible différente par défaut (par exemple, de graphique à multi-utilisateur, ou vice-versa), vous pouvez utiliser systemctl set-default :

Pour définir la cible par défaut sur graphique (courant pour les systèmes de bureau) :

sudo systemctl set-default graphical.target

Pour définir la cible par défaut sur multi-utilisateur (courant pour les serveurs) :

sudo systemctl set-default multi-user.target

Important : La modification de la cible par défaut ne prendra effet qu'au prochain redémarrage.

Sous le capot, cela modifie le lien symbolique default.target. Vous pouvez l'inspecter directement si vous déboguez une image de démarrage cassée :

systemctl get-default
ls -l /etc/systemd/system/default.target

Basculer vers une cible (sans redémarrer)

Vous pouvez basculer le système vers une cible différente immédiatement sans redémarrer. Cela est utile pour tester ou modifier temporairement l'état du système. Utilisez la commande systemctl isolate :

Pour basculer vers la cible graphique :

sudo systemctl isolate graphical.target

Pour basculer vers la cible multi-utilisateur :

sudo systemctl isolate multi-user.target

Attention : systemctl isolate est une commande puissante. Isoler vers une cible comme rescue.target ou emergency.target arrêtera la plupart des services en cours d'exécution. Assurez-vous de comprendre les implications avant de l'utiliser. Vous pourriez perdre la connectivité réseau ou votre session graphique.

Sur un serveur distant, soyez particulièrement prudent avec isolate rescue.target ou isolate emergency.target. Vous pourriez perdre SSH et avoir besoin d'un accès console via votre fournisseur de cloud, votre hyperviseur ou votre machine physique. Si vous avez seulement besoin d'arrêter le bureau graphique sur une station de travail, isoler vers multi-user.target est moins drastique que de sauter directement en mode de secours.

Comment les cibles sont liées aux fichiers unitaires

Les cibles sont implémentées sous forme de fichiers unitaires, généralement situés dans /usr/lib/systemd/system/ ou /etc/systemd/system/. Un fichier unitaire de cible (par exemple, graphical.target) spécifie les dépendances sur d'autres unités, y compris d'autres cibles et services.

Un fichier unitaire graphical.target typique pourrait ressembler à ceci (simplifié) :

[Unit]
Description=Graphical multi-user system
Documentation=man:systemd.special(7)
# This target is intended to be a prerequisite for the graphical login manager.
# It's the target that the system will boot into if not otherwise specified.
Wants=display-manager.service
Before=shutdown.target

[Install]
Alias=default.target

Ici :

  • Wants=display-manager.service : Indique que display-manager.service (le gestionnaire de connexion réel comme GDM ou LightDM) doit être démarré si possible. C'est une dépendance plus faible que Requires=.
  • Before=shutdown.target : Garantit que l'environnement graphique est arrêté avant que le système n'entre dans le processus d'arrêt.
  • Alias=default.target : Cela fait en sorte que graphical.target agisse comme la cible par défaut si default.target y est lié (ce qui est généralement le cas pour les systèmes de bureau).

Créer des cibles personnalisées

Bien que moins courant pour une utilisation quotidienne, vous pouvez créer vos propres cibles personnalisées pour définir des états système spécifiques avec des ensembles uniques de services.

Étapes pour créer une cible personnalisée :

  1. Créez un fichier unitaire .target : Placez-le dans /etc/systemd/system/ (par exemple, my-custom.target).
    [Unit]
    Description=My Custom Target
    
    [Install]
    WantedBy=multi-user.target # Or another appropriate target
    
  2. Créez des fichiers .service ou d'autres unités : Définissez les services et autres unités qui doivent être actifs pour votre cible personnalisée.
  3. Ajoutez des dépendances : Dans le fichier unitaire de votre cible personnalisée, utilisez Requires= ou Wants= pour spécifier quelles unités doivent ou devraient être démarrées.
    [Unit]
    Description=My Custom Target
    Wants=service1.service
    Wants=service2.service
    After=service1.service service2.service
    
    [Install]
    WantedBy=multi-user.target
    
  4. Rechargez systemd :
    
    

sudo systemctl daemon-reload 5. **Activez/Démarrez votre cible :** bash sudo systemctl start my-custom.target # Or to make it bootable sudo systemctl enable my-custom.target ```

Cas d'utilisation : Imaginez un environnement de développement où vous avez besoin de serveurs de base de données et d'applications spécifiques en cours d'exécution. Vous pourriez créer un dev-env.target qui démarre ces services.

Les cibles personnalisées sont également utiles pour les systèmes de type appliance. Par exemple, une machine de kiosque pourrait avoir une cible qui démarre le réseau, un navigateur, un watchdog local et un agent de journalisation, mais pas le reste d'une session de bureau normale. Un serveur de laboratoire pourrait avoir des cibles séparées pour une pile de test et une pile de démonstration afin que les opérateurs puissent démarrer un groupe connu de services ensemble.

Meilleures pratiques et conseils

  • Comprenez la valeur par défaut : Connaissez la cible par défaut de votre système (graphical.target ou multi-user.target) car elle dicte l'expérience de démarrage initiale.
  • Utilisez isolate avec prudence : Soyez attentif lorsque vous utilisez systemctl isolate, en particulier sur les systèmes de production, car cela peut perturber les services en cours d'exécution.
  • Vérifiez les dépendances : Si un service ne démarre pas, examinez les dépendances de la cible à laquelle il est associé en utilisant systemctl list-dependencies <nom_cible>.
  • Serveur vs. Bureau : Sur les serveurs, multi-user.target est presque toujours préféré pour des raisons de sécurité et d'efficacité des ressources. Sur les bureaux, graphical.target est standard.
  • Maintenance du système : Pour les tâches nécessitant une interférence minimale, rescue.target est utile. Pour une récupération critique, emergency.target est disponible.

Une façon pratique de penser aux cibles

Pour la plupart des travaux d'administration, vous n'avez besoin que d'un modèle mental court :

systemctl get-default
systemctl set-default multi-user.target
systemctl isolate graphical.target
systemctl list-dependencies graphical.target

get-default vous indique où la machine est censée démarrer. set-default modifie le prochain démarrage. isolate modifie l'état actuel et peut arrêter les services en dehors de cet état. list-dependencies explique ce qu'une cible attire.

Les cibles ne sont pas simplement des niveaux d'exécution renommés. Ce sont des groupes de dépendances. Une fois que vous les traitez comme tels, les problèmes de démarrage deviennent plus faciles à raisonner : trouvez la cible que le système a essayé d'atteindre, inspectez les services qu'elle voulait, puis corrigez l'unité ou la dépendance qui a échoué.