Супервизор Systemd

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

У нас есть небольшое неудобство, заключающееся в том, что нам приходится запускать наше приложение вручную.

Чтобы полноценно демонизировать процесс его надо подключить к супервизору. Супервизор — это главный процесс в linux который мониторит все процессы, подчищает некорректно удаленные, а также управляет различными сервисами, логирует их исполнение, следит чтобы они перезапускались в случае непредвиденных ситуаций и т.п.

Для управления супервизором есть две основные команды.

  • systemctl – для непосредственного управления сервисами (перезапуск, остановка, проверка статусов)
  • journalctl – для просмотре логов

Например, можно запустить команду systemctl list-units --type=service и увидеть список всех сервисов доступных в системе

В крайнем левом столбце видно название сервисов. Каждому сервису как правило сопоставлена некоторая программа, которую супервизор должен запустить

Чтобы супервизор мог понять кого запускать. Есть специальные файлик описывающие сервис. Мы можем быстро посмотреть файлик сопоставленный сервису если напишем команду

sudo systemctl cat ИМЯ_СЕРВИСА

например можно глянуть сервис который ответственен за общение VirtualBox и нашего линукса

sudo systemctl cat vboxadd.service

В выводе видим две наиболее интересных строчки. Первая это путь к файлу, в котором содержится описание сервиса /lib/systemd/system/vboxadd.service. Скоро мы сделаем свой такой.

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

Можно глянуть кстати, что лежит в папке /lib/systemd/system и увидеть, что там действительно есть такой файлик и еще куча других

ls /lib/systemd/system

каждый отвечает за какой-то свой сервис

Мы можем отредактировать каждый файлик либо прямо через, типа

sudo nano /lib/systemd/system/vboxadd.service

либо используя systemctl, вот так

sudo systemctl edit --full vboxadd.service

Регистрация сервиса

И так, чтобы наш сервис подключить к супервизору создадим файлик my_daemon.service:

и теперь опишем в него сервис

[Unit]
Description=Заклинатель книг  # название сервиса

[Service]
User=m  # под каким юзером запускать
# рабочая директория, в ней будет искаться config.txt
WorkingDirectory=/home/m/cpp05
# путь к скомпилированному файлу
ExecStart=/home/m/cpp05/main

[Install]
WantedBy=multi-user.target # хотим, чтобы запускалось при запуске системы

обязательно уберите из файлика все комментарии, иначе он не будет работать. Но прежде прочитайте их внимательно, и адаптируйте значения под свою систему. Если вы просто бездумно скопируете, то, внезапно, ничего работать не будет =О

Теперь нам надо подключить этот файлик к супервизору.

Сначала надо положить его в папку /etc/systemd/system, чтобы проще было редактировать мы просто создадим ссылку на наш файл вот так:

sudo ln -s $PWD/my_daemon.service /etc/systemd/system

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

Переменная $PWD как раз хранит полный путь текущей папки.

теперь надо перегрузить кеш сервисов

sudo systemctl daemon-reload

у меня старый демон, который папку мониторит, вот с таким кодом

#include <iostream>
#include <sys/inotify.h>
#include <unistd.h>

using namespace std;

int main(int argc, char *argv[])
{
    int inotify_fd = inotify_init();
    int watch_fd = inotify_add_watch(inotify_fd, "/home/m", IN_MODIFY | IN_CREATE | IN_DELETE);

    while (true) {
        char buffer[10000];
        int length = read(inotify_fd, buffer, 10000);

        int i = 0;
        while (i < length) {
            struct inotify_event *event = (struct inotify_event *)&buffer[i];

            if (event->mask & IN_MODIFY) {
                cout << "изменился" << event->name << endl;
            }
            else if (event->mask & IN_CREATE) {
                cout << "создали файл" << event->name << endl;
            }

            i += sizeof(struct inotify_event) + event->len;
        }
    }

    inotify_rm_watch(inotify_fd, watch_fd);
    close(inotify_fd);
    return 0;
}

Момент истины, запускаем наш сервис:

sudo systemctl start my_daemon.service

теперь попробуем узнать статус нашего сервиса

sudo systemctl status my_daemon.service

если увидим такое

значит все работает =)

Давайте теперь протестируем как он работает

смотреть так что происходит в логах очень неудобно, но к счастью есть альтернативный вариант

Journalctl

Утилита journalctl, позволяет смотреть логи по всему что происходит в системе, в том числе и по нашему демону.

Для просмотра журнала по своему демону надо ввести вот такую команду

sudo journalctl -u my_daemon.service

чтобы выйти из лога нажмите q

если хочется смотреть лог в режиме реального времени, то можно добавит флаг -f (--follow)

sudo journalctl -u my_daemon.service -f

работает практически мгновенно

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

sudo systemctl stop my_daemon.service

в логе зафиксируется момент и причина остановки.

И еще один важный момент чтобы ваш демон действительно запустился при перезапуске системы надо активировать сервис командой enable

sudo systemctl enable my_daemon.service

можно попробовать перезапустить систему и проверить что сервис действительно перезапустился.

Задание

Настроить супервизор systemd для запуска вашего демона. В логи демона фиксировать моменты изменения данных в файле, дублировать, то что выводете и в файл и в лог.