¿Cómo creo un servicio para un script de shell para que pueda iniciarlo y detenerlo como un demonio?

22

Estoy usando CentOS 7, mi objetivo es crear un cron por cada cinco segundos, pero mientras investigaba, podemos usar cron solo por un minuto, así que lo que estoy haciendo ahora es crear un archivo shell.
hit.sh

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

pero lo golpeé manualmente haciendo clic derecho sobre él.

Lo que quiero es crear un servicio para ese archivo para que pueda iniciarlo y detenerlo automáticamente.

Encontré el script para crear un servicio

#!/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 

Pero no sé qué escribir en los métodos de inicio o detención Intenté colocar el mismo contenido de hit.sh start(){}pero me dio un error }en el método de detención.

codegasmer
fuente
¿ /usr/bin/myscriptFunciona bien cuando lo ejecuta solo? ¿Cuál es el resultado de echo $?cuando el script ha completado una ejecución? ¿Es 203?
Alexander
@Alexander /usr/bin/myscript.shfunciona bien en la ejecución a través del terminal y echo$?me dio1
codegasmer
El script debe devolver el código de error 0 si no hay problemas. El código de error 1 indica un error.
Alexander

Respuestas:

30

Si desea reutilizar su muestra de código, podría verse así:

#!/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 

Naturalmente, la secuencia de comandos que desea ejecutar como servicio debe ir, por ejemplo /usr/local/bin/hit.sh, y el código anterior debe ir a /etc/init.d/hitservice.

Para cada nivel de ejecución que necesite ejecutar este servicio, deberá crear un enlace simbólico respectivo. Por ejemplo, un enlace simbólico llamado /etc/init.d/rc5.d/S99hitserviceiniciará el servicio para el nivel de ejecución 5. Por supuesto, aún puede iniciarlo y detenerlo manualmente a través de service hitservice start/service hitservice stop

Dmitry Grigoryev
fuente
¿Necesita el archivo un sufijo como: hitservice.service? Después de esto: Error al iniciar backupservice.service: Unidad no encontrada. En CentOS 7, ¿por qué se sugiere esto como respuesta
Spektakulatius
@ Code.IT Tenga en cuenta que el OP quería un script SystemV, no un systemdscript, por lo tanto, no se necesita sufijo. Sin systemdembargo, deberías poder ejecutar scripts antiguos con muy bien. ¿Lo has intentado systemctl enable hitservice?
Dmitry Grigoryev
@DmitryGrigoryev: este script no evita múltiples instancias ni detiene todas las instancias múltiples creadas, el archivo pid solo almacena el último proceso generado por el último pid.
Luciano
27

Creo que CentOS 7 y superior usa systemd. Si ese es el caso de su sistema, intente lo siguiente:

  1. Coloque los comandos de script en los que desea ejecutar /usr/bin/myscript.

  2. Recuerde hacer que el script sea ejecutable con chmod +x.

  3. Crea el siguiente archivo:

/etc/systemd/system/my.service

[Unit]
Description=My Script

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

[Install]
WantedBy=multi-user.target
  1. Vuelva a cargar todos los archivos de servicio systemd: systemctl daemon-reload

  2. Compruebe que está funcionando iniciando el servicio con systemctl start my.

Prima:

Para probar el servicio systemd, es posible iniciar un entorno tmux con dos paneles de ventanas, donde la ventana superior monitorea la salida del script ( stdouty stderr) y la ventana inferior se puede usar para reiniciar los servicios. Esto requiere tmuxser instalado, luego simplemente:

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

Luego reinicie el servicio con:

systemctl restart my

Salir tmuxcon ctrl-dy luego ctrl-c.

Alejandro
fuente
gracias por responder. Intenté su solución, pero el servicio no se está iniciando. ¿Pueden ver mi pregunta
Agregué
Creo que funcionará si su script no falla, pero devuelve el código de error 0.
Alexander
44
Ahora me gusta systemd!
DenisKolodin
1
El script se puede colocar en cualquier lugar, siempre que el servicio systemd pueda acceder y ejecutarlo.
Alexander
2
No recomendaría Type=forking. Es probable que el autor de la pregunta necesite, Type=simplepero en general no se recomienda bifurcar : 0pointer.de/public/systemd-man/… . La gente ha estado tomando sus viejos guiones de inicio y envolviéndolos systemdpara que se inicie su servicio systemd(init-script(service)). Sin embargo, systemdes un reemplazo para los scripts de inicio, por lo que debe llamar al servicio directamente systemdpara que se vea así systemd(service).
Centimane
3

Este es mi script como servicio:

[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
decimal
fuente
0

Vea el proyecto Bash Service Manager : https://github.com/reduardo7/bash-service-manager

Ejemplo de implementación

#!/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

Ejemplo de uso

$ ./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
fuente