Le service Systemd s'exécute sans quitter

30

J'ai créé mon propre service pour jekyll et quand je démarre le service, il semble qu'il ne fonctionne pas comme un processus d'arrière-plan car je suis obligé de ctrl+ en csortir. Il reste juste au premier plan à cause de la --watch. Je ne sais pas comment le contourner et faire en sorte qu'il fonctionne en arrière-plan. Des pensées?

# /etc/systemd/system/jekyll-blog.service

[Unit]
Description=Start blog jekyll

[Service]
Type=forking
WorkingDirectory=/home/blog
ExecStart=/usr/local/bin/jekyll build --watch --incremental -s /home/blog -d /var/www/html/blog &
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
User=root
Group=root

[Install]
WantedBy=multi-user.target
madmanali93
la source
systemd démarrera votre processus et s'attendra à ce qu'il en charge un autre si vous l'utilisez Type=forking. De plus, il ne fonctionnera pas execStartcomme une extension du shell, de sorte qu'à &la fin il ne sera jamais compris comme un drapeau d'arrière-plan.
grochmal
mon mauvais le & me testait-il. Le type devrait-il donc être simple?
madmanali93
2
Si je ne me trompe pas, jekyll est un truc de type rails, c'est-à-dire un petit serveur weby en rubis. Alors oui, ce Type=simpleserait approprié. De plus, ce n'est pas le genre d'application que j'exécuterais en tant que root, du moins pas sur une machine Internet (ce qui n'est peut-être pas votre cas).
grochmal
Merci oui simple travaillé. La commande this génère également le html statique pour Apache afin que jekyll ne serve pas sur le serveur. Je pense que cela devrait être bien s'il fonctionne en tant que root. Je n'étais pas sûr d'en débattre.
madmanali93
Oh OK, c'est ce qui --incrementalfait :). Oui, je ne vois aucun problème de sécurité dans la régénération des fichiers en tant que root. Bien sûr, étant donné que ces fichiers ne sont pas fournis par l'utilisateur.
grochmal

Réponses:

54

Systemd est capable de gérer différents types de services différents, en particulier l'un des suivants

  • simple - Un processus de longue durée qui ne se déroule pas en arrière-plan et reste attaché à la coque.
  • forking - Un démon typique qui se fourche en le détachant du processus qui l'a exécuté, en se mettant en arrière-plan efficacement.
  • oneshot - Un processus de courte durée qui devrait se terminer.
  • dbus - Comme simple, mais la notification de la fin du démarrage des processus est envoyée via dbus.
  • notify - Comme simple, mais la notification de la fin du démarrage des processus est envoyée via inotify.
  • idle - Comme simple, mais le binaire est démarré après l'envoi du travail.

Dans votre cas, vous avez choisi Type=forkingce qui signifie que systemd attend que le processus se termine lui-même et que le processus parent se termine, ce qui indique que le processus a démarré avec succès. Cependant, votre processus ne fait pas cela - il reste au premier plan et systemctl startse bloque donc indéfiniment ou jusqu'à ce que le processus se bloque.

Au lieu de cela, vous le souhaitez Type=simple, ce qui est la valeur par défaut afin que vous puissiez supprimer complètement la ligne pour obtenir le même effet. Dans ce mode, systemd n'attend pas la fin du démarrage des processus (car il n'a aucun moyen de savoir quand cela s'est produit) et continue donc à exécuter immédiatement les services dépendants. Dans votre cas, il n'y en a pas, donc cela n'a pas d'importance.

Une petite note sur la sécurité:

Vous exécutez le service en tant que root, cela est déconseillé car il est moins sécurisé que de l'exécuter en tant qu'utilisateur non privilégié. La raison en est que s'il y a une vulnérabilité dans jekyll qui permet en quelque sorte l'exécution de commandes (éventuellement via le code qu'il analyse), l'attaquant n'a rien d'autre à faire pour posséder complètement votre système. Si, d'autre part, il est exécuté en tant qu'utilisateur non privilégié, l'attaquant ne peut faire autant de dégâts que cet utilisateur et doit maintenant tenter d'obtenir des privilèges root pour posséder entièrement votre système. Cela ajoute simplement une couche supplémentaire aux attaquants.

Vous pouvez simplement l'exécuter en tant que même utilisateur qui exécute votre serveur Web, mais cela vous laisse ouvert à une autre attaque potentielle. S'il y a une vulnérabilité dans votre serveur Web qui permet à l'utilisateur de manipuler des fichiers sur votre système, il peut modifier les fichiers html générés, ou pire les fichiers source et amener votre serveur à servir tout ce qu'il veut. Cependant, si les fichiers générés et les fichiers source ne sont lisibles que par le serveur Web et inscriptibles par un autre utilisateur non privilégié, ils ne pourront pas, aussi facilement, les modifier en attaquant le serveur Web.

Cependant, si vous servez simplement des fichiers statiques de ce serveur et que vous maintenez le serveur à jour, ces attaques sont très peu probables - mais toujours possibles. Il est de votre responsabilité de peser les risques par rapport aux frais généraux liés à sa configuration en fonction de la gravité de votre système, mais ces deux conseils sont très simples à configurer et pratiquement sans frais de maintenance.

Michael Daffin
la source
0

En plus de la solution de @ Michael Daffin , vous pouvez également utiliser l' outil daemonize pour réaliser l'utilisation de forkingcomme indiqué dans l'exemple suivant.

Étant donné un petit script shell que je veux démonifier et que je veux contrôler sur systemd, je l'ai enregistré sous /home/pi/testscript.sh:

#!/bin/bash

while true;
do
    sleep 1
    echo -n "."
done

Si vous ne l'avez pas encore, installez daemonize, comme ceci:

sudo apt install daemonize

Créez maintenant le fichier de définition du service de fichiers:

sudo vi /etc/systemd/system/testomat.service
# It is not recommended to modify this file in-place, because it will
# be overwritten during package upgrades. If you want to add further
# options or overwrite existing ones then use
# $ systemctl edit testomat.service
# See "man systemd.service" for details.

# copied from https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service and modified by Michael 

[Unit]
Description=Test service
After=network.target

[Service]
ExecStart=daemonize -p /run/testomat/testomat.pid -o /home/pi/testscript.log /home/pi/testscript.sh
TimeoutSec=1200

# Make sure the config directory is readable by the service user
PermissionsStartOnly=true

# Process management
####################
Type=forking
PIDFile=/run/testomat/testomat.pid
Restart=on-failure
GuessMainPID = true

# Directory creation and permissions
####################################

# Run as pi:pi
User=pi
Group=pi

# /run/testomat
RuntimeDirectory=testomat
RuntimeDirectoryMode=0710

# /var/lib/testomat
StateDirectory=testomat
StateDirectoryMode=0710

# Hardening measures
####################

# Provide a private /tmp and /var/tmp.
PrivateTmp=true

# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full

# Allow access to /home, /root and /run/user
# Chosing "false" is actually no hardening, this is just to demonstrate the usage of a service. Well, I could have omitted it. True. :)
ProtectHome=false

# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true

# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true

# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true

[Install]
WantedBy=multi-user.target

Le service nouvellement créé doit être annoncé à systemd:

systemctl daemon-reload

Vous pouvez maintenant démarrer le service et les fourches de script. Comme prévu, le démarrage du service revient immédiatement au shell. Le résultat est évident:

$ tail -f testscript.log 
.....................

Michael
la source
Quel est l'avantage d'utiliser daemonize+ Type=forkingplutôt que de Type=simplelaisser systemd se charger du démarrage du service? Type=forkingest une sorte de paramètre de compatibilité dans systemd pour prendre en charge les programmes hérités qui sont écrits sur fork.
Johan Myréen
Je pense que c'est une solution équivalente; Je voulais juste fournir à l'OP une solution alternative et lui faire prendre conscience de cet outil que j'ai déjà utilisé dans /etc/init.d car la question est aussi un peu sur la façon de démoniser un processus.
Michael