Jak utworzyć usługę dla skryptu powłoki, aby można ją było uruchomić i zatrzymać jak demon?


22

Korzystam z CentOS 7, a moim celem jest tworzenie crona co pięć sekund, ale kiedy badałem, możemy używać crona tylko przez minutę, więc teraz tworzę plik powłoki.
hit.sh

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

ale trafiłem go ręcznie, klikając go prawym przyciskiem myszy.

Chcę utworzyć usługę dla tego pliku, aby móc go uruchomić i zatrzymać automatycznie.

Znalazłem skrypt do stworzenia usługi

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

Ale nie wiem, co napisać w metodach start lub stop Próbowałem umieścić tę samą zawartość hit.sh w, start(){}ale dało to błąd }w metodzie in stop.


Czy /usr/bin/myscriptdziała dobrze, gdy uruchamiasz go samodzielnie? Jakie są wyniki, echo $?kiedy skrypt zakończy działanie? Czy to 203?
Alexander

@Alexander /usr/bin/myscript.shdziała dobrze przy wykonywaniu przez terminal i echo$?dał mi1
codegasmer

Skrypt powinien zwrócić kod błędu 0, jeśli nie ma żadnych problemów. Kod błędu 1 oznacza błąd.
Alexander

Odpowiedzi:


30

Jeśli chcesz ponownie użyć próbki kodu, może wyglądać mniej więcej tak:

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

Oczywiście skrypt, który chcesz wykonać jako usługę, powinien przejść np. /usr/local/bin/hit.shDo powyższego kodu /etc/init.d/hitservice.

Dla każdego poziomu działania, który wymaga uruchomienia tej usługi, musisz utworzyć odpowiednie dowiązanie symboliczne. Na przykład nazwane dowiązanie symboliczne /etc/init.d/rc5.d/S99hitserviceuruchomi usługę dla poziomu uruchamiania 5. Oczywiście nadal można uruchomić i zatrzymać ją ręcznie za pomocą service hitservice start/service hitservice stop


Czy plik potrzebuje sufiksu takiego jak: hitservice.service? Następnie: Nie można uruchomić backupservice.service: Nie znaleziono urządzenia. Na CentOS 7 więc dlaczego jest to sugerowane jako odpowiedź
Spektakulatius

@ Code.IT Należy pamiętać, że OP chciał skryptu SystemV, a nie systemdskryptu, dlatego nie jest potrzebny przyrostek. Powinieneś być w stanie uruchomić stare skrypty z systemddobrze. Próbowałeś systemctl enable hitservice?
Dmitrij Grigoriew

@DmitryGrigoryev: Ten skrypt nie zapobiega wielu wystąpieniom ani nie zatrzymuje wszystkich utworzonych wielu wystąpień, plik pid przechowuje tylko proces odradzania ostatniego pid.
Luciano

27

Wierzę, że CentOS 7 i wyżej używa systemd. Jeśli tak jest w przypadku twojego systemu, spróbuj wykonać następujące czynności:

  1. Umieść polecenia skryptu, w których chcesz uruchomić /usr/bin/myscript.

  2. Pamiętaj, aby skrypt był wykonywalny za pomocą chmod +x.

  3. Utwórz następujący plik:

/etc/systemd/system/my.service

[Unit]
Description=My Script

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

[Install]
WantedBy=multi-user.target
  1. Załaduj ponownie wszystkie pliki usługi systemowej: systemctl daemon-reload

  2. Sprawdź, czy działa, uruchamiając usługę za pomocą systemctl start my.

Premia:

W celu przetestowania usystematyzowanej usługi można uruchomić środowisko tmux z dwoma panelami okien, w których górne okno monitoruje dane wyjściowe skryptu ( stdouti stderr), a dolne okno może być użyte do ponownego uruchomienia usług. Wymaga tmuxto instalacji, a następnie:

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

Następnie uruchom ponownie usługę za pomocą:

systemctl restart my

Wyjdź za tmuxpomocą, ctrl-da następnie ctrl-c.


dziękuję za odpowiedź Próbowałem rozwiązania, ale usługa się nie uruchamia. Możesz spojrzeć na moje pytanie. Dodałem szczegóły
codegasmer

Myślę, że zadziała, jeśli skrypt nie zawiedzie, ale zwróci kod błędu 0.
Alexander

4
Teraz lubię systemd!
DenisKolodin

1
Skrypt można umieścić w dowolnym miejscu, o ile usługa systemowa może uzyskać do niego dostęp i go wykonać.
Alexander

2
Nie poleciłbym Type=forking. Są szanse, że pytający będzie potrzebował, Type=simpleale generalnie rozwidlenie nie jest zalecane: 0pointer.de/public/systemd-man/… . Ludzie biorą swoje stare skrypty inicjujące i pakują je systemdtak, aby rozpocząć uruchamianie ich usługi systemd(init-script(service)). Jednak systemdzastępuje skrypty init, więc powinieneś wywoływać usługę bezpośrednio systemd, aby wyglądała systemd(service).
Centimane

3

To jest mój skrypt jako usługa:

[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


0

Zobacz projekt Bash Service Manager : https://github.com/reduardo7/bash-service-manager

Przykład realizacji

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

Przykład użycia

$ ./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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.