Демонизация приложений, делаем демон приложения systemd в CentOS (Debian), работа с сервисами (sysvinit, systemctl)

  • systemctl (system control) без запущенных аргументов выдает список systemd объектов/UNIT (mount, target, service, socket, timers, etc) запущенных в системе. с флагом —type <UNIT> можно отфильтровать конкретные объекты.
# systemctl
UNIT LOAD ACTIVE SUB DESCRIPTION 
proc-sys-fs-binfmt_misc.automount loaded active waiting Arbitrary Executable File Formats File System Automount Point 
sys-devices-pci0000:00-0000:00:07.1-ata2-host1-target1:0:0-1:0:0:0-block-sr0.device loaded active plugged VMware_Virtual_IDE_CDROM_Drive 
sys-devices-pci0000:00-0000:00:10.0-host2-target2:0:0-2:0:0:0-block-sda-sda1.device loaded active plugged Virtual_disk 1 
sys-devices-pci0000:00-0000:00:10.0-host2-target2:0:0-2:0:0:0-block-sda-sda2.device loaded active plugged Virtual_disk 2 
sys-devices-pci0000:00-0000:00:10.0-host2-target2:0:0-2:0:0:0-block-sda-sda5.device loaded active plugged Virtual_disk 5 
sys-devices-pci0000:00-0000:00:10.0-host2-target2:0:0-2:0:0:0-block-sda.device loaded active plugged Virtual_disk 
sys-devices-pci0000:00-0000:00:11.0-0000:02:00.0-net-ens32.device loaded active plugged 82545EM Gigabit Ethernet Controller (Copper) (PRO/1000 MT Single Port Adapter)
sys-devices-pci0000:00-0000:00:11.0-0000:02:01.0-net-ens33.device loaded active plugged 82545EM Gigabit Ethernet Controller (Copper) (PRO/1000 MT Single Port Adapter)
sys-devices-pci0000:00-0000:00:11.0-0000:02:02.0-net-ens34.device loaded active plugged 82545EM Gigabit Ethernet Controller (Copper) (PRO/1000 MT Single Port Adapter)
sys-devices-platform-floppy.0-block-fd0.device loaded active plugged /sys/devices/platform/floppy.0/block/fd0 
...


# systemctl --type=mount
UNIT LOAD ACTIVE SUB DESCRIPTION 
-.mount loaded active mounted / 
dev-hugepages.mount loaded active mounted Huge Pages File System 
dev-mqueue.mount loaded active mounted POSIX Message Queue File Syst
run-netns-VRF1.mount loaded active mounted /run/netns/VRF1 
run-netns-VRF2.mount loaded active mounted /run/netns/VRF2 
run-netns.mount loaded active mounted /run/netns 
run-user-0.mount loaded active mounted /run/user/0 
sys-kernel-debug.mount loaded active mounted Kernel Debug File System

Все управляющие программы для роботов по сути демоны/службы – работают в бесконечном цикле.

В CentOS, в отличии от Ubuntu, по умолчанию нет Start-stop-daemon для запуска своих процессов в виде демонов. При его наличии запуск приложения в виде демона решается простой командой (главное чтобы скрипт был исполняемым :)).

start-stop-daemon -Sbvx /home/redkin_p/bin/test.rb

Для того чтобы сделать это в CentOS (справедливо и для Debian) есть такие варианты:

0) screen

1) Запустить приложение через nohup. Или в сессии screen/tmux (о screen).

nohup — UNIX-утилита, запускающая указанную команду с игнорированием сигналов потери связи (SIGHUP). Таким образом, команда будет продолжать выполняться в фоновом режиме и после того, как пользователь выйдет из системы.
Позволяет не запускать start-stop-daemon, делать сервисы и вообще что-либо. Идет из коробки во всех известных дистрибутивах Linux. Еще круто, что вывод она пишет в отдельный файл - nohup.out (если не нужен - можно дропнуть через редирект &>/dev/null)

nohup bin/sms2.rb
nohup nmap -sP 10.3.0.0/20
nohup ip netns exec VRF1 ping 172.17.0.2 >ping_res_va # по умолчанию STDOUT сохраняется в файле nohup.out

2) собрать start-stop-daemon для CentOS. Как по мне очень плохое решение (но, возможно, в 2011 единственное) – требует компилятора, компиляции и прочих штук очень долгих и несущих существенные изменений в систему (зависимые системные библиотеки).

3) Перевести активное приложение/процесс с отвязкой от терминала можно с использованием hotkey по сворачиванию + переводу в background + disown процеса

1) Ctrl+Z to stop (pause) the program and get back to the shell.
2) bg to run it in the background.
3) disown -h [job-spec] where [job-spec] is the job number (like %1 for the first running job; find about your number with the jobs command) so that the job isn't killed when the terminal closes.

Команда disown является встроенной командой таких командных оболочек, как Bash, Zsh и Ksh и позволяет убрать заданную задачу из таблицы задач командной оболочки. Это делается для того заблокировать отправку системного сигнала SIGHUP запущенному с помощью командной оболочки и исполняющемуся в фоновом режиме процессу при завершении работы командной оболочки. В отличие от команды nohup, рассматриваемая команда может использоваться в любой момент после создания задачи, а не до только при ее создании и не отсоединяет стандартные потоки ввода, вывода и ошибок исполняющегося процесса от командной оболочки.

4) Сделать сервис в system.d. Прекрасное и самое правильное решение. Немного сложнее start-stop-daemon (и, тем более, nohup), но лучше т.к. позволяет стандартно добавить сервис в автозагрузку, следить по аналогии с другими сервисами за работоспособностью, стандартно перезагружать и прочее.

https://scottlinux.com/2014/12/08/how-to-create-a-systemd-service-in-linux-centos-7/ 
https://unix.stackexchange.com/questions/236084/how-do-i-create-a-service-for-a-shell-script-so-i-can-start-and-stop-it-like-a-d
управление сервисами sysvinit

Смотрим какие сервисы есть в автозапуске

ls /etc/rc.d/rc3.d  # для runlevel 3
ls /etc/rc.d/init.d  # сервисы могут быть тут, а в runlevel ссылки на эти скрипты
chkconfig —list  # для всех runlevel


Включение/отключение в автозапуск сервиса для runlevel по умолчанию (2 3 4 5) или для конкретных runlevel. Chkconfig позволил отказаться от  устаревшего подхода подкладывания файлов в директории rc.d для соответствующих runlevel (если скрипт подложен – запускается, если нет – не запускается).

sudo chkconfig httpd on
sudo chkconfig httpd off
sudo chkconfig —level 35 httpd on

Запуск/отключение/рестарт/просмотр статуса сервиса

sudo service httpd status
sudo service httpd start
sudo service httpd stop
sudo service httpd restart

 

Пошагово создание сервиса в systemd

Аналог service файла ниже создается обычно при установке софта, описано создание своего сервиса.

1) Создаем файл с сервисом, называем как хотим, на конце должно быть “service”. Указываем target в котором будет запускаться сервис (подробнее в wants runlevel). Опционально указываем

  • [Unit] After=<target> – сервис будет запущен только после запуска (after) указанного, например для сетевых сервисов логично “After=Network.target”.
  • [Service]
    • User=<user> – сервис по умолчанию запускается из под root, можно указать конкретного
    • WorkingDirectory=<dir>
    • Restart=<always> – автоперезагрузка сервиса при падении
$ cat /etc/systemd/system/test_service.service 
[Unit] 
Description=test_service.rb
After=Network.target

[Service] 
Type=simple 
ExecStart=/usr/bin/test_service.rb <options>

[Install] 
WantedBy=multi-user.target

Для передачи переменных (напр. указываем название файла вывода от времени запуска сервиса) можно вызывать утилиту через /bin/bash. Пример: запускаем tcpdump, имя файла с дампом содержит дату/время запуска.

ExecStart=/bin/bash -c "test=$(/usr/bin/date | tr ' :' '.'); /usr/sbin/tcpdump -n -w /opt/logs/$test.pcap"

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

sudo systemctl daemon-reload
sudo systemctl enable test_service

3) Стартуем наш сервис (так же start/stop)

sudo systemctl start test_service

4) Проверяем статус (тут можно посмотреть и текущий и включен ли автостарт). Тут так же видим последние сообщения от нашей программы/скрипта. Для просмотра всех сообщений смотрим journalctl (journald).

sudo systemctl status test_service
sudo journalctl -u test_service

5) Добавляем в автозагрузку через enable (можно так же использовать множество других способов, напр. добавив команду start сервиса в /etc/rc.local, но самый правильный через systemctl; offtop: при использовании rc.local нужно не забывать добавлять shebang и права на исполнение). Флаг –now позволяет запустить службу, даже если ранее мы ее не запустили через start. Помимо добавления в автозагрузку systemd команда так же на всякий случай синхронизирует состояние сервиса в sysVinit.

sudo systemctl enable test_service
sudo systemctl enable --now open-vm-tools

# systemctl enable ssh
Synchronizing state of ssh.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable ssh

Так же можно управлять текущим состоянием сервиса start/stop/restart.

sudo systemctl start test_service
sudo systemctl stop test_service
sudo systemctl restart test_service

Enjoy

 

 

Типы сервисов в system.d

Выше рассмотрен простой типовой случай, когда используется тип сервиса simple, но возможно так же использовать oneshot и forking.

  • Forking: systemd считает службу запущенной после того, как процесс разветвляется с завершением родительского процесса. Нужен для работы с приложениями, которые создают дочерние процессы при запуске (напр. worker’ы), а сами при этом отключаются – используется для запуска классических демонов за исключением тех случаев, когда в таком поведении процесса нет необходимости. Можно указать параметр PIDFile=, чтобы systemd мог отслеживать основной процесс. Oneshot и forking для таких задач подходят плохо, они оба предназначены для работы именно с тем процессом, который запускается
Both Type=oneshot and Type=simple units ignore any children of the first process, so do not use these modes with forking processes
  • Simple (по умолчанию): systemd запустит эту службу незамедлительно. Процесс при этом не должен разветвляться (fork). Если после данной службы должны запускаться другие, то этот тип использовать не стоит (исключение — служба использует сокетную активацию).
  • Oneshot: удобен для сценариев, которые выполняют одно задание и завершаются. Примеры использования.
Если задать параметр RemainAfterExit=yes, то systemd будет считать процесс активным даже после его завершения.

 

Questions

The command dbmaint & was used to run dbmaint in the background. However, dbmaint is terminated after logging out of the system. Which alternative dbmaint invocation lets dbmaint continue to run even when the user running the program logs out?

A. job –b dmaint

B. dbmaint &>/dev/pts/null

C. nohup dbmaint &

D. bg dbmaint

E. wait dbmaint

Answer: C

The correct answer is nohup dbmaint & The reason for this is nohup (“no hangup”) detaches dbmaint from the user who started it, and the & at the end tells the console to run dbmaint in the background.

Leave a Reply