TL;DR : indique à systemd l'ensemble des dépendances d'un service qu'il doit lancer, y compris les partitions qui doivent être montées au préalable. Surtout si le binaire qu'une unit systemd doit lancer est stocké sur une autre partition que la partition racine. Sans ça, tu t'exposes à un comportement aléatoire (unit démarre, unit démarre pas, unit démarre, etc.) lors du démarrage de la machine.
Suite au déplacement sans interruption raté d'une machine virtuelle au sein d'une grappe d'hyperviseurs (migration à chaud) et à son crash, je démarre ladite machine virtuelle Red Hat 7.9. Il s'agit d'une machine de test donc je suis détendu, mais après 30 minutes, ma supervision m'indique toujours que les bases de données Oracle ne sont pas ouvertes. En effet, systemctl status oracledb
indique « code=exited », « status=203/EXEC ». Pas d'info complémentaire intéressante dans l'extrait de journal également retourné par la commande.
Une recherche dans la doc' officielle de systemd me met sur la piste que le programme à lancer est inaccessible ou non-exécutable. Pourtant, un systemctl start oracledb
fonctionne. Donc le binaire est OK en temps normal… mais pas au démarrage du serveur ?
Regardons ce que lance l'unit avec systemctl show oracledb | grep -i execstart
. (On peut aussi faire systemctl show oracledb -p ExecStart
. Attention à bien respecter les majuscules, sensibilité à la case, tout ça.) Il n'y a pas de programme lancé au préalable (« ExecStartPre ») qui pourrait lui aussi foirer. « ExecStart=/appli/oracle/product/19c/db/bin/dbstart ». Hum… Sur ce serveur, /appli est un volume logique LVM distinct de celui de la racine. Il est référencé dans fstab
et il est monté automatiquement au démarrage. Est-il possible que systemd tente de démarrer Oracle avant le montage de /appli ?
Un détail dans la définition de l'unit oracledb conforte cette hypothèse : « After=opt-oracle.mount ». Cette unit est explicitement conçue pour être démarrée après que /opt/oracle ait été montée. Mais, sur ce serveur, Oracle est stocké dans /appli/oracle. Oubli d'adapter l'unit systemd ?
Une lecture de /var/log/boot.log
valide définitivemnt cette hypothèse : systemd a d'abord tenté de lancer le service oracledb avant de monter /appli.
A posteriori, je pense que c'est plus subtil que cela. La machine virtuelle crashe lors de sa migration à chaud. Au démarrage suivant, fsck
est lancé. Il vérifie d'abord /, puis les autres partitions, car, dans fstab
, elles ont la valeur 2 à l'attribut « fs_passno » (6e champ). En attendant, en l'absence d'information sur la dépendance, systemd lance le service oracledb. Cela explique pourquoi le démarrage d'Oracle au boot peut être effectif ou non : race condition.
Pour régler le problème, il faut conditionner le lancement du service oracledb au montage de /appli. L'unit est stockée dans /usr/lib/systemd/system/oracledb.service
. Normalement, ces units sont censées être déposées par des paquets, des installeurs, etc., et ne pas être modifiées par l'administrateur. Dans le cas présent, mes collègues ont déjà trifouillé dedans, donc je continue. Avec n'importe quel éditeur de texte, je remplace la ligne After=opt-oracle.mount
par After=appli.mount
.
Si j'avais voulu faire propre, j'aurai fait systemctl edit oracledb
. Cela aurait créé une surcharge de l'unit sous la forme d'un fichier stocké dans /etc/systemd/system/oracledb.service.d/override.conf
. Dedans, j'aurai mis le contenu suivant :
[Unit]
After=appli.mount
J'ai redémarré trois fois ce serveur (afin d'avoir des stats fiables) : 0 échec du service oracledb. \o/ Dans le journal, je vois que l'unit' oracledb est lancée immédiatement après le montage de /appli.
N'étant pas le référent de ce serveur, j'en parle à celui-ci, afin, notamment, qu'il valide ma modif' et qu'il l'applique en prod'. Il est étonné : c'est la même unit systemd pour lancer Oracle sur tous ses serveurs et ça juste marche ailleurs. On regarde ensemble sur un autre serveur. Ce n'est pas la même unit. Celle-ci contient « After=network.target ».
Là encore, c'est un coup de chance que cela fonctionne : on peut raisonnablement espérer que le réseau sera monté après les partitions locales. Donc si l'on demande à systemd de lancer Oracle après le réseau, on peut légitimement s'attendre à ce que ça fonctionne. Mais c'est bancal… et implicite (les pré-requis d'un service ne sont pas clairement énoncés).
Bref, prends soin des dépendances de tes units systemd.