Что такое systemd: примеры использования

systemd — подсистема инициализации и управления службами в Linux, фактически традиционную подсистему init. systemctl - основной инструмент управления systemd.

Systemd опирается на современные Linux- технологии: cgroups, AutoFS, D-Bus, и при этом совместим с исторически устоявшимися механизмами: init- скриптами, стандартными командами shutdown, poweroff и т.п. Предоставляемый systemd функционал позволяет заменить не только систему инициализации, но и ряд других подсистем, в частности: cron, (x)inetd, xdm/kdm/gdm/…, частично даже SELinux как правильно отключить!! Для начинающих.

Чтобы понять разницу между всеми этими “модулями” или “юнитами”, надо вспомнить, что systemd, как и все остальное в Linux, является файлом. И все systemd-сущности являются разными файлами (например systemd службы хранят конфигурации в файле с расширением .service, а сокеты - .socket и т.д.). Systemd, если рассматривать как демон, управляет другими демонами и является первым демоном, который запускается во время загрузки ОС.

Базовым элементом systemd являются модули (units). Модули имеют имя и тип. Каждый модуль может требовать для своей работы другие модули, конфликтовать с модулями, запускаться только после или до определенного модуля (директивы конфигурации Requires, Conflicts, Before, After, Wants). Поскольку их конфигурация обычно загружается из файловой системы - названия модулей на самом деле представляют собой имена файлов. Например: модуль avahi.service считывается из конфигурационного файла с тем же именем и естественно, что он реализует работу с демоном Avahi. Из типов модулей определены:

  • service. Обычный демон, поддерживающий операции start, stop, restart, reload. Может быть представлен родным (native) файлом конфигурации systemd или System V init- скриптом. Для совместимости с SysV в systemd помимо собственных файлов конфигурации для различных сервисов имеется возможность чтения классических скриптов инициализации SysV, а также она умеет разбирать заголовок LSB, если он существует. /etc/init.d является, следовательно, не более, чем просто еще одним источником конфигурации.
  • socket. При обращении к сокету генерируется событие, для которого можно настроить обработчик. Например, автоматически запускать определенные службы при обращении к заданному сокету. В этом отношении systemd похож на давно известный (x)inetd, однако при этом поддерживает unix domain сокеты и FIFO.
  • device. Отметив нужные устройства в конфигурации udev, впоследствии можно использовать такие события, как появление и удаление устройства, в качестве событий systemd, назначив на них обработчики. Например, при появлении устройства bluetooth будет запущена соответствующая служба.
  • Path unit (файловый путь .path) - используется для наблюдения за файлом или директорий на предмет наличия определенного события, и если это событие происходит, то выполняется запуск service-юнита с таким же именем (если не указан другой). Тут стоит привести более конкретный пример, чтобы было понятнее:
    [Unit] 
    Description=Smotrim za izmeneniyami v faile
    [Path] 
    PathChanged=/home/some_path/some_file 
    Unit=changes_applied.service 
    [Install] 
    WantedBy=multi-user.target

    Он описывает следующее: Вы наблюдаете за файлом /home/some_path/some_file, и если он меняется, то запускается сервис, определенный в Unit=changes_applied.service.

  • mount. Модуль реализует точку монтирования в файловой системе. systemd контролирует все точки монтирования (их подключение и отключение), а также может быть использована для монтирования и размонтирования отдельных файловых систем. Файл /etc/fstab используется как дополнительный источник конфигурации для них, в целях обратной совместимости.
  • automount. Для помеченных таким образом точек монтирования, монтирование выполняется только при обращении к ним.
  • target. Более гибкий аналог уровней исполнения (runlevels), используемых в System V init. Представляет собой группу служб, объединенных по функциональному назначению. Например, multi-user.target идентичен runlevel 5, а bluetooth.target приводит к инициализации подсистемы bluetooth.
  • snapshot — во многом похож на target. Позволяет «запомнить» существующую конфигурацию units (запущенных служб, открытых сокетов, смонтированных ФС) с тем, чтобы в дальнейшем восстановить это состояние. Позволяет, например, перейти в emergency shell (сейчас это init 1), а затем полностью восстановить набор запущенных служб. Второй вариант его использования - поддержка режима suspend: достаточно много сервисов не могут корректно работать с этой системой, и зачастую их лучше остановить перед засыпанием, а потом просто запустить.

Службы Systemd делят на две категории - системные службы, запускаемые от имени суперпользователя. Чтобы ими управлять, необходимо использовать sudo. Вторая категория - пользовательские службы, запускаемые от имени конкретного пользователя. Этот пользователь может иметь полный контроль без sudo.

Файлы системных служб находятся в

/usr/lib/systemd/system
/lib/systemd/system
/etc/systemd/system

Например, в примере ниже видно что физически файл находится в /usr/lib/systemd/system/, а из других каталогов просто ссылки

stat /etc/systemd/system/multi-user.target.wants/postgresql-13.service
  File: ‘/etc/systemd/system/multi-user.target.wants/postgresql-13.service’ ->/usr/lib/systemd/system/postgresql-13.service’

Файлы пользовательских служб можно найти в:

/usr/lib/systemd/user
/lib/systemd/user
/etc/systemd/user
$USER/.config/systemd/user

Причем файлы сервисов поставляемые с пакетами обычно находятся в каталогах /lib и /usr/lib, а в /etc/ расположены модифицированные файлы юнитов переопределяющие стандартные настройки

systemctl - основной инструмент управления systemd.

  • Запуск, останов и просмотр статуса какой-либо службы происходит посредством команд. В командах используется служба nginx:
systemctl start nginx
systemctl stop nginx
systemctl status nginx
  • Перезапуск командой
systemctl restart nginx
  • Проверить добавлена ли уже служба nginx в автозагрузку:
systemctl is-enabled nginx
  • Для добавления сервиса в автозагрузку используется
systemctl enable nginx

Подкоманда enable не запускает службу, а только помечает ее для автоматического запуска при загрузке. Чтобы включить и запустить службу одновременно, используйте параметр –now

systemctl enable --now nginx
systemctl disable apparmor

В строке Loaded видим ключ enabled.

 systemctl status apparmor
   Loaded: loaded (/etc/init.d/apparmor; bad; vendor preset: enabled)
  • Можно также "замаскировать" сервис - то есть, лишить модуль возможности запускаться. systemctl mask / systemctl unmask: запрещает (разрешает) все и любые попытки запуска рассматриваемого модуля (либо вручную, либо как зависимость любого другого модуля, включая зависимости цели загрузки по умолчанию).
systemctl mask nginx
  • Посмотреть дерево зависимостей - от каких процессов зависит cron.
systemctl list-dependencies nginx
  • Вывести список всех процессов
    systemctl
  • Список запущенны юнитов, без ключа -а будут показаны только те службы которые сейчас работают
systemctl -t service -a
или так
systemctl --type=service -a

Список запущенны юнитов в Linux.

  • Список всех имеющихся модулей в системе покажет команда
# systemctl list-units
  • Просмотр статуса службы, например syslog
# systemctl status syslog.target
syslog.target - Syslog
	  Loaded: loaded (/lib/systemd/system/syslog.target; static)
	  Active: active since Thu, 01 Mar 2012 16:18:25 +0000; 18h ago

Файл модуля cron находится по адресу /lib/systemd/system/cron.service.

[Unit] - директива, указывающая systemd, что эта часть файла является описательной, указывает параметры запуска и т.д.
Description=Regular background program processing daemon - описание юнита
Documentation=man:cron(8) - указание пути к документации
After=remote-fs.target nss-user-lookup.target - параметр, указывающий, что данный юнит должен запускаться после (after) модуля, указанного справа от "=".
 
[Service] - блок конфигурации юнита
EnvironmentFile=/etc/default/cron - файл окружения
ExecStart=/usr/sbin/cron -f $EXTRA_OPTS - команда для старта
IgnoreSIGPIPE=false - параметр для игнорирования SIGPIPE сигнала (SIGPIPE — сигнал, посылаемый процессу при записи в соединение (пайп, сокет) при отсутствии или обрыве соединения с другой (читающей) стороной.)
KillMode=process - указывает, как "убивать" процесс.
Restart=on-failure - указание, когда необходимо перезагружать сервис.
 
[Install] - блок, описывающий информацию об установке юнита (нужен для команд systemctl enable/disable)
WantedBy=multi-user.target - данная директива, является наиболее распространенным способом
определения того, как юнит должен быть включен, от чего зависит.

Создайте скрипт, который вы хотите запускать и дать файлу права на исполнение (chmod +x). В этом примере создан тестовый файл /usr/sbin/love.sh, с таким содержимым:

#!/bin/bash
while true
do
  printf "Make love,not war\n"
sleep 60
done

Создайте файл /etc/systemd/system/love.service на вашем тестовом Debian:

[Unit]
Description=My first super program
 
[Service]
#fail
ExecStop=/bin/kill -9 $MAINPID
#StandardOutput=null
#success
ExecStart=/bin/bash /usr/sbin/love.sh
 
[Install]
WantedBy=multi-user.target

Все готово, теперь для запуска введите:

systemctl daemon-reload
systemctl start love.service

Для проверки того что все работает, убедитесь что служба работает, командой:

systemctl status love.service

И также проверьте системный журнал syslog на наличие строки "Started My first super program", командой:

tail -f /var/log/syslog
 
Dec  6 23:32:34 dark systemd[1]: Started My first super program.
Dec  6 23:32:34 dark bash[2672]: Make love,not war
Dec  6 23:32:39 dark bash[2672]: Make love,not war

Если раскомментировать строку StandardOutput=null, то вывод нашего скрипта love.sh (Make love,not war) перестанет писаться в файл syslog.

Ваш сервер перезагрузился и все запущенные контейнеры Docker остановились. Чтобы избавиться от необходимости вручную запускать их, можно настроить автозапуск контейнеров. Для этого следует создать текстовые файлы со специальным форматом для сервиса systemd. Рассмотрим пример автозапуска контейнера my-db, для этого создадим файл

nano /etc/systemd/system/my-db.service

В этом файле:

  • [Unit] секция описывает метаданные и зависимости службы.
    • Description предоставляет описание службы.
    • Requires и After указывают, что служба зависит от docker.service.
  • [Service]
    • ExecStartPre используется для остановки и удаления контейнера, если он уже существует, перед запуском. Вы можете настроить эти команды в соответствии с вашими требованиями.
    • ExecStart указывает команду для запуска вашего контейнера.
    • ExecStop определяет, как остановить контейнер.
  • [Install] секция указывает, когда служба должна быть запущена. В этом примере служба настроена на запуск при загрузке в многопользовательском режиме.
[Unit]
Description=My docker container my-db-container
# для успешного запуска нашего контейнера сначала должна быть запущена служба Docker
Requires=docker.service
After=docker.service
 
[Service]
# Если служба завершает работу всегда перезапускать её
Restart=always
ExecStartPre=-/usr/bin/docker stop 
ExecStartPre=-/usr/bin/docker rm my-db-container
ExecStart=/usr/bin/docker run --name my-db-container my-docker-image
ExecStop=/usr/bin/docker stop my-db-container
 
[Install]
WantedBy=multi-user.target

После этого остается перезапустить демон systemcmd и включить автозагрузку контейнера mydb, набрав в терминале поочередно команды:

systemctl daemon-reload
systemctl start my-db.service
systemctl enable my-db.service

Systemd-таймеры и задания cron, могут, в заданное время, вызывать выполнение различных действий в системе. Например — запуск скриптов командной оболочки или программ. Таймеры могут срабатывать, например, раз в день, причём — только по понедельникам. Ещё один пример — срабатывание таймера каждые 15 минут в рабочее время (с 8 утра до 6 вечера). Но таймеры systemd могут кое-что такое, что недоступно заданиям cron. Например, таймер может вызвать скрипт или программу через заданное время после некоего события. Таким событием может быть загрузка системы или запуск systemd, завершение предыдущей задачи или даже завершение работы сервиса, вызванного ранее по таймеру.

Получить список всех таймеров в системе

systemctl status *timer

Таймеры systemd обладают другими возможностями, которых нет у заданий cron, «одноразовых» или повторяющихся, которые вызываются только с привязкой к реальному времени и к реальным датам. Таймеры systemd можно настроить так, чтобы они вызывались бы на основании изменения состояния других юнитов systemd. Например, таймер можно настроить так, чтобы он срабатывал бы через заданное время после загрузки системы, после входа в неё пользователя, или через заданное время после активации определённого сервиса. Такие таймеры называют монотонными (monotonic). Эти таймеры сбрасываются после каждой перезагрузки системы.

Таймеры systemd можно использовать для решения тех же задач, которые решают с помощью заданий cron. Но systemd даёт больше гибкости в плане настройки календарных и монотонных таймеров.

Система инициализации Systemd имеет собственный распознаватель systemd-resolved, который запускается по умолчанию. Указываем systemd-resolved IP-адреса DNS-серверов, для разрешения доменных имен:

nano /etc/systemd/resolved.conf
[Resolve]
DNS=8.8.8.8 8.8.8.4 1.1.1.1

Для применения изменеий выполните

systemctl restart systemd-resolved.service

Утилиты не использующие библиотечные вызовы, обращаются к DNS-серверам напрямую из файла /etc/resolv.conf.

Команда systemd-resolve была переименована в resolvectl. Чтобы посмотреть состояние службы запустите команду

resolvectl status

Команда systemd-analyze blame в Linux показывает список служб и программ, запускаемых при загрузке системы, в порядке убывания времени, которое каждая из них занимает для завершения. Это позволяет идентифицировать процессы, которые могут замедлять загрузку системы, и оптимизировать их при необходимости.

~# systemd-analyze blame
13.832s systemd-networkd-wait-online.service
 6.071s geoipupdate.service
 2.396s redis-server.service
 1.975s postfix@-.service
 1.497s certbot.service
 1.348s apt-daily.service
 1.051s logrotate.service
  874ms apt-daily-upgrade.service
  611ms mariadb.service
  423ms dev-sda3.device
  393ms networkd-dispatcher.service
  383ms fstrim.service
  377ms php8.1-fpm.service
  352ms man-db.service
  349ms ufw.service
  333ms phpsessionclean.service
  315ms dpkg-db-backup.service
  228ms nginx.service
...
PQ VPS сервера в 28+ странах.