Systèmed : dépendances de démarrage et d’arrêt
Le problème
Un serveur Debian (jessie, systemd 215) exécute une application web qui nécessite un partage samba (cifs) via openvpn (IPv6). Avec le manuel de configuration naïve, le démarrage et l’arrêt fonctionnent bien, mais le redémarrage ne fonctionne pas correctement.
Configuration naïve :
- Debian Packages:
apache2
cifs-utils
openvpn
- cifs mount in
/etc/fstab
konfiguriert - openvpn Konfiguration in
/etc/openvpn/client.conf
Si vous démarrez tout individuellement, cela fonctionne parfaitement :
systemctl start openvpn@client.service
mount /var/www/data
systemctl start apache2.service
L’arrêt est également facile à effectuer manuellement :
systemctl stop apache2.service
umount /var/www/data
systemctl stop openvpn@client.service
Mais un redémarrage ne démarre pas.…
- Au démarrage, la monture est essayée avant que le VPN ne soit disponible et échoue bien sûr.
- Apache s’exécute, mais l’application web a un problème d’accès aux fichiers dans la monture cifs.
… ni ne s’éteint :
- Le VPN est interrompu avant que le démontage ne soit terminé.
- Le système reste en attente pendant 2 minutes jusqu’à ce que le délai d’expiration du démontage soit expiré. C’est très ennuyeux.
Approche #1
La solution ne devrait pas être trop difficile avec[systemd units] (https://www.freedesktop.org/software/systemd/man/systemd.unit.html).
Comme /etc/fstab
ne peut pas être utilisé pour formuler explicitement des dépendances, un fichier unité séparé est créé pour le montage. Nous commençons par le fichier unitaire généré automatiquement :
systemctl cat var-www-www-data.mount > /etc/systemd/system/system/system/var-www-data.mount`
Et supprimez les entrées SourcePath' et
Documentation’, de sorte qu’il ne reste que le minimum :
#/etc/systemd/system/var-www-data.mount
[Unit]
Before=remote-fs.target
[Mount]
What=//v6.smb.example.com/WwwDataShare
Where=/var/www/data
Type=cifs
Options=ro,guest,iocharset=utf8
Ensuite, l’entrée est supprimée de /etc/fstab
et l’unité est activée avec :
systemctl enable var-www-data.mount ; systemctl daemon-reload`
Il est important de noter qu’il est possible d’utiliser les données d’une manière simple et rapide et d’une manière efficace.
Maintenant nous pouvons formuler la dépendance à openvpn :
#/etc/systemd/system/var-www-data.mount
[Unit]
Before=remote-fs.target
After=openvpn@client.service
Requires=openvpn@client.service
systemctl daemon-reload
Ça ne marche toujours pas, j’en ai peur. Après diverses analyses avec `journalctl -f’, il est apparu clairement que
- l’unité openvpn prétend être “prête” au démarrage, bien que les routes IPv6 ne soient pas encore correctement définies.
- l’umount de /var/www/data prétend être prêt quand il s’arrête, bien qu’il y ait toujours une communication réseau en attente.
Solution
Tout d’abord, vous avez besoin d’un script qui vérifie les conditions préalables au démarrage (ping') et à l'arrêt (
umount’) :
/etc/openvpn/checks_updown
#!/bin/bash
LOGGER_RED="systemd-cat -t $0 -p err"
LOGGER_BOLD="systemd-cat -t $0 -p notice"
LOGGER_NORM="systemd-cat -t $0 -p info"
case "$1" in
ping)
while true
do
if ping6 -q -c 3 v6.smb.example.com > /dev/null 2>&1
then
echo ping6 ok | $LOGGER_BOLD
exit 0
else
echo "." | $LOGGER_NORM
sleep 4
fi
done
;;
umount)
while true
do
if mount | grep "//v6.smb.example.com/" >/dev/null 2>&1
then
echo ";" | $LOGGER_NORM
sleep 4
else
echo umount ok | $LOGGER_BOLD
exit 0
fi
done
;;
*)
echo "invalid call: $1" | tee | $LOGGER_RED
exit 1
;;
esac
Pour ce script, nous construisons notre propre unité :
# /etc/systemd/system/vpnbarrier.service
[Unit]
Requires=openvpn@client.service
After=openvpn@client.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/etc/openvpn/checks_updown ping
ExecStop=/etc/openvpn/checks_updown umount
[Install]
RequiredBy=var-www-data.mount
Le RemainAfterExit=yes' provoque (avec
oneshot’) que ExecStop
n’est pas exécuté tant que cette unité n’est pas arrêtée. Sans ce réglage, ExecStop
serait exécuté immédiatement après ExecStart
, c’est-à-dire au démarrage.
Étendre les dépendances dans l’unité `mount’ :
# /etc/systemd/system/var-www-data.mount
[Unit]
Before=apache2.service
Requires=vpnbarrier.service
After=vpnbarrier.service
[Mount]
...
[Install]
RequiredBy=apache2.service
systemctl enable vpnbarrier.service; systemctl daemon-reload
C’est seulement maintenant que tout fonctionne comme il se doit :
systemctl stop openvpn@client.service
: D’abord apache2 est arrêté, puis/var/www/data
est déconnecté et seulement ensuite le VPN est arrêté.- systemctl start apache2.service` : D’abord le VPN est lancé, puis le cifs-mount et enfin apache2.
- Un redémarrage prend moins de 20 secondes.
Remarques
- La documentation de systemd est assez bonne, par exemple àdigitalocean. Cependant, l’accent est surtout mis sur la montée en puissance et il est difficile de trouver quoi que ce soit à descendre en voiture.
- Une[discussion quelque peu différente] (https://github.com/systemd/systemd/issues/2647) a montré qu’il y en a d’autres qui manquent de quelque chose.
*L’intuition la plus importante : **Utilisez toujoursRequires' et
After’, c’est le seul moyen d’obtenir un contrôle sur l’arrêt. - Cause racine : Le problème est-il un problème générique du système ou un bogue dans le paquet openvpn ? Et à l’umount de la C.I.F.S. ?
- Le problème pourrait-il être résolu un peu plus élégamment, par exemple en se passant d’une unité séparée
vpnbarrier.service' et en implémentant le contrôle "ping" ou "umount" par des entrées dans les répertoires
*.conf.d` ? - De temps en temps, il ne suffisait pas de faire un `systemd daemon-reload’, seulement après un redémarrage, tout fonctionnait comme prévu.