Linux Embedded

Le blog des technologies libres et embarquées

Maîtriser les services GNU/Linux à l'aide de systemd

Dans cet article, nous allons présenter quelques outils de gestion des services, avec pour objectif d'améliorer la compréhension du fonctionnement des services (daemons) sous GNU/Linux. Comme ces outils sont dépendants du processus d'initialisation, nous considérons un système utilisant systemd.

Introduction à systemd

Systemd étant le processus qui gère tous les services (on parle de processus init), une petite présentation de ce dernier s'impose.

Contexte

Avant de parler du processus init, replaçons le dans son contexte. Le démarrage de Linux sur un PC peut se résumer en 4 étapes:

linuxbootprocess

Qu'attend-on du processus init?

Le processus init se charge de lancer les services (daemons) et de mettre en place un environnement pour l'utilisateur (graphique, réseau, etc). Sa dernière action consiste généralement à présenter un écran d'authentification, laissant la main à l'utilisateur.

Un daemon est un processus qui tourne en arrière plan et qui supervise le système ou bien fournit des fonctionnalités à d'autres processus.

Le processus init a un status particulier.

  • Il est le tout premier processus appelé par le kernel (PID = 1).
  • Il est le parent de tous les processus qui deviennent orphelins.
  • Il reste vivant jusqu'à l'arrêt du système.
  • A l'arrêt du système, il est chargé de fermer tous les services et de quitter proprement.

Les différents processus init

Il existe différents processus init, dont les plus connus sont:

  • SysVinit: processus init historique, hérité de UNIX System V.
  • Upstart: sorti en 2006, à l'origine pour Ubuntu.
  • Systemd: sorti en 2010.

Systemd est destiné à remplacer SysVinit et Upstart sur toutes les grandes distributions (Debian, Ubuntu, Fedora, ...).

Le fonctionnement de systemd diffère complètement de SysVinit et Upstart qui utilisaient principalement des scripts. Systemd permet une parallélisation des lancements des services et une activation à la demande de ceux-ci grâce à l'utilisation de sockets.

Solutions technologiques de systemd

Les dépendances entre les services compliquent beaucoup la conception d'un processus init. Une solution consiste à avoir un arbre statique des dépendances, et donc un ordre figé dans l'activation des services (solution SysVinit).

Systemd propose de lancer les services en parallèle. L'activation d'un service est conditionnée par la création des sockets qui le lient aux autres services, sans attendre la fin de leur initialisation. Ainsi, même si les services dont il dépend n'ont pas fini de démarrer, les messages envoyés sont temporisés par le mécanisme de buffers intrinsèque aux sockets.

Systemd introduit différentes façons d'activer un service:

  • Socket-Based : connexion réseau, réception d'un paquet.
  • Bus-Based : utilisation de dbus.
  • Device-Based : détection d'un nouveau périphérique.
  • Path-Based : surveillance sur un chemin.
  • Timer-Based : tâche périodique.

Ces différents types d'activations, et en particulier l'utilisation de D-Bus, permettent non seulement de démarrer les services en parallèle mais aussi de les lancer à la demande.

 

Les services, en pratique

Après cette courte introduction à systemd, allons explorer les services et leurs dépendances, à l'aide de quelques outils pratiques.

A propos des services en place

L'ordinateur vient de démarrer. Il y a une page pour s'identifier, la barre des tâches indique la charge de la batterie, l'état du réseau, le volume audio, etc. Autrement dit, quand on prend enfin la main sur notre système, il y a déjà tout un ensemble de processus qui sont actifs.

Pour en avoir une liste, on peut utiliser systemadm (paquet systemd-gui ou systemd-gtk) :

capt_systemadm

En choisissant "Services" dans le menu déroulant de l'onglet "Units", on affiche tous les services lancés sur le système. Cliquez sur un service et vous verrez apparaître diverses informations, dont une description, une liste des dépendances, le chemin où se trouve le fichier décrivant ce service, et bien sûr l'état du service.

Note : Les unités sont un concept introduit par systemd. Sans entrer dans les détails, systemd contrôle tout grâce aux unités. Une unité est un fichier. Il en existe 12 types. Certaines unités contiennent les informations spécifiques à un service (dépendances, exécutions, options), d'autres servent à définir des groupes en fonction des dépendances d'activation, ou encore permettent de gérer la communication entre services. Deux types sont importants : les unités services et les unités sockets. Le type d'une unité est indiqué par l'extension du nom du fichier (.service, .socket, .target, etc).

Exemple : avec accounts-daemon.service. Le "Fragment path" nous indique que le fichier correspondant se trouve dans /lib/systemd/system/accouts-daemon.service. Ouvrons ce fichier :

$ more /lib/systemd/system/accounts-daemon.service
 [Unit]
 Description=Accounts Service
 
 [Service]
 Type=dbus
 BusName=org.freedesktop.Accounts
 ExecStart=/usr/lib/accountsservice/accounts-daemon
 
 [Install]
 # We pull this in by graphical.target instead of waiting for the bus
 # activation, to speed things up a little: gdm uses this anyway so it is nice
 # if it is already around when gdm wants to use it and doesn't have to wait for
 # it.
 WantedBy=graphical.target

On remarque que le fichier de configuration est court et organisé par section. Les sections [Unit] et [Install] sont communes à tous les types d'unités. La section [Service] est spécifiques aux unités .service et contient, entre autre, la commande pour lancer le service. Quelques éléments de ces sections sont abordés dans la partie suivante. Pour plus de renseignements sur ces éléments, on peut se référer aux manuels :

$ man systemd.service
$ man systemd.unit

Les dépendances

Remonter les dépendances relève un peu du jeu de piste. Voici la liste des dépendances fournie par systemadm concernant accounts-daemon :

requires: basic.target(active), dbus.socket(running)
wants: system.slice(active)
conflicts: shutdown.target(dead)
wanted by: graphical.target(active)
after: basic.target(active), dbus.socket(running), system.slice(active), systemd-journald.socket(running)
before: graphical.target(active), shutdown.target(dead)

Certaines dépendances découlent directement du fichier unité accounts-daemon.service :

WantedBy=graphical.target

D'autres sont activées par défaut. Citation de "man systemd.service" et man systemd.slice" :

« Unless DefaultDependencies= is set to false, service units will implicitly have dependencies of type Requires= and After= on basic.target as well as dependencies of type Coflicts= and Before= on shutdown.target. »
« By default, service and scope units are placed in system.slice »

Ou par l'intermédiaire d'options. Le fichier unité accounts-daemon.service indique que le service utilise dbus :

Type=dbus

Or d'après « man systemd.service » :

« Service units with [dbus] option configured implicitly gain dependencies on the dbus.socket unit. »

Note : Certains services ont une description commençant par « LSB : » et le champ Fragment Path est vide. Ces services correspondent à des scripts issus de SysVinit. Ils sont présents dans le dossier /etc/init.d/.

La liste des dépendances fournie par systemadm concerne seulement les dépendances directes. Pour avoir une meilleure idée des étapes par lesquelles un service doit passer avant d'être lancé, on peut utiliser systemd-analyze. L'outil systemd-analyze nous permet de visualiser le chemin parcouru, en terme de dépendances, en gardant les étapes qui ont pris le plus de temps :

systemd-analyze critical-chain accounts-daemon.service
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

accounts-daemon.service +5.346s
└─basic.target @8.604s
 └─paths.target @8.603s
  └─cups.path @8.603s
   └─sysinit.target @8.566s
    └─nfs-common.service @7.968s +596ms
     └─rpcbind.target @7.967s
      └─rpcbind.service @7.414s +552ms
       └─network-online.target @7.413s
        └─network.target @7.413s
         └─networking.service @4.790s +2.623s
          └─systemd-random-seed.service @4.519s +269ms
           └─systemd-remount-fs.service @3.785s +733ms
            └─keyboard-setup.service @2.198s +1.586s
             └─systemd-udevd.service @2.108s +89ms
              └─systemd-tmpfiles-setup-dev.service @1.426s +682ms
               └─kmod-static-nodes.service @1.295s +109ms
                └─systemd-journald.socket @1.292s
                 └─-.mount @1.290s
                  └─system.slice @1.364s
                   └─-.slice @1.364s

Note : Si on ne spécifie pas le service, systemd-analyze critical-chain affichera le chemin critique global, c'est-à-dire le chemin de dépendances qui a pris le plus de temps à s'achever.

L'initialisation

On peut connaître le temps de démarrage global grâce à systemd-analyse :

$ systemd-analyze time
 Startup finished in 6.168s (kernel) + 15.814s (userspace) = 21.983s

Regardons la liste des services lancés par systemd, triée par temps de démarrage.

$ systemd-analyse blame
 7.833s loadcpufreq.service
 7.830s exim4.service
 7.410s ModemManager.service
 7.126s NetworkManager.service
 6.454s accounts-daemon.service
 5.466s bluetooth.service
 5.287s avahi-daemon.service
 5.273s systemd-logind.service
 4.657s bootlogs.service
 3.831s nfs-kernel-server.service
 2.769s gdm.service
 2.670s rsyslog.service
 2.658s xinetd.service
 ...

Renseignons nous par exemple sur exim4. La description dans systemadm nous indique qu'il s'agit d'un agent de messagerie. On peut arrêter ce service pour la session en cour avec systemctl :

sudo systemctl stop exim4

Ou bien le désactiver pour les prochains redémarrages :

sudo systemctl disable exim4

Note : Désactiver exim4 ne fera pas gagner 7 secondes sur le temps de démarrage. Les services sont lancés en parallèle et les temps de démarrages sont liés aux dépendances.

 

Conclusions

Ces quelques outils permettent de facilement visualiser l'ensemble des services et de mieux comprendre les liens et dépendances entre eux.  Pour aller plus loin dans l'utilisation de ses outils, suivre les tutoriels "The systemd for Administrators Blog Series" disponibles ici : http://0pointer.de/blog/projects/systemd-for-admins-1.html.

 

Bibliographie

http://fr.wikipedia.org/wiki/Systemd

http://0pointer.de/public/systemd-man/daemon.html

http://www.tldp.org/LDP/sag/html/major-services.html

http://doc.fedora-fr.org/wiki/Systemd

    • le 30 juillet 2015 à 18:16

      […] les couches de l’infrastructure d’un système linux récent. Après avoir abordé la partie init de systemd puis avoir étudié comment les événements noyau créent des entrées dans /dev grâce à udev, […]

    • le 08 août 2016 à 14:49

      […] – Le support de systemd a été sérieusement retravaillé avec plusieurs dizaine de patches issus du travail de Gave Evans et du travail complémentaire de Maxime Hadjinlian et Yann E. Morin. Systemd a fait l’objet d’un précédent article sur Linuxembedded ici […]

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.