понедельник, 29 июля 2013 г.

Немного про демонов.

Допустим мы написали приложение, которое теперь захотели запустить в демонизирующем режиме при запуске ОС. Что нужно для этого сделать?

0. Написать управляющий скрипт my_lovely_daemon, который должен обрабатывать как минимум 2 параметра: stop, start. А лучше, чтоб побольше: {start|stop|restart|reload|force-reload}.

Простейший пример (twisted-приложение dserver.tac уже кем-то написано):
cat my_lovely_daemon

#!/bin/sh

UTIL="/usr/bin/twistd"
PIDFILE=/var/run/dserver.pid
OPTS="--pidfile=$PIDFILE -y /usr/lib/python2.x/site-packages/namedirs/dserver.tac"

case "$1" in
  start)
echo -n "Starting"
start-stop-daemon --start -x $UTIL -- $OPTS
;;
  stop)
echo -n "Stopping"
start-stop-daemon --stop -R 15 -p "$PIDFILE"
ps ww | grep dserver | grep -v grep | awk '{print $1}' | xargs -r kill -9
;;
  *)
echo "Usage: $N {start|stop}" >&2
exit 1
;;
esac

exit 0

Немного подробнее об утилите start-stop-daemon и используемых опциях:

start-stop-daemon --start -x UTIL --pidfile PIDFILE
Запуск демона с помощью команды UTIL и создание файла с идентификатором процесса. 
Параметр -y /../dserver.tac -- относится к параметрам утилиты twistd, а не к start-stop-daemon. twistd -y server.tac -- позволяет запустить приложение *.tac

start-stop-daemon --stop -R 15 -p PIDFILE
Параметр -R как бы намекает, что нужно проверить через 15 секунд, убит ли демон или нет, если не убит, то пробует опять проверить.
Параметр -p означает, что во время операции stop будут остановлены только процессы, перечисленные в файле-идентификаторе PIDFILE.

Зачем нам нужен следующий конвеер?
ps ww | grep dserver | grep -v grep | awk '{print $1}' | xargs -r kill -9

ps ww -- показывает информацию на весь экран, в расширенном варианте 
(т.е.  
PID - идентификатор процесса 
TTY - терминал, с которым связан данный процесс
STAT - состояние, в котором на данный момент находится процесс
TIME - время старта процесса
COMMAND - команда, которая запустила данный процесс
)
grep dserver -- найти в списке процессов нужный нам dserver
grep -v grep -- ключ -v инвертирует результаты
Т.к. в процессе будет помимо искомого еще и процесс, запущенный предыдущей команд, т.е.
vi@kewtree$ ps ww | grep ps30803 pts/4    R+     0:00 ps ww30804 pts/4    S+     0:00 grep --color=auto ps
то очевидно, что сам grep-процесс нам не нужен.

awk '{print $1}' -- выводит первый столбец (pid-процесса в данном примере)

xargs - разбивает входной поток на аргументы и передает их выполнение любой команде.
В данном случае, в качестве команды выступает kill -9, а параметр -r нужен для того, чтобы ничего не выполнять, если вдруг список входных аргументов оказался пустым.

Подробнее о совершении убийства -> тут.

1. Демона добавляем в /etc/init.d. Теперь мы можем запускать наше приложение (*.tac) в демонизируещем режиме с командами start/stop (или больше, если сами это реализовали)

2. Чтобы наш демон запускался прям вместе с операционной системой, нужно определить, на каком уровне (runlevel) будет запущен наш демон.
Для того, чтобы указать системе, какие демоны, на каком уровне запуска, должны стартовать или останавливаться, в разных дистрибутивах существуют специально предназначенные для этого утилиты:

- update-rc.d для Debian
(Хотя в чем преимущество sysv-rc-conf или bum я не очень понимаю)

/*Тут когда-нибудь будут еще примеры утилит для других дистрибутивов */

Пример: 
"Хочу запустить демон на уровне 3 и 4 и приоритетом 70, и удалить на уровне 5 и 6 с приоритетом 20."
vi@kewtree# update-rc.d my_lovely_daemon start 70 3 4 . stop 20 5 6 .
Нужно больше примеров? Искать тут 




Коротко о происходящем:
1. ls -l /etc/rc*
И вы увидете, какие символические линки относятся к какому runlevel'у, и связь между линкой и соответсвующим демоном из init.d.

2. Запуск происходит последовательно, в соответсвии с названием симв.линки.
K15*
K20*
K30*
S10*
S20*
S30*
...

3. Еще про названия: K - означает, что соответствующий демон (my_lovely_daemon) должен быть выполнен с командой stop, S -- выполнение с командой start.

Т.е. можно вместо встроенных команд, вручную создавать симв. линки, например так:
"Хочу чтоб мой демон запускался при входе в систему на 5 уровне с приоритетом 99."
vi@kewtree$ sudo ln -s /etc/init.d/my_lovely_daemon /etc/rc5.d/S99my_lovely_daemon
Более подробно -> тут


В качестве презента дочитавшим и дополнившим -- кексики:

12 комментариев:

  1. Как автоматически вместе с загрузкой запустить скрипт строго после или перед определенным скриптом, который тоже стартует при загрузке?

    ОтветитьУдалить
    Ответы
    1. man init
      ну или что-нить подобное.

      советую посмотреть в /etc/rc*.d

      Удалить
    2. а, прочитал статью до конца, там об этом и написано)

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

      Удалить
    3. Может быть и правда читать до конца.

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

      Еще стоит написать про то, что существуют /etc/init.d/skeleton и /etc/init.d/README в Дебиане и ему подобных.

      Удалить
    5. Или можно. http://uzverss.livejournal.com/18483.html

      Да, еще как ведет себя скрипт по-умолчанию, если не указывать уровни и приоритеты.

      Удалить
    6. $ cat /etc/init.d/xxx
      #!/bin/sh -e
      ### BEGIN INIT INFO
      # Provides: xxx
      # Required-Start: $local_fs $remote_fs $network $syslog $activemq
      # Required-Stop: $local_fs $remote_fs $network $syslog
      # Default-Start: 2 3 4 5
      # Default-Stop: 0 1 6
      # Short-Description: Start/stop xxx
      ### END INIT INFO

      Удалить
    7. "после загрузки (перед загрузкой) таких-то скриптов стартовать этот. Это красиво и логично.", подумал Поттеринг и придумал SystemD. Он организует сущности (процессы, ресурсы, вообще все) в виде объектов с зависимостями.

      Удалить
  2. хм.
    ps ww | grep dserver | grep -v grep | awk '{print $1}' | xargs -r kill -9
    многобукаф

    я бы просто написал pkill -9 dserver

    =)

    ОтветитьУдалить
    Ответы
    1. Нет, pkill убьёт все процессы, в название которых входит dserver.

      Можешь посмотреть ещё на pgrep, который просто выводит pid'ы тех процессов, которые pkill убивает.

      Пример:
      $ ps wax | grep upstart
      413 ? S 0:00 upstart-file-bridge --daemon
      434 ? S 0:02 upstart-udev-bridge --daemon
      1174 ? S 0:00 upstart-socket-bridge --daemon
      6714 pts/1 S+ 0:00 grep --color=auto upstart

      $ pgrep upstart
      413
      434
      1174

      Удалить
    2. ok. спасибо за дополнение)

      Удалить