Как мне демонизировать произвольный скрипт в unix? - PullRequest
91 голосов
/ 08 февраля 2009

Мне нужен демонизатор, который может превратить произвольный общий сценарий или команду в демон .

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

  1. У меня есть скрипт, который должен работать вечно. Если он когда-либо умрет (или перезагрузится), перезапустите его. Не допускайте одновременного запуска двух копий (определите, запущена ли уже копия и не запускайте ее в этом случае).

  2. У меня есть простой скрипт или команда командной строки, которую я хотел бы продолжать выполнять многократно вечно (с небольшой паузой между запусками). Опять же, не позволяйте одновременно запускать две копии скрипта.

Конечно, тривиально написать цикл while (true) вокруг сценария в случае 2, а затем применить решение для случая 1, но более общее решение просто решит случай 2 напрямую, поскольку это применимо к сценарию в также случай 1 (вы можете просто захотеть сделать более короткую паузу или вообще не делать паузу, если скрипт не предназначен для того, чтобы когда-либо умереть (конечно, если скрипт действительно действительно никогда не умрет, тогда пауза на самом деле не имеет значения)).

Обратите внимание, что решение не должно включать, скажем, добавление кода блокировки файла или запись PID в существующие сценарии.

Точнее, я бы хотел программу "daemonize", которую я мог бы запустить как

% daemonize myscript arg1 arg2

или, например,

% daemonize 'echo `date` >> /tmp/times.txt'

, который будет содержать растущий список дат, добавленный в times.txt. (Обратите внимание, что если аргумент (ы) для daemonize является сценарием, который выполняется вечно, как в случае 1 выше, то daemonize все равно будет делать правильные вещи, перезапуская его при необходимости.) Затем я мог бы поместить команду, как указано выше, в мой .login и / или cron это ежечасно или ежечасно (в зависимости от того, насколько я волновался, что он внезапно умрет).

NB. Сценарий daemonize должен будет помнить командную строку, которую он демонизирует, чтобы при повторной демонизации той же командной строки он не запускал вторую копию.

Кроме того, решение в идеале должно работать как на OS X, так и на Linux, но решения для одного или другого приветствуются.

РЕДАКТИРОВАТЬ: Это нормально, если вам нужно вызвать его с sudo daemonize myscript myargs.

(Если я думаю об этом все неправильно или есть быстрые и грязные частичные решения, я бы тоже хотел это услышать.)


PS: В случае, если это полезно, вот аналогичный вопрос, специфичный для python.

И этот ответ на аналогичный вопрос имеет то, что представляется полезным для быстрой и грязной демонизации произвольного сценария:

Ответы [ 12 ]

88 голосов
/ 11 марта 2010

Вы можете демонизировать любой исполняемый файл в Unix, используя nohup и оператор &:

nohup yourScript.sh script args&

Команда nohup позволяет вам завершить сеанс оболочки, не убивая ваш скрипт, в то время как & помещает ваш скрипт в фоновый режим, чтобы вы получили приглашение оболочки продолжить ваш сеанс. Единственная незначительная проблема с этим - стандартный вывод и стандартная ошибка, и они отправляются на ./nohup.out, поэтому, если вы запустите несколько сценариев в этом поместье, их выходные данные будут переплетены. Лучшая команда будет:

nohup yourScript.sh script args >script.out 2>script.error&

Это отправит стандарт в файл по вашему выбору, а стандартную ошибку - в другой файл по вашему выбору. Если вы хотите использовать только один файл как для стандартной ошибки, так и для стандартной ошибки, вы можете использовать это:

nohup yourScript.sh script args >script.out 2>&1 &

2> & 1 указывает оболочке перенаправлять стандартную ошибку (дескриптор файла 2) в тот же файл, что и стандартный вывод (дескриптор файла 1).

Чтобы запустить команду только один раз и перезапустить ее, если она умрет, вы можете использовать этот скрипт:

#!/bin/bash

if [[ $# < 1 ]]; then
    echo "Name of pid file not given."
    exit
fi

# Get the pid file's name.
PIDFILE=$1
shift

if [[ $# < 1 ]]; then
    echo "No command given."
    exit
fi

echo "Checking pid in file $PIDFILE."

#Check to see if process running.
PID=$(cat $PIDFILE 2>/dev/null)
if [[ $? = 0 ]]; then
    ps -p $PID >/dev/null 2>&1
    if [[ $? = 0 ]]; then
        echo "Command $1 already running."
        exit
    fi
fi

# Write our pid to file.
echo $$ >$PIDFILE

# Get command.
COMMAND=$1
shift

# Run command until we're killed.
while true; do
    $COMMAND "$@"
    sleep 10 # if command dies immediately, don't go into un-ctrl-c-able loop
done

Первый аргумент - это имя файла pid, который нужно использовать. Второй аргумент - это команда. Все остальные аргументы являются аргументами команды.

Если вы назовете этот скрипт restart.sh, вы бы назвали его так:

nohup restart.sh pidFileName yourScript.sh script args >script.out 2>&1 &
32 голосов
/ 18 марта 2010

Я прошу прощения за длинный ответ (пожалуйста, смотрите комментарии о том, как мой ответ прибивает спецификацию). Я пытаюсь быть всеобъемлющим, так что вы как можно лучше держите ногу. : -)

Если вы можете устанавливать программы (иметь root-доступ) и готовы выполнить однократную работу по настройке сценария для выполнения демона (т. Е. Более сложным, чем просто указание аргументов командной строки для запуска на командной строки, но это нужно сделать только один раз для каждой службы), у меня есть более надежный способ.

Используется daemontools . В оставшейся части статьи описывается, как настроить службы с помощью daemontools.

Начальная настройка

  1. Следуйте инструкциям в Как установить daemontools . Некоторые дистрибутивы (например, Debian, Ubuntu) уже имеют пакеты для него, так что просто используйте это.
  2. Создайте каталог с именем /service. Установщик должен был это сделать, но просто проверить или установить вручную. Если вам не нравится это местоположение, вы можете изменить его в своем скрипте svscanboot, хотя большинство пользователей daemontools привыкли использовать /service и могут запутаться, если вы его не используете.
  3. Если вы используете Ubuntu или другой дистрибутив, который не использует стандартный init (т.е. не использует /etc/inittab), вам нужно будет использовать предустановленный inittab в качестве основы для организации svscanboot будет вызвано init. Это не сложно, но вам нужно знать, как настроить init, который использует ваша ОС. svscanboot - это скрипт, который вызывает svscan, который выполняет основную работу по поиску сервисов; он вызывается с init, поэтому init организует его перезапуск, если он по какой-либо причине умирает.

Настройка на обслуживание

  1. Каждой службе необходим каталог службы , в котором хранится служебная информация об услуге. Вы также можете создать место для размещения этих сервисных каталогов, чтобы они все были в одном месте; обычно я использую /var/lib/svscan, но с любым новым местоположением все будет в порядке.
  2. Я обычно использую сценарий для настройки каталога службы, чтобы сэкономить много ручной повторяющейся работы. например.,

    sudo mkservice -d /var/lib/svscan/some-service-name -l -u user -L loguser "command line here"
    

    , где some-service-name - это имя, которое вы хотите присвоить своей службе, user - это пользователь, который будет запускать эту службу, а loguser - это пользователь, который будет запускать регистратор от имени. (Ведение журнала объясняется чуть-чуть.)

  3. Ваша служба должна работать на переднем плане . Если ваша программа имеет фон по умолчанию, но имеет возможность отключить это, то сделайте это. Если фон вашей программы не имеет возможности отключить ее, прочитайте fghack, хотя это может быть компромиссом: вы больше не можете управлять программой, используя svc.
  4. Отредактируйте скрипт run, чтобы убедиться, что он делает то, что вам нужно. Возможно, вам придется позвонить sleep сверху, если вы ожидаете частого выхода из службы.
  5. Когда все настроено правильно, создайте символическую ссылку в /service, указывающую на каталог службы. (Не помещайте каталоги сервисов непосредственно в /service; это усложняет удаление сервиса из часов svscan.)

Вход

  1. Способ ведения журнала daemontools заключается в том, чтобы служба записывала сообщения журнала в стандартный вывод (или в стандартную ошибку, если вы используете сценарии, сгенерированные с mkservice); svscan заботится об отправке сообщений журнала в службу регистрации.
  2. Служба ведения журнала принимает сообщения журнала со стандартного ввода. Сценарий службы ведения журнала, сгенерированный mkservice, создаст автоматически повернутые файлы журнала с метками времени в каталоге log/main. Текущий файл журнала называется current.
  3. Службу регистрации можно запускать и останавливать независимо от основной службы.
  4. Передача файлов журнала через tai64nlocal переведет временные метки в удобочитаемый формат. (TAI64N - это 64-разрядная атомная временная метка с наносекундным счетом.)

Контроллерские услуги

  1. Используйте svstat для получения статуса услуги. Обратите внимание, что служба ведения журнала является независимой и имеет собственный статус.
  2. Вы управляете своим сервисом (запуск, остановка, перезапуск и т. Д.), Используя svc. Например, чтобы перезапустить ваш сервис, используйте svc -t /service/some-service-name; -t означает «отправить SIGTERM».
  3. Другие доступные сигналы включают -h (SIGHUP), -a (SIGALRM), -1 (SIGUSR1), -2 (SIGUSR2) и -k (SIGKILL).
  4. Чтобы отключить услугу, используйте -d. Вы также можете запретить автоматический запуск службы при загрузке, создав файл с именем down в каталоге службы.
  5. Чтобы запустить службу, используйте -u. В этом нет необходимости, если вы не отключили его ранее (или не настроили автоматический запуск).
  6. Чтобы попросить руководителя выйти, используйте -x; обычно используется с -d для прекращения службы. Это обычный способ разрешить удаление службы, но сначала необходимо отсоединить службу от /service, иначе svscan перезапустит супервизор. Кроме того, если вы создали свою службу со службой ведения журнала (mkservice -l), не забудьте также выйти из супервизора ведения журнала (например, svc -dx /var/lib/svscan/some-service-name/log) перед удалением каталога службы.

Резюме

Плюсы:

  1. daemontools предоставляет пуленепробиваемый способ создания и управления сервисами. Я использую его для своих серверов и очень рекомендую.
  2. Система регистрации очень надежна, как и средство автоматического перезапуска службы.
  3. Поскольку он запускает службы с помощью сценария оболочки, который вы пишете / настраиваете, вы можете адаптировать свой сервис так, как вам нравится.
  4. Мощные инструменты управления сервисом: вы можете отправлять в сервис практически любой сигнал и надежно повышать или понижать сервис.
  5. Вашим сервисам гарантируется чистая среда выполнения: они будут работать в той же среде, с лимитами процессов и т. Д., Которые предоставляет init.

Минусы:

  1. Каждый сервис требует настройки. К счастью, это нужно сделать только один раз за услугу.
  2. Службы должны быть настроены для работы на переднем плане. Кроме того, для достижения наилучших результатов они должны быть настроены на запись в стандартный вывод / стандартную ошибку, а не в системный журнал или другие файлы.
  3. Крутая кривая обучения, если вы новичок в способе работы daemontools. Вы должны перезапустить службы, используя svc, и не можете запускать сценарии запуска напрямую (так как они не будут находиться под контролем супервизора).
  4. Множество служебных файлов и множество служебных процессов. Каждой службе нужен собственный каталог службы, и каждая служба использует один процесс супервизора для автоматического перезапуска службы, если она умирает. (Если у вас много служб, вы увидите лотов из supervise процессов в вашей таблице процессов.)

В целом, я думаю, daemontools - отличная система для ваших нужд. Я приветствую любые вопросы о том, как его настроить и поддерживать.

12 голосов
/ 17 марта 2010

Вы должны взглянуть на daemonize . Позволяет обнаружить вторую копию (но использует механизм блокировки файлов). Также он работает на разных дистрибутивах UNIX и Linux.

Если вам нужно автоматически запустить приложение как демон, вам нужно создать соответствующий init-скрипт.

Вы можете использовать следующий шаблон:

#!/bin/sh
#
# mydaemon     This shell script takes care of starting and stopping
#               the <mydaemon>
#

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


# Do preliminary checks here, if any
#### START of preliminary checks #########


##### END of preliminary checks #######


# Handle manual control parameters like start, stop, status, restart, etc.

case "$1" in
  start)
    # Start daemons.

    echo -n $"Starting <mydaemon> daemon: "
    echo
    daemon <mydaemon>
    echo
    ;;

  stop)
    # Stop daemons.
    echo -n $"Shutting down <mydaemon>: "
    killproc <mydaemon>
    echo

    # Do clean-up works here like removing pid files from /var/run, etc.
    ;;
  status)
    status <mydaemon>

    ;;
  restart)
    $0 stop
    $0 start
    ;;

  *)
    echo $"Usage: $0 {start|stop|status|restart}"
    exit 1
esac

exit 0
11 голосов
/ 09 февраля 2009

Я думаю, вы можете попробовать start-stop-daemon(8). Проверьте сценарии в /etc/init.d в любом дистрибутиве Linux для примеров. Он может найти запущенные процессы по вызванной командной строке или PID-файлу, поэтому он соответствует всем вашим требованиям, за исключением того, что он является сторожевым таймером для вашего скрипта. Но вы всегда можете запустить другой сторожевой скрипт демона, который при необходимости просто перезапускает ваш скрипт.

7 голосов
/ 09 июня 2012

В качестве альтернативы уже упомянутым daemonize и daemontools существует команда daemon пакета libslack.

daemon вполне настраивается и заботится обо всех утомительных вещах демона, таких как автоматический перезапуск, ведение журнала или обработка pidfile.

5 голосов
/ 17 марта 2010

Daemontools (http://cr.yp.to/daemontools.html) - это набор довольно жестких утилит, используемых для этого, написанный dj bernstein. Я использовал это с некоторым успехом. Раздражает то, что ни один из скриптов не возвращает видимых результатов при их запуске - только невидимые коды возврата. Но когда он работает, он пуленепробиваемый.

5 голосов
/ 08 февраля 2009

Если вы используете OS X специально, я советую вам посмотреть, как работает launchd. Он автоматически проверит, работает ли ваш скрипт, и перезапустит его при необходимости. Он также включает в себя все виды функций планирования и т. Д. Он должен удовлетворять требованиям как 1, так и 2.

Что касается обеспечения работы только одной копии вашего скрипта, вам нужно использовать файл PID. Обычно я пишу файл в /var/run/.pid, который содержит PID текущего запущенного экземпляра. если файл существует при запуске программы, он проверяет, действительно ли запущен PID в файле (возможно, программа потерпела крах или иным образом забыла удалить файл PID). Если это так, отменить. Если нет, запустите и перезапишите файл PID.

3 голосов
/ 08 февраля 2009

Сначала получите createDaemon() от http://code.activestate.com/recipes/278731/

Тогда основной код:

import subprocess
import time

createDaemon()

while True:
    subprocess.call(" ".join(sys.argv[1:]),shell=True)
    time.sleep(10)
1 голос
/ 07 сентября 2017

Вы можете попробовать бессмертный Это кроссплатформенный (независимый от ОС) супервизор.

Для быстрого знакомства с macOS:

brew install immortal

В случае, если вы используете FreeBSD из портов или с помощью pkg:

pkg install immortal

Для Linux путем загрузки предварительно скомпилированных двоичных файлов или из источника: https://immortal.run/source/

Вы можете использовать его так:

immortal -l /var/log/date.log date

Или с помощью файла конфигурации YAML , который дает вам больше возможностей, например:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log

Если вы хотите сохранить стандартный вывод ошибок в отдельном файле, вы можете использовать что-то вроде:

cmd: date
log:
    file: /var/log/date.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
stderr:
    file: /var/log/date-error.log
    age: 86400 # seconds
    num: 7     # int
    size: 1    # MegaBytes
    timestamp: true # will add timesamp to log
1 голос
/ 13 апреля 2017

Вы также можете попробовать Monit . Monit - это сервис, который отслеживает и сообщает о других сервисах. Хотя он в основном используется как способ уведомления (через электронную почту и смс) о проблемах во время выполнения, он также может делать то, что отстаивало большинство других предложений здесь. Он может автоматически (повторно) запускать и останавливать программы, отправлять электронные письма, запускать другие сценарии и вести журнал вывода, который вы можете получить. Кроме того, я обнаружил, что его легко устанавливать и обслуживать, поскольку есть надежная документация.

...