Comment créer un service pour un script shell afin de pouvoir le démarrer et l'arrêter comme un démon?

22

J'utilise CentOS 7, mon objectif est de créer un cron toutes les cinq secondes, mais pendant mes recherches, nous ne pouvons utiliser cron que pendant une minute, donc ce que je fais maintenant, c'est que j'ai créé un fichier shell.
hit.sh

while sleep 5; do curl http://localhost/test.php; done

mais je l'ai frappé manuellement en faisant un clic droit dessus.

Ce que je veux, c'est créer un service pour ce fichier afin que je puisse le démarrer et l'arrêter automatiquement.

J'ai trouvé le script pour créer un service

#!/bin/bash
# chkconfig: 2345 20 80
# description: Description comes here....

# Source function library.
. /etc/init.d/functions

start() {
    # code to start app comes here 
    # example: daemon program_name &
}

stop() {
    # code to stop app comes here 
    # example: killproc program_name
}

case "$1" in 
    start)
       start
       ;;
    stop)
       stop
       ;;
    restart)
       stop
       start
       ;;
    status)
       # code to check status of app comes here 
       # example: status program_name
       ;;
    *)
       echo "Usage: $0 {start|stop|status|restart}"
esac

exit 0 

Mais je ne sais pas quoi écrire dans les méthodes start ou stop J'ai essayé de placer le même contenu de hit.sh dans start(){}mais cela a donné une erreur pour la }méthode in stop.

codegasmer
la source
Fonctionne-t-il /usr/bin/myscriptbien lorsque vous l'exécutez seul? Quelle est la sortie echo $?lorsque le script a terminé une exécution? Est-ce 203?
Alexander
@Alexander /usr/bin/myscript.shfonctionne très bien sur l'exécution via le terminal et echo$?m'a donné1
codegasmer
Le script doit renvoyer le code d'erreur 0 s'il n'y a aucun problème. Le code d'erreur 1 indique une erreur.
Alexander

Réponses:

30

Si vous souhaitez réutiliser votre exemple de code, il pourrait ressembler à:

#!/bin/bash

case "$1" in 
start)
   /path/to/hit.sh &
   echo $!>/var/run/hit.pid
   ;;
stop)
   kill `cat /var/run/hit.pid`
   rm /var/run/hit.pid
   ;;
restart)
   $0 stop
   $0 start
   ;;
status)
   if [ -e /var/run/hit.pid ]; then
      echo hit.sh is running, pid=`cat /var/run/hit.pid`
   else
      echo hit.sh is NOT running
      exit 1
   fi
   ;;
*)
   echo "Usage: $0 {start|stop|status|restart}"
esac

exit 0 

Naturellement, le script que vous souhaitez exécuter en tant que service doit aller par exemple /usr/local/bin/hit.sh, et le code ci-dessus devrait aller /etc/init.d/hitservice.

Pour chaque niveau d'exécution nécessitant l'exécution de ce service, vous devrez créer un lien symbolique respectif. Par exemple, un lien symbolique nommé /etc/init.d/rc5.d/S99hitservicedémarrera le service pour le niveau d'exécution 5. Bien sûr, vous pouvez toujours le démarrer et l'arrêter manuellement via service hitservice start/service hitservice stop

Dmitry Grigoryev
la source
Le fichier a-t-il besoin d'un suffixe comme: hitservice.service? Après cela: échec du démarrage de backupservice.service: unité non trouvée. Sur CentOS 7 alors pourquoi est-ce suggéré comme réponse
Spektakulatius
@ Code.IT Notez que l'OP voulait un script SystemV, pas un systemdscript, donc aucun suffixe n'est nécessaire. Vous devriez être capable d'exécuter d'anciens scripts systemdtrès bien. As-tu essayé systemctl enable hitservice?
Dmitry Grigoryev
@DmitryGrigoryev: Ce script n'empêche pas plusieurs instances ni n'arrête toutes les instances multiples créées, le fichier pid ne stocke que le processus généré du dernier pid.
Luciano
27

Je crois que CentOS 7 et supérieur utilise systemd. Si tel est le cas pour votre système, essayez ce qui suit:

  1. Placez les commandes de script que vous souhaitez exécuter /usr/bin/myscript.

  2. N'oubliez pas de rendre le script exécutable avec chmod +x.

  3. Créez le fichier suivant:

/etc/systemd/system/my.service

[Unit]
Description=My Script

[Service]
Type=forking
ExecStart=/usr/bin/myscript

[Install]
WantedBy=multi-user.target
  1. Rechargez tous les fichiers de service systemd: systemctl daemon-reload

  2. Vérifiez qu'il fonctionne en démarrant le service avec systemctl start my.

Prime:

Pour tester le service systemd, il est possible de lancer un environnement tmux avec deux volets de fenêtre, où la fenêtre supérieure surveille la sortie du script ( stdoutet stderr) et la fenêtre inférieure peut être utilisée pour redémarrer les services. Cela nécessite tmuxd'être installé, puis simplement:

tmux new-session \; select-layout even-horizontal \; split-window -v journalctl -o cat --since=@$(date +%s) -f -u my \; rotate-window \; set -g status-bg colour0 \; set -g status-fg colour9 \; attach

Redémarrez ensuite le service avec:

systemctl restart my

Quittez tmuxavec ctrl-dpuis ctrl-c.

Alexandre
la source
merci d'avoir répondu J'ai essayé votre solution mais le service ne démarre pas pouvez-vous regarder ma question j'ai ajouté les détails
codegasmer
Je pense que cela fonctionnera si votre script n'échoue pas, mais renvoie le code d'erreur 0.
Alexander
4
Maintenant j'aime systemd!
DenisKolodin
1
Le script peut être placé n'importe où, tant que le service systemd peut y accéder et l'exécuter.
Alexander
2
Je ne recommanderais pas Type=forking. Il y a de fortes chances que le demandeur ait besoin Type=simplemais en général, le forking n'est pas recommandé: 0pointer.de/public/systemd-man/… . Les gens ont pris leurs anciens scripts d'initialisation et les ont enveloppés systemdpour que le démarrage de leur service se poursuive systemd(init-script(service)). Cependant, il systemdremplace les scripts init, vous devez donc appeler le service directement avec systemdpour qu'il ressemble systemd(service).
Centimane
3

Voici mon script en tant que service:

[Unit]
Description=To change In test buffer
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/test.sh
TimeoutStartSec=0

[Install]
WantedBy=default.target
décimal
la source
2

Jetez un oeil à fpm. C'est un outil qui créera pour vous des scripts d'initialisation. Fonctionne sur de nombreuses plateformes (systemd, upstart, ect ..)

https://github.com/jordansissel/fpm

spuder
la source
1

Voir le projet Bash Service Manager : https://github.com/reduardo7/bash-service-manager

Exemple d'implémentation

#!/usr/bin/env bash

export PID_FILE_PATH="/tmp/my-service.pid"
export LOG_FILE_PATH="/tmp/my-service.log"
export LOG_ERROR_FILE_PATH="/tmp/my-service.error.log"

. ./services.sh

run-script() {
  local action="$1" # Action

  while true; do
    echo "@@@ Running action '${action}'"
    echo foo
    echo bar >&2

    [ "$action" = "run" ] && return 0
    sleep 5
    [ "$action" = "debug" ] && exit 25
  done
}

before-start() {
  local action="$1" # Action

  echo "* Starting with $action"
}

after-finish() {
  local action="$1" # Action
  local serviceExitCode=$2 # Service exit code

  echo "* Finish with $action. Exit code: $serviceExitCode"
}

action="$1"
serviceName="Example Service"

serviceMenu "$action" "$serviceName" run-script "$workDir" before-start after-finish

Exemple d'utilisation

$ ./example-service
# Actions: [start|stop|restart|status|run|debug|tail(-[log|error])]

$ ./example-service start
# Starting Example Service service...

$ ./example-service status
# Serive Example Service is runnig with PID 5599

$ ./example-service stop
# Stopping Example Service...

$ ./example-service status
# Service Example Service is not running
Eduardo Cuomo
la source