Systemd unités (services, timers, mount)
Créer des unités (services, timers, mount)
Article original : systemd : Créer des unités (services, timers, mount)
Rappels systemd
Un service est un programme qui est exécuté en tache de fond (sans interaction directe avec l’utilisateur). A noter qu’un service peut être appelé également démon.
Chez systemd, on ne parle pas de service, mais d’unité (unit).
Il existe des unités service, comme on l’entend avec OpenRC ou du temps de sysVinit, mais il existe d’autres unités telles que “automount”, “path”, “mount”, “target”, “timer”, “wants” et “socket”.
Les unités du système sont créées dans /usr/lib/systemd/system
Les unités créées personnelles seront à placer dans /etc/systemd/system
Une fois une unité créée ou modifiée, il faut relancer le démon systemd :
1
systemctl --system daemon-reload
Types d’unités
J’ai listé ci-dessus les différentes unités possibles. Il y a donc :
- service : pour un service/démon
- socket : pour une socket réseau (de tous types : UNIX, fichier …)
- mount : pour un système de fichiers (exemple : home.mount), /etc/fstab est aussi utilisé sur le système
- swap : comme mount mais pour les partitions d’échanges
- automount : comme mount mais pour un système de fichiers monté à la demande
- device : pour un périphérique
- timer : pour l’activation basée sur une date
- path : pour l’activation basée sur des fichiers ou des répertoires ;
- target : macro-unité qui permet de grouper plusieurs unités (exemple : multi-user.target pour définir une cible) : Ce sont les niveaux d’exécutions de l’ancien système d’init.
Les services
Du côté des services, il existe plusieurs types de service. C’est défini dans le fichier de configuration par Type= avec comme valeur possible : simple, forking, oneshot, dbus, notify.
Nous allons rester simple et ne traiter que les cas suivants :
- Service simple : C’est le type par défaut. Il lance un processus principal. Le créateur du service doit s’assurer de créer les canaux de communication ou de lancer les processus avant le lancement du dit service. Systemd ne se préoccupe pas de la fin de l’exécution du service pour traiter d’autres unités.
- Service oneshot : Le fonctionnement est similaire au type simple. Cependant, systemd attend que le processus soit terminé avant de continuer ses traitement. (Fonctionnement similaire des services sysVinit, au rc.local)
- Service forking : Ce service lance un processus père, qui créera un processus fils. Le processus parent s’arrête une fois le service complètement démarré (canaux de communication inclus). Le processus fils tourne tant que le service est démarré. Systemd traite les autres unités une fois le processus père précédemment décrit est terminé. Par analogie, ce sont ainsi que fonctionnent les scripts unix traditionnels.
Il existe d’autres types, tel que notify, et dbus par exemple non abordés ici.
Syntaxe service
Pour les services voici une structure classique, avec quelques options facultatives aussi :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=
After=
ConditionPathExists=
[Service]
Type=
ExecStartPre=
ExecStart=
ExecStop=
ExecStopPost=
RemainAfterExit=
Restart=
[Install]
WantedBy=
On a donc 3 sections :
- La section Unit permet de décrire le service, de vérifier des prérequis.
- La section Service définit le type de service, et ce qu’il va faire
- La section Install s’occupe des circonstances et des déclencheurs
Dans la section Unit, on retrouve :
- Description : Description du service
- After : Doit se lancer après un processus donné (exemple : After=network.target)
- ConditionPathExists : Sera utilisé si le chemin existe (facultatif)
Dans la section Service, on retrouve :
- Type : Le type de service (simple, forking, oneshot, …)
- ExecStartPre : Commande à exécuter avant le démarrage du service (facutatif)
- ExecStart : Commande de service lorsque start est invoqué
- ExecStop : Commande de service lorsque stop est invoqué (facultatif)
- ExecStopPost : Commande à exécuter après l’arrêt du service (facultatif)
- RemainAfterExit : yes = Quand ExecStart est terminée, le service est considéré comme toujours lancé. (utile pour oneshot) / no = Ne doit pas considérer que le service est actif lorsque le processus neo4j s’est terminé normalement. (facultatif)
- Restart : Permet de redémarre le service (on-failure = après un plantage) (facultatif)
A noter qu’on peut aussi utiliser :
- User= : Permet de lancer le processus sous le nom d’un utilisateur donné
- Group= Permet de lancer le processus sous le nom d’un groupe donné
Dans la section Install, on retrouve :
- WantedBy : Dans quel cadre le service s’exécute ( multi-user.target = mode multi-utilisateurs) (facultatif)
Exemples de services
Exemple de script permettant de restaurer la fonction du fichier rc.local :
1
nano /etc/systemd/system/rclocal.service
1
2
3
4
5
6
7
8
9
10
[Unit]
Description=Exécuter le fichier rc.local
ConditionFileIsExecutable=/etc/rc.local
After=network.target
[Service]
Type=oneshot
ExecStart=/etc/rc.local
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Voici un exemple de service utilisé pour gérer un script de parefeu :
1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=Parefeu Perso
ConditionFileIsExecutable=/root/iptables-perso.sh
After=network.target
[Service]
Type=oneshot
ExecStart=/root/iptables-perso.sh
ExecStop=/root/iptables-flush.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Services modèles
Parfois, vous pourrie avoir besoin de créer des services modèles. Un service modèle est un service qui peut recevoir un paramètre en argument.
Ils seront nommés sur cette syntaxe : leservice@.service
Lorsque vous démarrez le service, ce qui est derrière l’arobase est un argument passé au service.
Il s’écrit de la même manière qu’un service classique, l’argument passé à l’arobase est récupéré par la variable %i
Exemple avec un service vnc@.service
Dans la ligne ExecStart on va passer l’argument %i
1
ExecStart=/usr/bin/vncserver %i
Ainsi, quand on lance
1
systemctl start vnc@:1.service
La commande lancée sera :
1
/usr/bin/vncserver :1
Et me lancera donc un serveur VNC sur l’affichage :1.
Vous pouvez regarder les services composés ainsi sur votre système via
1
find /usr/lib/systemd/system -iname '*@*.service'
Les timers ou services périodiques
Les timers sont des fichiers de programmation qui vont se charger de lancer des services à intervalles réguliers.
Quand vous créez un timer, il doit avoir l’extension .timer. Un service .service du même nom doit exister. (le service est souvent un service minimaliste, de type oneshot, permettant de lancer une commande)
Les timers «pourraient presque» remplacer le planificateur de tâches cron.
Syntaxe d’un timer
Un timer possède une section Unit et Install comme un service.
Cependant la section Service n’existe pas et s’appelle Timer :
1
2
3
4
5
6
7
8
9
[Unit]
Description=
[Timer]
OnBootSec=
OnUnitActiveSec=
OnCalendar=
Persistent=
[Install]
WantedBy=timers.target
Dans la section Timer, on peut retrouver :
- OnBootSec : Démarre le service du même nom que le timer après X secondes
- OnUnitActiveSec : Répétition toutes les X secondes tant que le système est en fonctionnement
- OnCalendar : Quand lancer le timer (voir ci-dessous)
- Persistent : yes = Si le système était à l’arrêt pendant le déclenchement, le lancement raté est rattrapé (utilisé avec OnCalendar)
Pour les valeurs en Secondes, on peut utiliser des suffixes tels que min, h, d et w pour minutes, heures, jours et semaines.
Pour la valeur OnCalendar :
- daily = à minuit chaque jour
- weekly = tous les lundis à minuit
- DayOfWeek Year-Month-Day Hour:Minute:Second Au format attendu
Exemples :
- OnCalendar=--* 1:00:00 : Tous les jours à 1h du matin
- OnCalendar=Sun --* 12:00:00 : Tous les dimanches à midi
- OnCalendar=--1 00:20:00 : Tous les premiers du mois à 00h20
- OnCalendar=Mon --1..7 6:00:00 ; Du 1 au 7 du mois, qui soit un lundi, à 6h (traduisez le premier lundi du mois à 6h)
Côté syntaxe :
- ***** : Toutes les occurrences
- 1 : Occurrence 1
- 1..7 : Occurrences de 1 à 7
- 0,12 : Occurrences 0 et 12
Plus d’exemples avec les OnCalendar des services installés sur le système :
1
grep OnCalendar -r /usr/lib/systemd/system/
Exemples de timers
Voici un exemple du timer logrotate.timer (qui va lancer à intervalle régulier logrotate.service) :
1
2
3
4
5
6
7
8
[Unit]
Description=Daily rotation of log files
[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true
[Install]
WantedBy=timers.target
Unités de montage mount
Les unités .mount permettent de gérer les points de montage du système via systemd au lieu du traditionnel fichier /etc/fstab. L’avantage majeur est de pouvoir gérer proprement les dépendances : par exemple, s’assurer qu’un service de base de données ne démarre que si le disque de données est effectivement monté.
Règle de nommage
Contrairement aux services, le nom du fichier d’unité mount ne peut pas être choisi arbitrairement. Il doit correspondre au chemin du point de montage. La règle est simple : on remplace les slashs / par des tirets -.
Exemple : Pour monter un disque dans /media/DATA, le fichier doit s’appeler media-DATA.mount.
Si le chemin est complexe, on peut utiliser systemd-escape pour générer le nom correct :
1
systemd-escape -p --suffix=mount "/media/DATA"
Mount
La structure comporte une section Mount qui reprend les arguments habituels de la commande mount :
1
2
3
4
5
6
7
8
9
10
11
[Unit]
Description=Montage du disque de données
[Mount]
What=/dev/disk/by-uuid/ac11d0b1-9304-4e32-a943-1ebeaac74d3b
Where=/media/DATA
Type=ext4
Options=defaults
[Install]
WantedBy=multi-user.target
Dabs la section Mount, on retrouve :
- What : Le périphérique à monter (L’UUID comme dans fstab évite les renommages de disques)
- Where : Le chemin complet du point de montage
- Type : Le système de fichiers (ext4, nfs, cifs, etc.)
- Options : Les options de montage (comme dans fstab)
Automount montage à la demande
Il est possible de coupler une unité mount avec une unité .automount. Cela permet de ne monter le périphérique que lorsqu’on tente d’accéder au dossier (très utile pour les partages réseau NFS ou Samba afin de ne pas ralentir le démarrage si le serveur distant est absent).
Pour /media/DATA, on crée un fichier media-DATA.automount :
1
2
3
4
5
6
7
8
[Unit]
Description=Montage automatique du disque data
[Automount]
Where=/media/DATA
[Install]
WantedBy=multi-user.target
Dans ce cas, on n’active que l’unité .automount au démarrage.
Systemd se chargera d’appeler l’unité .mount correspondante dès qu’un processus fera un “ls” ou un “cd” dans le répertoire !
