В качестве системы инициализации в Fedora применяется systemd, поэтому в этой статье мы подробно рассмотрим управление, настройку и создание собственных юнитов и таймеров.
Введение
Основная единица конфигурации systemd — юнит. Основные типы юнитов:
- target — целевой юнит, описывает цели, по достижении которых могут срабатывать другие юниты;
- service — используется для запуска системных служб;
- timer — используется для запуска конкретных действий по заранее составленному расписанию;
- socket — применяется для активации служб посредством обращения к Unix-сокетам;
- device — позволяет запускать какое-либо действие или сервис при подключении или отключении устройств;
- mount и automount — используется для (автоматического) монтирования файловых систем;
- swap — применяется для работы с файлами или устройствами (например разделами) подкачки.
В Fedora все стандартные предустановленные юниты размещаются в каталоге /usr/lib/systemd/, который имеет следующие подкаталоги:
- system — стандартные общесистемные юниты для общих целей, выполняющиеся при запуске системы или при наступлении определённых условий, прописанных в них;
- user — запускаются при входе (или выходе) пользователя в систему от его имени;
- system-shutdown — содержит скрипты, которые выполняются автоматически при завершении работы системы;
- systemd-sleep — содержит скрипты, которые выполняются автоматически при уходе системы в спящий (hybernate) режим.
Создание обыкновенных юнитов
Начнём мы конечно же с создания собственных юнитов. Как уже сообщалось выше, общесистемные юниты общего назначения располагаются в каталоге /usr/lib/systemd/system/ в виде файлов $name.$suffix, где $suffix явно указывает его тип.
Сразу рассмотрим простой пример foobar.service:
[Unit] Description=Sample standard unit After=network.target [Service] Type=simple Restart=always RestartSec=30 ExecStartPre=/usr/bin/foobar prehook ExecStart=/usr/bin/foobar ExecStartPost=/usr/bin/foobar posthook [Install] WantedBy=multi-user.target
Теперь разберёмся с основными директивами:
- Description — описание юнита;
- After — используется для указания зависимостей, после которых данный юнит должен запускаться при активации;
- Type — тип юнита. Возможны варианты:
- simple — простой запуск указанного процесса или сценария. Такие процессы не должны создавать своих дочерних процессов (форков);
- forking — то же, что и simple, но с возможностью запуска форков. Внутри юнита обязательно должна использоваться директива PIDFile, чтобы systemd мог знать PID родительского процесса и корректно проверять его состояние;
- oneshot — юнит, который должен запустить процесс или сценарий и сразу завершить свою работу вместе с запущенным приложением;
- dbus — используется для активации посредством получения определённого D-Bus события;
- Restart — включает или отключает механизм автоматического перезапуска в случае падения запущенного приложения;
- RestartSec — задаёт интервал времени, по истечении которого упавший процесс будет автоматически перезапущен (если это разрешено предыдущей директивой);
- ExecStartPre — путь к бинарнику или сценарию, который будет запущен до непосредственного запуска главного приложения;
- ExecStart — главный бинарник или сценарий юнита;
- ExecStartPost — путь к бинарнику или сценарию, который будет запущен после запуска главного приложения;
- WantedBy — задаёт цель, при активации которой юнит будет автоматически запускаться.
Полный список директив можно найти в официальной документации к systemd.
Создание юнита, который будет запускаться с правами указанного пользователя
По умолчанию все общесистемные юниты запускаются с правами суперпользователя (root), что может быть небезопасно, поэтому systemd предоставляет возможность тонкой настройки запуска с правами любого доступного в системе пользователя:
[Unit] Description=Sample unit running from specified user After=network.target [Service] Type=simple Restart=always RestartSec=30 User=nobody Group=nobody ExecStart=/usr/bin/foobar [Install] WantedBy=multi-user.target
В данном примере мы добавили директивы User и Group, задающие пользователя и группу, от имени которых будет запущен процесс.
Указанный в файле пользователь и группа должны существовать, т.к. в противном случае попытка запуска завершится с ошибкой.
Создание юнита, который будет выполняться при завершении работы системы
Если требуется выполнять какой-то процесс при завершении работы системы, мы должны создать unit-файл такого вида:
[Unit] Description=Sample unit running on shutdown Before=shutdown.target reboot.target halt.target [Service] Type=oneshot ExecStart=/usr/bin/foobar
В данном примере будет запускаться приложение /usr/bin/foobar при каждом завершении работы системы (условие указано внутри директивы Before).
Следует обратить внимание на тип данного юнита — oneshot и отсутствие секции Install.
Создание юнита, который будет выполняться при входе пользователя в систему
Данный тип ничем не отличается от стандартных юнитов, однако размещаются в каталоге /usr/lib/systemd/user/. При активации всегда выполняются с правами вошедшего в систему пользователя.
Создание юнита, который будет выполняться при выходе пользователя из системы
Также должны располагаться в /usr/lib/systemd/user/, но внутри директивы Before должно быть указано exit.target:
[Unit] Description=Sample unit running on logoff Before=exit.target [Service] Type=oneshot ExecStart=/usr/bin/foobar
Указанная команда также будет выполнена с правами пользователя, который инициировал процесс выхода из системы.
Создание таймеров
Имя файла таймера должно иметь суффикс timer, например foobar.timer. Таймер всегда является дополнением к service, т.к. при его срабатывании запускается service с тем же именем:
[Unit] Description=Sample standard timer [Timer] OnUnitActiveSec=1w [Install] WantedBy=timers.target
Условия срабатывания прописываются в секции Timer. В нашем примере применяется директива OnUnitActiveSec, означающая, что данный таймер будет срабатывать автоматически каждую неделю (отсчёт начнётся в момент его активации). Это т.н. неточный таймер.
Наряду с неточными существуют ещё и точные таймеры, в которых применяется особая директива OnCalendar, где, в свою очередь, указывается время и дата его срабатывания (например по вторникам, в 16:20).
Редактирование и переопределение стандартных юнитов и таймеров
В случае если нужно отредактировать какой-то из уже установленных в системе юнитов или таймеров, ни в коем случае не следует непосредственно править файл внутри каталога /usr/lib/systemd/, т.к. при следующем обновлении системы все изменения в нём будут перезаписаны.
Вместо этого следует использовать штатную возможность systemd:
sudo systemctl edit --full foobar.service
Здесь foobar.service — имя нужного нам юнита/таймера, который мы будем редактировать. Systemd автоматически сделает копию файла в пользовательский каталог настроек /etc/systemd/system/, загрузит его в системном редакторе по умолчанию, а по окончании внесения изменений заставит systemd применить их.
Чтобы изменить редактор по умолчанию, можно воспользоваться системой изменения альтернатив:
sudo update-alternatives --config editor
Для отката любых внесённых изменений следует использовать:
sudo systemctl revert foobar.service
Управление юнитами systemd
Перезагрузка базы данных установленных юнитов (рекомендуется выполнять при любом внесении изменений):
sudo systemctl daemon-reload
Вывод информации о доступных юнитах:
systemctl list-units
Вывод информации о доступных таймерах:
systemctl list-timers
Запуск:
sudo systemctl start foobar.service
Остановка:
sudo systemctl stop foobar.service
Перезапуск:
sudo systemctl restart foobar.service
Активация (юнит начнёт запускаться автоматически при возникновении указанных в его файле условий):
sudo systemctl enable foobar.service
Отключение:
sudo systemctl disable foobar.service
Проверка текущего статуса:
systemctl status foobar.service
Полная блокировка возможности запуска и работы юнита:
sudo systemctl mask foobar.service
Разблокировка:
sudo systemctl unmask foobar.service
Показать весь журнал работы:
journalctl -u foobar.service
Показать только ошибки:
journalctl -u foobar.service -p err..alert
Создание пользовательских юнитов systemd
Systemd позволяет каждому пользователю создавать собственные юниты и управлять ими. Для хранения таких файлов применяются следующие каталоги (при отсутствии нужно создать самостоятельно):
- ~/.local/share/systemd/user/ (аналог системного /usr/lib/systemd/user/ для установленных пользовательскими приложениями юнитов);
- ~/.config/systemd/user/ (каталог для пользовательских файлов конфигурации и юнитов).
Управление ничем не отличается от стандарта за исключением необходимости использования параметра —user. Пример:
systemctl --user start foobar.service
Литература
При написании данной статьи использовались следующие источники: