Unit templates =3a comment systemd r=c3=a9cup=c3=a8re le nom des instances =c3=a0 d=c3=a9marrer =3f

Le
Francois Lafont
Bonjour à tous,

J'ai une question sur systemd et, plus précisément, sur les templates
d'unités systemd. Je donne un exemple avec ma Ubuntu 18.04 perso où j'ai
ceci :


~$ sudo service postgresql@10-main status
● postgresql@10-main.service - PostgreSQL Cluster 10-main
Loaded: loaded (/lib/systemd/system/postgresql@.service; indirect; vendor preset: enabled)
Active: active (running) since Sat 2018-12-01 11:36:51 CET; 38min ago
Process: 1184 ExecStart=/usr/bin/pg_ctlcluster --skip-systemctl-redirect 10-main start (code=exited, status=0/SUCCESS)
Main PID: 1274 (postgres)
Tasks: 7 (limit: 4915)
CGroup: /system.slice/system-postgresql.slice/postgresql@10-main.service
├─1274 /usr/lib/postgresql/10/bin/postgres -D /var/lib/postgresql/10/main -c config_file=/etc/postgresql/10/main/postgresql.conf
├─1292 postgres: 10/main: checkpointer process
├─1293 postgres: 10/main: writer process
├─1294 postgres: 10/main: wal writer process
├─1295 postgres: 10/main: autovacuum launcher process
├─1296 postgres: 10/main: stats collector process
└─1297 postgres: 10/main: bgworker: logical replication launcher

Dec 01 11:36:49 flhpz4 systemd[1]: Starting PostgreSQL Cluster 10-main
Dec 01 11:36:51 flhpz4 systemd[1]: Started PostgreSQL Cluster 10-main.


J'ai donc le fichier /lib/systemd/system/postgresql@.service qui est un unit
template, ie une unité systemd qui pourra se décliner en plusieurs instances.
Et dans mon cas j'ai l'instance "postgresql@10-main" qui tourne automatiquement
au boot où :

- "10" est la version de PostGreSQL sur ma Ubuntu,
- "main" est le nom du clusteur PostGreSQL.

L'idée, si j'ai bien compris, est qu'avec une même unité systemd, on peut alors
lancer plusieurs daemons (par exemple je pourrais avoir plusieurs versions de
PostgreSQL qui tournent sur ma machine, ou alors une seule version mais plusieurs
clusters PostgreSQL qui tournent etc).

Voici le contenu de mon unit template /lib/systemd/system/postgresql@.service :


$ cat /lib/systemd/system/postgresql@.service
# systemd service template for PostgreSQL clusters. The actual instances will
# be called "postgresql@version-cluster", e.g. "postgresql@9.3-main". The
# variable %i expands to "version-cluster", %I expands to "version/cluster".
# (%I breaks for cluster names containing dashes.)

[Unit]
Description=PostgreSQL Cluster %i
ConditionPathExists=/etc/postgresql/%I/postgresql.conf
PartOf=postgresql.service
ReloadPropagatedFrom=postgresql.service
Before=postgresql.service

[Service]
Type=forking
# -: ignore startup failure (recovery might take arbitrarily long)
# the actual pg_ctl timeout is configured in pg_ctl.conf
ExecStart=-/usr/bin/pg_ctlcluster --skip-systemctl-redirect %i start
# 0 is the same as infinity, but "infinity" needs systemd 229
TimeoutStartSec=0
ExecStop=/usr/bin/pg_ctlcluster --skip-systemctl-redirect -m fast %i stop
TimeoutStopSec=1h
ExecReload=/usr/bin/pg_ctlcluster --skip-systemctl-redirect %i reload
PIDFile=/var/run/postgresql/%i.pid
SyslogIdentifier=postgresql@%i
# prevent OOM killer from choosing the postmaster (individual backends will
# reset the score to 0)
OOMScoreAdjust=-900
# restarting automatically will prevent "pg_ctlcluster stop" from working,
# so we disable it here. Also, the postmaster will restart by itself on most
# problems anyway, so it is questionable if one wants to enable external
# automatic restarts.
#Restart=on-failure
# (This should make pg_ctlcluster stop work, but doesn't:)
#RestartPreventExitStatus=SIGINT SIGTERM

[Install]
WantedBy=multi-user.target


Dans le cas de mon instance "postgresql@10-main" automatiquement démarrée
au boot, dans le template ci-dessus :

- le "%i" a été remplacé par "10-main"
- le "%I" a été remplacé par "10/main"

On imagine bien que le "10/main" trouve son origine au niveau de
l'arborescence de mon système où j'ai les répertoires suivants :
- /etc/postgresql/10/main/
- /var/lib/postgresql/10/main/.


Maintenant voici ma question

Au moment du boot, l'instance "10/main" est démarrée automatiquement par
systemd mais quel mécanisme précisément permet de faire en sorte que c'est
bien l'instance "10/main" qui est démarrée pas une autre ? En d'autres termes,
j'ai un template mais il faut bien un programme, un code shell etc. pour
alimenter ce template avec des valeurs (pour que les %i, %I etc. se remplissent).
Donc il doit bien y avoir quelque part une configuration, un code shell ou je
ne sais quoi pour dire à systemd « c'est l'instance "10/main" de postgresql@.service
que tu dois lancer automatiquement au boot ». Mais je n'arrive pas à trouver sur
ma machine où cela est mis en place. Pouvez-vous me dire où ?

J'espère que c'est à peu près clair.
Merci d'avance pour votre aide.

--
François Lafont
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Lucas Levrel
Le #26499795
Le 1 décembre 2018, à 12:49, Francois Lafont a écrit :
Au moment du boot, l'instance "10/main" est démarrée automatiquement par
systemd mais quel mécanisme précisément permet de faire en sorte que c'est
bien l'instance "10/main" qui est démarrée pas une autre ? En d'autres
termes,
j'ai un template mais il faut bien un programme, un code shell etc. pour
alimenter ce template avec des valeurs (pour que les %i, %I etc. se
remplissent).
Donc il doit bien y avoir quelque part une configuration, un code shell ou je
ne sais quoi pour dire à systemd « c'est l'instance "10/main" de

que tu dois lancer automatiquement au boot ». Mais je n'arrive pas à trouver
sur
ma machine où cela est mis en place. Pouvez-vous me dire où ?

D'après man systemd.unit :
---
Optionally, units may be instantiated from a template file at runtime.
This allows creation of multiple units from a single configuration file.
If systemd looks for a unit configuration file, it will first search for
the literal unit name in the file system. If that yields no success and
the unit name contains an "@" character, systemd will look for a unit
template that shares the same name but with the instance string (i.e. the
part between the "@" character and the suffix) removed. Example: if a
service is requested and no file by that name is found,
systemd will look for and instantiate a service from that
configuration file if it is found.
To refer to the instance string from within the configuration file you may
use the special "%i" specifier in many of the configuration options. See
below for details.
---
J'en déduis que tu as quelque part un "service" ou un "target" qui demande
("wants", "requires") explicitement cette instance, et systemd fait le
reste.
Plus loin :
---
WantedBy=foo.service in a service bar.service is mostly equivalent to
Alias=foo.service.wants/bar.service in the same file. In case of template
units, systemctl enable must be called with an instance name, and this
instance will be added to the .wants/ or .requires/ list of the listed
unit. E.g. WantedBy=getty.target in a service will result
in systemctl enable creating a
getty.target.wants/ link to
---
Donc c'est peut-être un script post-installation du paquet qui a exécuté
systemctl enable .
Dans tous les cas tu devrais trouver un lien symbolique
quelque part dans /etc/systemd , il me semble.
--
LL
Ἕν οἶδα ὅτι οὐδὲν οἶδα (Σωκράτης)
C'est mieux avé les accents (F. Patte)
Francois Lafont
Le #26499805
Bonjour Lucas, merci pour ta réponse.
On 12/2/18 12:27 PM, Lucas Levrel wrote:
Donc c'est peut-être un script post-installation du paquet
qui a exécuté systemctl enable .

C'est ce que je me suis dit mais je n'ai pas trouvé (mais je n'ai
peut-être pas bien cherché).
Pour mémoire, je suis sous Ubuntu 18.04 mais j'ai constaté la même
chose sous Debian Stretch par exemple avec PostgreSQL (dans une version
différente que sous Ubuntu mais avec le même mécanisme de template, donc
a priori le même phénomène d'un point de vue systemd qui est le point
de vue qui m'intéresse ici).
Dans tous les cas tu devrais trouver un lien symbolique
quelque part dans /etc/systemd , il me semble.

Et bien c'est ce que je pensais aussi mais ce n'est pas le cas non plus.
------------------------------------------------------
~$ tree /etc/systemd/ | grep -i post
│   │   ├── postgresql.service -> /lib/systemd/system/postgresql.service
------------------------------------------------------
où /lib/systemd/system/postgresql.service est une sorte d'unit « dummy »
qui doit être là pour mettre en place une arborescence de dépendances ou
un truc dans le genre :
------------------------------------------------------
~$ cat /lib/systemd/system/postgresql.service
# systemd service for managing all PostgreSQL clusters on the system. This
# service is actually a systemd target, but we are using a service since
# targets cannot be reloaded.
[Unit]
Description=PostgreSQL RDBMS
[Service]
Type=oneshot
ExecStart=/bin/true
ExecReload=/bin/true
RemainAfterExit=on
[Install]
WantedBy=multi-user.target
------------------------------------------------------
Une chose qui m'interroge :
------------------------------------------------------
~$ sudo systemctl --full is-enabled postgresql
enabled
/etc/systemd/system/multi-user.target.wants/postgresql.service
~$ sudo systemctl --full is-enabled
enabled-runtime
------------------------------------------------------
Malgré l'option --full, je n'ai pas symlink indiqué pour
"". Par ailleurs, cette valeur retournée
"enabled-runtime" m'interroge aussi. Dans man systemctl(1), on peut
lire :
------------------------------------------------------
enabled, enabled-runtime
Enabled via .wants/, .requires/ or Alias= symlinks
(permanently in /etc/systemd/system/, or transiently
in /run/systemd/system/).
------------------------------------------------------
Mais perso, je n'ai rien dans /run/systemd/system/ :
------------------------------------------------------
$ ll /run/systemd/system/
total 0
drwxr-xr-x 2 root root 40 Dec 2 10:59 ./
drwxr-xr-x 21 root root 480 Dec 2 11:02 ../
------------------------------------------------------
Donc pour l'instant, la manière dont systemd « sait » qu'il faut
instancier le service "" reste encore bien
mystérieux pour moi.
--
François Lafont
Francois Lafont
Le #26499906
Bonsoir,
On 12/2/18 1:16 PM, Francois Lafont wrote:
------------------------------------------------------
enabled, enabled-runtime
    Enabled via .wants/, .requires/ or Alias= symlinks
    (permanently in /etc/systemd/system/, or transiently
    in /run/systemd/system/).
------------------------------------------------------
Mais perso, je n'ai rien dans /run/systemd/system/ :
------------------------------------------------------
$ ll /run/systemd/system/
total 0
drwxr-xr-x  2 root root  40 Dec  2 10:59 ./
drwxr-xr-x 21 root root 480 Dec  2 11:02 ../
------------------------------------------------------

En fait, j'ai bien un symlink dans /run/systemd/ mais pas dans
/run/systemd/system/. Il se trouve dans /run/systemd/generator/ :
------------------------------------------------------
~$ ll /run/systemd/generator/postgresql.service.wants/
total 0
drwxr-xr-x 2 root root 60 Dec 2 18:28 ./
drwxr-xr-x 7 root root 400 Dec 2 18:28 ../
lrwxrwxrwx 1 root root 39 Dec 2 18:28 -> /lib/systemd/system/
------------------------------------------------------
Seulement /run/ est un point de montage de type tmpfs et qui est
donc vide au boot. Il y a donc bien un « programme » qui a peuplé
cette partition et en particulier qui a créé le symlink ci-dessus,
mais lequel ? C'est tout l'objet de mon post.
--
François Lafont
Francois Lafont
Le #26500038
Bonsoir,
On 12/2/18 10:53 PM, Francois Lafont wrote:
En fait, j'ai bien un symlink dans /run/systemd/ mais pas dans
/run/systemd/system/. Il se trouve dans /run/systemd/generator/ :
------------------------------------------------------
~$ ll /run/systemd/generator/postgresql.service.wants/
total 0
drwxr-xr-x 2 root root  60 Dec  2 18:28 ./
drwxr-xr-x 7 root root 400 Dec  2 18:28 ../
lrwxrwxrwx 1 root root  39 Dec  2 18:28 -> /lib/systemd/system/
------------------------------------------------------
Seulement /run/ est un point de montage de type tmpfs et qui est
donc vide au boot. Il y a donc bien un « programme » qui a peuplé
cette partition et en particulier qui a créé le symlink ci-dessus,
mais lequel ? C'est tout l'objet de mon post.

Et bien j'ai fini par trouver. Dans le package "postgresql-common", il y
a un fichier
/lib/systemd/system-generators/postgresql-generator
C'est ce fichier, qui est d'ailleurs un bête script shell, qui est à
l'origine de la création du symlink
/run/systemd/generator/postgresql.service.wants/
qui lui-même va faire démarrer le daemon « » via le
template « ». En gros, lors du démarrage de systemd,
celui-ci va lancer un composant "systemd.generator" qui va justement
générer à la volée des unités dans le tmpfs /run/systemd/ qui seront
utilisés (ou non) par systemd. Et ce composant utilise les éventuels
scripts shell qui se trouvent dans /lib/systemd/system-generators/
Voici le contenu du script shell en question qui montre bien comment
le ou les symlinks sont créés en fonction de l'arborescence
"/etc/postgresql/$VERSION/$CLUSTER/postgresql.conf" présente sur le
système :
------------------------------------------------------
~$ cat /lib/systemd/system-generators/postgresql-generator
#!/bin/sh
# This systemd generator creates dependency symlinks that make all PostgreSQL
# clusters with "auto" in their start.conf file be started/stopped/reloaded
# when postgresql.service is started/stopped/reloaded.
set -eu
gendir="$1"
wantdir="$1/postgresql.service.wants"
pgservice="/lib/systemd/system/"
mkdir -p "$wantdir"
for conf in /etc/postgresql/*/*/postgresql.conf; do
# abort loop if glob was not expanded (but accept dead symlinks)
if ! test -e "$conf" && ! test -L "$conf"; then continue; fi
dir="${conf%/*}"
# evaluate start.conf
if [ -e "$dir/start.conf" ]; then
start=$(sed 's/#.*$//; /^[[:space:]]*$/d; s/^s*//; s/s*$//' "$dir/start.conf")
else
start=auto
fi
[ "$start" = "auto" ] || continue
verdir="${dir%/*}"
version="${verdir##*/}"
cluster="${dir##*/}"
ln -s "$pgservice" "$wantdir/postgresql@$version-$cluster.service"
done
exit 0
------------------------------------------------------
Ce fil a été l'occasion pour moi de me pencher un peu plus sur systemd, ce qui
est toujours intéressant. Je considère ce fil comme résolu (sauf si j'ai écrit
des bêtises auquel cas je suis toujours preneurs d'explications complémentaires
évidemment).
À+
--
François Lafont
Doug713705
Le #26500039
Le 2018-12-03, Francois Lafont nous expliquait dans
fr.comp.os.linux.configuration
(
Bonsoir,
On 12/2/18 10:53 PM, Francois Lafont wrote:
En fait, j'ai bien un symlink dans /run/systemd/ mais pas dans
/run/systemd/system/. Il se trouve dans /run/systemd/generator/ :
------------------------------------------------------
~$ ll /run/systemd/generator/postgresql.service.wants/
total 0
drwxr-xr-x 2 root root  60 Dec  2 18:28 ./
drwxr-xr-x 7 root root 400 Dec  2 18:28 ../
lrwxrwxrwx 1 root root  39 Dec  2 18:28 -> /lib/systemd/system/
------------------------------------------------------
Seulement /run/ est un point de montage de type tmpfs et qui est
donc vide au boot. Il y a donc bien un « programme » qui a peuplé
cette partition et en particulier qui a créé le symlink ci-dessus,
mais lequel ? C'est tout l'objet de mon post.

Et bien j'ai fini par trouver. Dans le package "postgresql-common", il y
a un fichier
/lib/systemd/system-generators/postgresql-generator
C'est ce fichier, qui est d'ailleurs un bête script shell, qui est à
l'origine de la création du symlink
/run/systemd/generator/postgresql.service.wants/
qui lui-même va faire démarrer le daemon « » via le
template « ». En gros, lors du démarrage de systemd,
celui-ci va lancer un composant "systemd.generator" qui va justement
générer à la volée des unités dans le tmpfs /run/systemd/ qui seront
utilisés (ou non) par systemd. Et ce composant utilise les éventuels
scripts shell qui se trouvent dans /lib/systemd/system-generators/

C'est d'une complexité sans nom !
Ce fil a été l'occasion pour moi de me pencher un peu plus sur systemd, ce qui
est toujours intéressant.

C'est toujours ça de pris. Connaître la bête de l'intérieur c'est
toujours mieux.
Merci pour les détails qui pourront reservir.
--
Retour aux joints et à la bière.
Désertion du rayon képis !
J'ai rien contre vos partenaires
Mais rien contre vos p'tites s½urs ennemies.
H.F. Thiéfaine- 113ème Cigarette Sans Dormir
Christophe PEREZ
Le #26500040
Le Tue, 04 Dec 2018 00:18:37 +0000, Doug713705 a écrit :
C'est d'une complexité sans nom !

Tout ce qu'il faut pour repousser d'encore quelques années mon intention
de migrer de OpenRC à systemd ;)
Francois Lafont
Le #26500184
Bonsoir,
Je réagis ci-dessous à ta réponse et à celle de Christophe qui va aussi dans ton sens.
On 12/4/18 1:18 AM, Doug713705 wrote:
C'est d'une complexité sans nom !

Et bien je ne suis pas d'accord (bien que j'ai pas mal galéré pour trouver la réponse
à ce fil mais bon je pense que ce n'est pas une raison). :)
Systemd lance les services avec des « units » et perso je trouve ça très bien.
La syntaxe en .ini est très simple, ça donne un cadre et franchement on peut
« daemoniser » un programme (qui ne forke pas) en 1 minute chrono (perso, avec
sysvinit, je trouvais ça bien plus compliqué et je devais souvent me gratter la
tête pendant des heures). En plus la mise en place de relation de dépendances
est vraiment simple à définir.
Ensuite il y a le cas des daemons qui peuvent se décliner en plusieurs instances
(comme c'est le cas de PostgreSQL donc, de Openvpn, de Ceph et de bien d'autres
programmes). Je trouve que l'idée d'une « unit » de type template carrément bonne
et cohérente (avec des %i, %I etc. pour « variabiliser » le template). Ensuite,
il faut bien un moyen pour « remplir » ces templates qui vont instancier plusieurs
daemons. Bon, ok, faut le savoir, c'est dans :
/lib/systemd/system-generators/
que se trouvent certains exécutables qui vont permettre de décliner un template
en plusieurs instances. Et comme la philosophie pour activer un service est
d'utiliser les symlinks (qui pointent vers une unit, en général fournie par le
package), je ne trouve pas ça déconnant que les exécutables de
/lib/systemd/system-generators/ se contentent de créer de tels symlinks, et
comme les instances peuvent varier dans le temps (je peux un jour ne plus avoir
besoin d'une instance Openvpn A et besoin d'une nouvelle instance B), je ne trouve
pas non plus déconnant que ces symlinks soient regénérés dans leur ensemble à
chaque boot au niveau d'un tmpfs (en l'occurrence /run/systemd/).
Bref, a posteriori je trouve que le mécanisme est plutôt cohérent.
--
François Lafont
Francois Lafont
Le #26500183
On 12/4/18 10:25 PM, Francois Lafont wrote:
[...] Bref, a posteriori je trouve que le mécanisme est plutôt cohérent.

Alors Doug713705 et Christophe... convaincus ? ;)
--
François Lafont
Doug713705
Le #26500185
Le 2018-12-04, Francois Lafont nous expliquait dans
fr.comp.os.linux.configuration
(
Bonsoir,

Bonsoir,
Je réagis ci-dessous à ta réponse et à celle de Christophe qui va aussi dans ton sens.
On 12/4/18 1:18 AM, Doug713705 wrote:
C'est d'une complexité sans nom !

Et bien je ne suis pas d'accord (bien que j'ai pas mal galéré pour trouver la réponse
à ce fil mais bon je pense que ce n'est pas une raison). :)
Systemd lance les services avec des « units » et perso je trouve ça très bien.
La syntaxe en .ini est très simple, ça donne un cadre et franchement on peut
« daemoniser » un programme (qui ne forke pas) en 1 minute chrono (perso, avec
sysvinit, je trouvais ça bien plus compliqué et je devais souvent me gratter la
tête pendant des heures). En plus la mise en place de relation de dépendances
est vraiment simple à définir.
Ensuite il y a le cas des daemons qui peuvent se décliner en plusieurs instances
(comme c'est le cas de PostgreSQL donc, de Openvpn, de Ceph et de bien d'autres
programmes). Je trouve que l'idée d'une « unit » de type template carrément bonne
et cohérente (avec des %i, %I etc. pour « variabiliser » le template). Ensuite,
il faut bien un moyen pour « remplir » ces templates qui vont instancier plusieurs
daemons. Bon, ok, faut le savoir, c'est dans :
/lib/systemd/system-generators/
que se trouvent certains exécutables qui vont permettre de décliner un template
en plusieurs instances. Et comme la philosophie pour activer un service est
d'utiliser les symlinks (qui pointent vers une unit, en général fournie par le
package), je ne trouve pas ça déconnant que les exécutables de
/lib/systemd/system-generators/ se contentent de créer de tels symlinks, et
comme les instances peuvent varier dans le temps (je peux un jour ne plus avoir
besoin d'une instance Openvpn A et besoin d'une nouvelle instance B), je ne trouve
pas non plus déconnant que ces symlinks soient regénérés dans leur ensemble à
chaque boot au niveau d'un tmpfs (en l'occurrence /run/systemd/).
Bref, a posteriori je trouve que le mécanisme est plutôt cohérent.

Je n'ai pas dit que c'était incohérant mais que c'était complexe.
Les templates, oui, pourquoi pas mais l'implémentation me semble
complexe et rébarbative.
En tous cas tu nous gratifies d'une belle explication.
--
Je ne connaîtrai rien de tes habitudes
Il se peut même que tu sois décédée
Mais j'demanderai ta main pour la couper
-- H.F. Thiéfaine, L'ascenceur de 22H43
Christophe PEREZ
Le #26500193
Le Tue, 04 Dec 2018 22:29:17 +0100, Francois Lafont a écrit :
Alors Doug713705 et Christophe... convaincus ?

Tu crois vraiment que ma réticence ne tient qu'à l'expérience que tu as
décrite dans ce fil ?
Elle ne date pas d'aujourd'hui, et des problèmes comme le tiens ne font
que me convaincre de n'y mettre les pieds que lorsque je n'aurai plus le
choix, en espérant que d'ici là, tout ait encore changé et que systemd
soit devenu obsolète avant que je ne me penche dessus.
J'avoue ne jamais avoir cherché à comprendre, mais justement, vu de loin,
ça a l'air tellement complexe et tordu (comme Grub2 par rapport à Grub)
que je ferai tout pour l'éviter, et sur ça, je peux t'assurer que mon
opinion est faite depuis un bon moment, et n'a pas bcp de chances de
changer.
Je ne remet pas en cause ni la performance, ni l'utilité. Ça doit
surement être très bien pour le pro, qui ne fait que ça toute la journée,
et qui a tout intérêt à investir les 10aines d'heures nécessaires pour
gagner du temps par la suite, mais ça ne me concerne donc pas. Je passe
déjà très largement assez de temps sur mon système (et certainement pas
juste à cause de OpenRC) pour ne surtout pas me rajouter un
investissement de temps inutile.
Ce n'est pas pour rien que je n'ai pas choisi une distribution comme
celles que vous avez quasiment tous. Je veux pouvoir profiter des
versions très récentes des softs, tout en n'ayant pas à subir des choix
(systemd) qui ne me conviendraient pas. Avec gentoo, je fais comme JE
veux et très peu de choses me sont imposées.
Convaincu ?
Publicité
Poster une réponse
Anonyme