Как мне создать сервис для скрипта оболочки, чтобы я мог запускать и останавливать его как демон?

22

Я использую CentOS 7, и моя цель - создавать cron каждые пять секунд, но, как я исследовал, мы можем использовать cron только на минуту, поэтому сейчас я создал файл оболочки.
hit.sh

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

но я ударил его вручную, щелкнув правой кнопкой мыши.

Я хочу создать службу для этого файла, чтобы я мог запускать и останавливать его автоматически.

Я нашел скрипт для создания сервиса

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

Но я не знаю, что писать в методах start или stop. Я попытался поместить в них тот же контент hit.sh, start(){}но он дал ошибку для }метода stop.

codegasmer
источник
Работает ли /usr/bin/myscriptнормально, когда вы запускаете его самостоятельно? Каковы результаты, echo $?когда скрипт завершил выполнение? Это 203?
Александр
@ Александр /usr/bin/myscript.shотлично работает на терминале и echo$?дал мне1
codegasmer
Скрипт должен вернуть код ошибки 0, если проблем нет. Код ошибки 1 указывает на ошибку.
Александр

Ответы:

30

Если вы хотите повторно использовать пример кода, он может выглядеть примерно так:

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

Естественно, сценарий, который вы хотите выполнить как сервис, должен идти, например /usr/local/bin/hit.sh, и вышеупомянутый код должен идти /etc/init.d/hitservice.

Для каждого уровня запуска, для которого требуется эта служба, вам нужно создать соответствующую символическую ссылку. Например, именованная символическая ссылка /etc/init.d/rc5.d/S99hitserviceзапустит службу для уровня запуска 5. Конечно, вы все равно можете запустить и остановить его вручную через service hitservice start/service hitservice stop

Дмитрий Григорьев
источник
Нужен ли для файла такой суффикс, как: hitservice.service? После этого: Не удалось запустить backupservice.service: Устройство не найдено. На CentOS 7, так почему это предлагается в качестве ответа
Spektakulatius
@ Code.IT Обратите внимание, что OP хотел сценарий SystemV, а не systemdсценарий, поэтому суффикс не требуется. Вы должны быть в состоянии запускать старые скрипты systemdпросто отлично. Ты пробовал systemctl enable hitservice?
Дмитрий Григорьев
@DmitryGrigoryev: Этот сценарий не предотвращает множественные экземпляры и не останавливает все созданные множественные экземпляры, файл pid хранит только порожденный процесс последнего pid.
Лучано
27

Я считаю, что CentOS 7 и выше использует systemd. Если это так для вашей системы, попробуйте следующее:

  1. Разместите команды сценария, в которых вы хотите выполнить /usr/bin/myscript.

  2. Не забудьте сделать скрипт исполняемым с chmod +x.

  3. Создайте следующий файл:

/etc/systemd/system/my.service

[Unit]
Description=My Script

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

[Install]
WantedBy=multi-user.target
  1. Перезагрузите все служебные файлы systemd: systemctl daemon-reload

  2. Убедитесь, что он работает, запустив сервис с systemctl start my.

Бонус:

Для тестирования службы systemd можно запустить среду tmux с двумя оконными панелями, где верхнее окно контролирует вывод скрипта ( stdoutи stderr), а нижнее окно можно использовать для перезапуска сервисов. Это требует tmuxустановки, а затем просто:

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

Затем перезапустите сервис с помощью:

systemctl restart my

Выход tmuxс ctrl-dи затем ctrl-c.

Александр
источник
спасибо за ответ Я попробовал ваше решение, но служба не
запускается. Можете
Я думаю, что это будет работать, если ваш скрипт не даст сбой, но вернет код ошибки 0.
Александр
4
Теперь я люблю systemd!
ДенисКолодин
1
Сценарий может быть размещен где угодно, если служба systemd может получить к нему доступ и выполнить его.
Александр
2
Я бы не рекомендовал Type=forking. Скорее всего, это понадобится запрашивающему,Type=simple но в целом разветвление не рекомендуется: 0pointer.de/public/systemd-man/… . Люди берут свои старые сценарии инициализации и оборачивают их, systemdчтобы запустить их службу systemd(init-script(service)). Однако systemdэто замена для сценариев инициализации, поэтому вы должны вызывать службу напрямую, systemdчтобы она выглядела так systemd(service).
Сентиман
3

Это мой скрипт как сервис:

[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
десятичный
источник
2

Посмотрите на Fpm. Это инструмент, который создаст сценарии инициализации для вас. Работает на многих платформах (systemd, upstart, ect ..)

https://github.com/jordansissel/fpm

spuder
источник
0

См. Проект Bash Service Manager : https://github.com/reduardo7/bash-service-manager.

Пример реализации

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

Пример использования

$ ./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
Эдуардо Куомо
источник