Управление сервисами и юнитами systemd с помощью systemctl. В systemd существует три уровня (разновидности) действий, направленных на прекращение работы службы или любого другого юнита. Программные сторожевые таймеры

Systemd – менеджер системы и сервисов в операционной системе Linux. При разработке eго стремились спроектировать обратно совместимым со скриптами инициализации SysV init и предоставить полезные функции, такие, как параллельный запуск системных сервисов во время загрузки, активацию демонов по требованию, поддержку снепшотов состояния системы и логику управления сервисами, основанную на зависимостях. В CentOS 7 systemd заменяет Upstart как систему инициализации по умолчанию.

В этой статье мы рассмотрим процесс управления сервисами в systemd для пользователя CentOS 7. Эти знания будут полезны и в других дистрибутивах, ведь systemd уже давно используется в Fedora и планируется в Ubuntu 14.10 и Debian 8. Хорошо это или нет — оставим за кадром.

В процессе чтения статьи вы можете попробовать systemd на классических VPS и облачных VPS от Infobox. Мы стремимся своевременно добавлять поддержку современных ОС, чтобы вы могли использовать последние технологии для более эффективной работы. Сама идея написания статьи родилась после очередного вопроса пользователей об использовании сервисов в CentOS 7.

Введение

Systemd приносит концепцию юнитов systemd. Юниты представлены конфигурационными файлами, размещенными в одной из директорий:
  • /usr/lib/systemd/system/ – юниты из установленных пакетов RPM.
  • /run/systemd/system/ — юниты, созданные в рантайме. Этот каталог приоритетнее каталога с установленными юнитами из пакетов.
  • /etc/systemd/system/ — юниты, созданные и управляемые системным администратором. Этот каталог приоритетнее каталога юнитов, созданных в рантайме.
Юниты содержат информацию о системных сервисах, прослушиваемых сокетах, сохраненных снапшотах состояний системы и других обьектах, относящихся к системе инициализации.

Типы юнитов systemd:

  • .service – системный сервис
  • .target — группа юнитов systemd
  • .automoun t – точка автомонтирования файловой системы
  • .device – файл устройства, распознанного ядром
  • .mount – точка монтирования файловой системы
  • .path – файл или директория в файловой системе
  • .scope – процесс, созданный извне
  • .slice – группа иерархически организованных юнитов, управляющая системными процессами
  • .snapshot – сохраненное состояние менеджера systemd
  • .socket – сокет межпроцессного взаимодействия
  • .swap – Свап-устройство или свап-файл (файл подкачки)
  • .timer – таймер systemd

Основные функции systemd в CentOS 7

  • Активация, основанная на сокетах . Во время загрузки systemd прослушивает сокеты для всех системных сервисов, поддерживает этот тип активации и передает сокеты этим сервисам сразу после старта сервисов. Это позволяет systemd не только запускать сервисы параллельно, но также дает возможность перезапускать сервисы без потери любых отправленных им сообщений, пока сервисы были недоступны. Соответствующий сокет остается доступным и все сообщения выстраиваются в очередь.
  • Активация, основанная на D-Bus . Системные сервисы, использующие D–Bus для межпроцессного взаимодействия, могут быть запущены по требованию, когда клиентское приложение пытается связаться с ними.
  • Активация, основанная на девайсах . Системные сервисы, поддерживающие активацию, основанную на девайсах, могут быть запущены, когда определенный тип оборудования подключается или становится доступным.
  • Активация, основанная на путях . Системные сервисы могут поддерживать этот вид активации, если изменяется состояние папки или директории.
  • Снепшоты системных состояний . Система может сохранять состояние всех юнитов и восстанавливать предыдущее состояние системы.
  • Управление точками монтирования и автомонтирования . Systemd отслеживает и управляет точками монтирования и автомонтирования.
  • Агрессивная параллелизация Systemd запускает системные сервисы параллельно из-за использования активации, основанной на сокетах. В комбинации с сервисами, поддерживающими активацию по требованию, параллельная активация значительно уменьшает время загрузки системы.
  • Транзакционная логика активации юнитов . До активации и деактивации юнитов systemd вычисляет их зависимости, создает временную транзакцию и проверяет целостность этой транзакции. Если транзакция нецелостная, systemd автоматически пытается исправить ее и удалить не требующиеся задания из нее до формирования сообщения об ошибке.
  • Обратная совместимость с инициализацией SysV . SystemD полностью поддерживает скрипты инициализации SysV, как описано в спецификации Linux Standard Base (LSB), что упрощает переход на systemd.

Управление сервисами

В предыдущих версиях CentOS использовалась SysV или Upstart. Скрипты инициализации располагались в директории /etc/rc.d/init.d/ . Такие скрипты обычно писались на Bash и позволяли администратору управлять состоянием сервисов и демонов. В CentOS 7 скрипты инициализации были заменены сервисными юнитами.

По способу использования сервисные юниты .service напоминают скрипты инициализации. Для просмотра, старта, остановки, перезагрузки, включения или выключения системных сервисов используется команда systemctl . Команды service и chkconfig по-прежнему включены в систему, но только по соображениям совместимости.


При использовании systemctl указывать расширение файла не обязательно.

Ниже представлены основные команды systemctl :

  • systemctl start name.service – запуск сервиса.
  • systemctl stop name.service — остановка сервиса
  • systemctl restart name.service — перезапуск сервиса
  • systemctl try-restart name.service — перезапуск сервиса только, если он запущен
  • systemctl reload name.service — перезагрузка конфигурации сервиса
  • systemctl status name.service — проверка, запущен ли сервис с детальным выводом состояния сервиса
  • systemctl is-active name.service — проверка, запущен ли сервис с простым ответом: active или inactive
  • systemctl list-units --type service --all – отображение статуса всех сервисов
  • systemctl enable name.service – активирует сервис (позволяет стартовать во время запуска системы)
  • systemctl disable name.service – деактивирует сервис
  • systemctl reenable name.service – деактивирует сервис и сразу активирует его
  • systemctl is–enabled name.service – проверяет, активирован ли сервис
  • systemctl list-unit-files --type service – отображает все сервисы и проверяет, какие из них активированы
  • systemctl mask name.service – заменяет файл сервиса симлинком на /dev/null, делая юнит недоступным для systemd
  • systemctl unmask name.service – возвращает файл сервиса, делая юнит доступным для systemd

Работаем с целями (targets) Systemd

Предыдущие версии CentOS с SysV init или Upstart включали предопределенный набор уровней запуска (runlevels), которые представляли специфичные режимы для операций, пронумерованные от 0 до 6. В CentOS 7 концепция уровней запуска была заменена целями systemd.

Файлы целей systemd .target предназначены для группировки вместе других юнитов systemd через цепочку зависимостей. Например юнит graphical.target , использующийся для старта графической сессии, запускает системные сервисы GNOME Display Manager (gdm.service ) и Accounts Service (accounts–daemon.service ) и активирует multi–user.target . В свою очередь multi–user.target запускает другие системные сервисы, такие как Network Manager (NetworkManager.service ) или D-Bus (dbus.service ) и активирует другие целевые юниты basic.target .

В CentOS 7 присутствуют предопределенные цели, похожие на стандартный набор уровней запуска. По соображениям совместимости они также имеют алиасы на эти цели, которые напрямую отображаются в уровнях запуска SysV.

  • poweroff.target (runlevel0.target) – завершение работы и отключение системы
  • rescue.target (runlevel1.target) – настройка оболочки восстановления
  • multi–user.target (runlevel2.target, runlevel3.target, runlevel4.target) – настройка неграфической многопользовательской системы
  • graphical.target (runlevel5.target) – настройка графической многопользовательской системы
  • reboot.target (runlevel6.target) – выключение и перезагрузка системы
Команды runlevel и telinit по-прежнему доступны, но оставлены в системе по соображениям совместимости. Рекомендуется использовать systemctl для изменения или настройки системных целей.

Для определения, какой целевой юнит используется по умолчанию, полезна следующая команда: systemctl get–default .

Для просмотра всех загруженных целевых юнитов воспользуйтесь командой systemctl list-units --type target , а для просмотра вообще всех целевых юнитов командой: systemctl list-units --type target --all .

Для изменения цели по умолчанию поможет команда systemctl set-default name.target .

Для изменения текущей цели: systemctl isolate name.target . Команда запустит целевой юнит и все его зависимости и немедленно остановит все остальные.

В CentOS 7 systemctl заменяет значительное количество команд управления питанием. Прежние команды сохранены для совместимости, но рекомандуется использовать systemctl:
systemctl halt – останавливает систему
systemctl poweroff – выключает систему
systemctl reboot – перезагружает систему

Управление systemd на удаленной машине

Systemd позволяет управлять удаленной машиной по SSH. Для управления используйте команду:
systemctl --host user_name@host_name command , где user_name – имя пользователя, host_name – имя хоста, которым осуществляется удаленное управление, а command – выполняемая команда systemd.

Типичный systemd .service

Этот раздел поможет вам, если вам необходимо быстро сделать поддержку управления сервисом из systemd. Подробная информация о всех параметрах файла.service есть в соответствующем разделе документации по systemd.

Description=Daemon to detect crashing apps After=syslog.target ExecStart=/usr/sbin/abrtd Type=forking WantedBy=multi-user.target
Давайте посмотрим на секцию . Она содержит общую информацию о сервисе. Такая секция есть не только в сервис-юнитах, но и в других юнитах (например при управлении устройствами, точками монтирования и т.д.). В нашем примере мы даем описание сервиса и указываем на то, что демон должен быть запущен после Syslog.

В следующей секции непосредственно содержится информация о нашем сервисе. Используемый параметр ExecStart указывает на исполняемый файл нашего сервиса. В Type мы указываем, как сервис уведомляет systemd об окончании запуска.

Финальная секция содержит информацию о цели, в которой сервис должен стартовать. В данном случае мы говорим, что сервис должен быть запущен, когда будет активирована цель multi–user.target .

Это минимальный работающий файл сервиса systemd. Написав свой, для тестирования скопируйте его в /etc/systemd/system/имя_сервиса.service. Выполните команды systemctl daemon-reload . Systemd узнает о сервисе и вы сможете его запустить.

Дополнительная информация

Отличное руководство по systemd от RedHat , положенное в основу этой статьи.
Документация по написанию своего сервис-юнита systemd .
«Systemd для администраторов» от разработчика systemd на русском языке.

Заключение

В этой статье мы научились управлять сервисами CentOS 7. Конечно, это далеко не единственная функция systemd и другие ее стороны будут рассмотрены в будущем. Сама ОС практически со времени релиза доступна на классических VPS и облачных VPS от Infobox. Попробуйте systemd прямо сейчас. Эти знания будут полезны в связи с переходом многих дистрибутивов на systemd.

Если вы обнаружили ошибку в статье, автор ее с удовольствием исправит. Пожалуйста напишите в ЛС или на почту о ней.
В случае, если вы не можете оставлять комментарии на Хабре, можно написать их в блоге

В операционной системе linux, так же как и в Windows, кроме обычных программ, которые могут взаимодействовать с пользователем есть еще один вид программ. Это работающие в фоне службы. Важность служб тяжело переоценить, они следят за состоянием системы, обеспечивают автоматическое подключение внешних устройств и сети, позволяют процессам взаимодействовать с оборудованием (dbus), а также в виде служб реализованы различные веб-серверы и серверы баз данных. В отличие от пользовательских программ, службы выполняются в фоне, и пользователь не имеет к ним прямого доступа. Пользователь еще не вошел в систему, только началась загрузка а основные службы уже запущенны и работают.

В этой статье мы рассмотрим управление службами Linux. Мы не будем трогать уже устаревшие системы, такие как SysVinit, сосредоточимся только на Systemd. Вы узнаете, как посмотреть запущенные службы linux, а также останавливать и запускать их самому.

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

Но потом на смену этому методу пришла новая модель и система инициализации systemd. Система инициализации запускается сразу после загрузки ядра и начинает инициализировать службы, теперь появилась возможность параллельной инициализации, а также зависимостей между службами. Таким образом, теперь можно определить сложное дерево порядка запуска служб. Но мы не будем вникать в подробности создания служб, нас интересует только сам процесс запуска. После запуска systemd собирает весь вывод службы в лог, и следит за ее работой, если служба аварийно завершилась, то автоматически ее перезапускает.

Служба в Systemd описывается файлом юнита, в нем описано что с ней нужно делать и как себя вести. Существуют такие типы служб:

  • service - обычная служба, программа
  • target - группа служб
  • automount - точка автоматического монтирования
  • device - файл устройства, генерируется на этапе загрузки
  • mount - точка монтирования
  • path - файл или папка
  • scope - процесс
  • slice - группа системных служб systemd
  • snapshot - сохраненное состояние запущенных служб
  • socket - сокет для взаимодействия между процессами.

Нас будут интересовать только service, и совсем немного target, но мы рассмотрели все остальные, чтобы вы смогли взглянуть на картину немного шире. Основы рассмотрели, теперь будет настройка служб LInux.

Утилита systemctl

В Systemd есть специальный инструмент для управления службами в Linux - systemctl. Эта утилита позволяет делать очень много вещей, начиная от перезапуска службы linux и проверки ее состояния, до анализа эффективности загрузки службы. Синтаксис у утилиты такой:

$ systemctl опции команда служба служба...

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

Рассмотрим все по порядку. Опции очень сильно зависят от команд, поэтому рассмотрим их позже, а пока пройдемся по командах:

  • list-units - посмотреть все службы (юниты), аналог опции -t
  • list-sockets - посмотреть все службы сокетов
  • start - запустить службу linux
  • stop - остановить службу linux
  • reload - обновить конфигурацию службы из файла юнита
  • restart - перезапустить службу
  • try-restart - перезапустить службу, только если она запущена
  • reload-or-restart - обновить конфигурацию затем выполнить перезапуск службы linux, если не поддерживается - только перезапустить
  • isolate - запустить только одну службу вместе с ее зависимостями, все остальные остановить
  • kill - отправить сигнал завершения процессу используется вместе с опциями --signal и --kill-who
  • is-active - проверить запущена ли служба linux
  • is-failed - проверить не завершилась ли служба с ошибкой
  • status - посмотреть состояние и вывод службы
  • show - посмотреть параметры управления службой в Linux
  • reset-failed - перезапустить службы linux, завершившиеся с ошибкой
  • list-dependencies - посмотреть зависимости службы linux
  • list-unit-files - вывести все установленные файлы служб
  • enable - добавить службу в автозагрузку
  • disable - удалить службу из автозагрузки
  • is-enabled - проверить если ли уже служба в автозагрузке
  • reenable - сначала выполнить disable потом enable для службы
  • list-jobs - все запущенные службы linux независимо от типа
  • snapsot - сохранить состояние служб, чтобы потом восстановить
  • daemon-reload - обновить конфигурацию всех служб
  • mask - сделать юнит недоступным
  • unmask - вернуть файл службы linux

А теперь основные опции:

  • -t, --type - тип служб для вывода
  • -a, --all - показать все известные службы, даже не запущенные
  • -q - минимальный вывод
  • --version - версия программы
  • --no-pager - не использовать постраничную навигацию
  • --no-legend - не выводить подробное описание
  • -f - принудительное выполнение команды
  • --runtime - не сохранять вносимые изменения после перезагрузки
  • -n - количество строк вывода лога для команды status
  • --plain - использовать обычный текстовый режим вместо деревьев
  • --kill-who - задать процесс, которому нужно отправить сигнал
  • --signal - сигнал, который нужно отправить.
  • --state - отфильтровать список служб по состоянию.

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

Управление службами Linux

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

systemctl list-units --type service

Команда отобразила все службы, которые известны systemd, они сейчас запущены или были запущены. Программа не пересматривает все файлы, поэтому будут показаны только те службы, к которым уже обращались. Состояние loaded - означает, что конфигурационный файл был успешно загружен, следующая колонка active - служба была запущена, а running или exited значит выполняется ли сейчас служба или она успешно завершила свою работу. Листать список можно кнопками вверх/вниз.

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

systemctl list-units --type service -all

systemctl list-units --type service --state running

Или те, которые завершились с ошибкой:

systemctl list-units --type service --state failed

Для фильтрации можно брать любой показатель состояния из любой колонки. Другой командой мы можем посмотреть все файлы конфигурации служб на диске. Тут не будем фильтровать по типу, пусть программа покажет все:

systemctl list-unit-files

Теперь отфильтруем только службы linux:

systemctl list-unit-files --type service

Здесь вы тоже можете использовать фильтры по состоянию. Теперь вы знаете как посмотреть запущенные службы linux, идем дальше.

Чтобы запустить службу используется команда start, например:

sudo systemctl start application.service

Причем расширение service можно опустить, оно и так подставляется по умолчанию. Если запуск прошел хорошо, программа ничего не выведет.

Остановить службу linux можно командой:

sudo systemctl stop application

Посмотреть состояние службы позволяет команда status:

sudo systemctl status application

Здесь вы можете видеть, состояние running, exited, dead, failed и т д. А также несколько последних строчек вывода программы, которые очень помогут решить проблему с запуском если она возникнет.

Как вы знаете, systemd позволяет автоматически загружать службы при запуске системы по мере их надобности. Команда list-unit-files показывает добавлена ли служба в автозагрузку.

Вообще, здесь может быть несколько состояний - enabled - в автозагрузке, disabled - автозагрузка отключена, masked - служба скрыта и static - значит что служба в автозагрузке, но вы не можете ее отключить.

Поэтому чтобы получить список служб linux, запускаемых автоматически достаточно отфильтровать ее вывод по состоянию:

systemctl list-unit-files --state enabled

Все службы, запускаемые по умолчанию. Можете также посмотреть службы static. Чтобы добавить службу в автозагрузку linux используйте команду enable:

sudo systemctl enable application

А для того чтобы убрать ее из автозагрузки.

В systemd существует три уровня (разновидности) действий, направленных на прекращение работы службы или любого другого юнита.

* Вы можете остановить службу, то есть прекратить выполнение уже запущенных процессов службы. При этом сохраняется возможность ее последующего запуска, как ручного (через команду systemctl start), так и автоматического (при загрузке системы, при поступлении запроса через сокет или системную шину, при срабатывании таймера, при подключении соответствующего оборудования и т.д.).
Таким образом, остановка службы является временной мерой, не дающей никаких гарантий на будущее.
В качестве примера рассмотрим остановку службы NTPd, отвечающей за синхронизацию времени по сети:


systemctl stop ntpd.service

Аналогом этой команды в классическом SysV init является


service ntpd stop

Заметим, что в Fedora 15, использующей в качестве системы инициализации systemd, в целях обеспечения обратной совместимости допускается использование классических SysV-команд, и systemd будет корректно воспринимать их. В частности, вторая приведенная здесь команда будет эквивалентна первой.

* Вы можете отключить службу, то есть отсоединить ее от всех триггеров активации. В результате служба уже не будет автоматически запускаться ни при загрузке системы, ни при обращении к сокету или адресу на шине, ни при подключении оборудования, и т.д. Но при этом сохраняется возможность «ручного» запуска службы командой systemctl start. Обратите внимание, что при отключении уже запущенной службы, ее выполнение в текущем сеансе не останавливается - это нужно сделать отдельно, иначе процессы службы будут работать до момента выключения системы (но при следующем включении, разумеется, уже не запустятся).
Рассмотрим отключение службы на примере все того же NTPd:



В классических SysV-системах аналогичная команда будет иметь вид


chkconfig ntpd off

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


systemctl disable ntpd.service
systemctl stop ntpd.service

Подобное сочетание команд используется, например, при деинсталляции пакетов в Fedora. Обратите внимание, что отключение службы является перманентной мерой, и действует вплоть до явной отмены соответствующей командой. Перезагрузка системы не отменяет отключения службы.

* Вы можете заблокировать (замаскировать) службу. Действие этой операции аналогично отключению, но дает более сильный эффект. Если при отключении отменяется только возможность автоматического запуска службы, но сохраняется возможность ручного запуска, то при блокировке исключаются обе эти возможности. Отметим, что использование данной опции при непонимании принципов ее работы может привести к трудно диагностируемым ошибкам.
Тем не менее, рассмотрим пример блокировки все той же службы NTPd:


ln -s /dev/null /etc/systemd/system/ntpd.service
systemctl daemon-reload

Итак, блокировка сводится к созданию символьной ссылки с именем соответствующей службы, указывающей на /dev/null.
Прим. перев.: Впоследствии в программу systemctl была добавлена поддержка команд mask и unmask, упрощающих процесс блокирования и разблокирования юнитов. Например, для блокирования службы ntpd.service теперь достаточно команды systemctl mask ntpd.service. Фактически она сделает то же самое, что и приведенная выше команда ln.
После такой операции служба не может быть запущена ни вручную, ни автоматически. Символьная ссылка создается в каталоге /etc/systemd/system/, а ее имя должно соответствовать имени файла описания службы из каталога /lib/systemd/system/ (в нашем случае ntpd.service).

Заметим, что systemd читает файлы конфигурации из обоих этих каталогов, но файлы из /etc (управляемые системным администратором) имеют
приоритет над файлами из /lib (которые управляются пакетным менеджером). Таким образом, создание символьной ссылки (или обычного файла)
/etc/systemd/system/ntpd.service предотвращает чтение штатного файла конфигурации /lib/systemd/system/ntpd.service.
В выводе systemctl status заблокированные службы отмечаются словом masked. Попытка запустить такие службы командой systemctl start завершится ошибкой.
В рамках классического SysV init, штатная реализация такой возможности отсутствует. Похожий эффект может быть достигнут с помощью «костылей», например, путем добавления команды exit 0 в начало init-скрипта. Однако, подобные решения имеют ряд недостатков, например, потенциальная возможность конфликтов с пакетным менеджером (при очередном обновлении исправленный скрипт может быть просто затерт соответствующим файлом из пакета).

Стоит отметить, что блокировка службы, как и ее отключение, является перманентной мерой.
Прим. перев.: Подробно описав принцип работы блокировки службы (юнита), автор забывает привести практические примеры ситуаций, когда эта возможность оказывается полезной. В частности, иногда бывает необходимо полностью предотвратить запуск службы в любой ситуации. При этом не стоит забывать, что в post-install скриптах пакетного менеджера или, скажем, в заданиях cron, вместо systemctl try-restart (service condrestart) может быть ошибочно указано systemctl restart (service restart), что является прямым указанием на запуск службы, если она еще не запущена. Вследствие таких ошибок, отключенная служба может «ожить» в самый неподходящий момент.

После прочтения изложенного выше, у читателя может возникнуть вопрос: как отменить произведенные изменения? Что ж, ничего сложного тут нет: systemctl start отменяет действия systemctl stop, systemctl enable отменяет действие systemctl disable, а rm отменяет действие ln.

Systemd – это система инициализации и системный менеджер, который становится новым стандартом для Linux-машин. Споры о продуктивности systemd по сравнению с традиционными системами инициализации SysV ведутся до сих пор, тем не менее, эту систему планируют внедрить большинство дистрибутивов, а многие уже сделали это.

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

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

Управление сервисами

Основная цель init-системы – инициализировать компоненты, которые должны запускаться после загрузки ядра Linux (традиционно они называются «пользовательскими» компонентами). Система инициализации также используется для управления сервисами и демонами сервера. Имея это в виду, начнем знакомство с systemd с простых операций управления сервисами.

В systemd целью большинства действий являются юниты – ресурсы, которыми systemd может управлять. Юниты делятся на категории по типам ресурсов, которые они представляют. Юниты определяются в так называемых юнит-файлах. Тип каждого юнита можно определить по суффиксу в конце файла.

Для задач управления сервисами предназначены юнит-файлы с суффиксом.service. Однако в большинстве случаев суффикс.service можно опустить, так как система systemd достаточно умна, чтобы без суффикса определить, что нужно делать при использовании команд управления сервисом.

Запуск и остановка сервиса

Чтобы запустить сервис systemd, используйте команду start. Если вы работаете не в сессии пользователя root, вам нужно использовать sudo, поскольку эта команда повлияет на состояние операционной системы:

sudo systemctl start application.service

Как уже говорилось ранее, systemd знает, что для команд управления сервисами нужно искать файлы *.service, поэтому эту команду можно ввести так:

sudo systemctl start application

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

Чтобы остановить сервис, достаточно ввести команду stop:

sudo systemctl stop application.service

Перезапуск и перезагрузка

Чтобы перезапустить сервис, используйте restart:

sudo systemctl restart application.service

Если указанное приложение может перезагрузить свои конфигурационные файлы (без перезапуска), можно использовать reload:

sudo systemctl reload application.service

Если вы не знаете, может ли сервис перезагрузить свои файлы, используйте команду reload-or-restart. Она перезагрузит сервис, а если это невозможно – перезапустит его.

sudo systemctl reload-or-restart application.service

Включение и отключение сервисов

Приведенные выше команды необходимы при работе с сервисом в текущей сессии. Чтобы добавить сервис в автозагрузку systemd, его нужно включить.

Для этого существует команда enable:

sudo systemctl enable application.service

Это создаст символическую ссылку на копию файла сервиса (обычно в /lib/systemd/system или /etc/systemd/system) в точке на диске, где systemd ищет файлы для автозапуска (обычно /etc/systemd/system/some_target.target.want, подробнее об этом — дальше в руководстве).

Чтобы убрать сервис из автозагрузки, нужно ввести:

sudo systemctl disable application.service

Имейте в виду, что включение сервиса не запускает его в текущей сессии. Если вы хотите запустить сервис и включить его в автозагрузку, вам нужно запустить команды start и enable.

Проверка состояния сервиса

Чтобы проверить состояние сервиса, введите:

systemctl status application.service

Эта команда выведет состояниесервиса, иерархию групп и первые несколько строк лога.

Например, при проверке состояния сервера Nginx вы можете увидеть такой вывод:

nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2015-01-27 19:41:23 EST; 22h ago
Main PID: 495 (nginx)
CGroup: /system.slice/nginx.service
├─495 nginx: master process /usr/bin/nginx -g pid /run/nginx.pid; error_log stderr;
└─496 nginx: worker process
Jan 27 19:41:23 desktop systemd: Starting A high performance web server and a reverse proxy server...
Jan 27 19:41:23 desktop systemd: Started A high performance web server and a reverse proxy server.

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

Существуют также методы проверки конкретных состояний. Например, чтобы проверить, активен ли данный юнит (запущен ли он), вы можете использовать команду is-active:

systemctl is-active application.service

Это отобразит текущее состояние юнита, обычно это active или inactive. Код завершения будет «0», если юнит активен, что упрощает процесс анализа.

Чтобы узнать, включен ли юнит, вы можете использовать команду is-enabled:

systemctl is-enabled application.service

Эта команда сообщит, включен ли сервис, и снова определит код завершения как «0» или «1» в зависимости от результата.

Третья команда позволяет определить, находится ли юнит в состоянии сбоя. Это указывает на то, что возникла проблема с запуском рассматриваемого юнита:

systemctl is-failed application.service

Команда вернет active, если юнит работает правильно, и failed, если случилась ошибка. Если юнит был остановлен намеренно, команда может вернуть unknown или inactive. Код завершения «0» означает, что произошел сбой, а «1» указывает на любое другое состояние.

Обзор состояния системы

Ранее мы рассмотрели команды, необходимые для управления отдельными сервисами, но они не очень полезны для изучения текущего состояния системы. Существует несколько команд systemctl, которые предоставляют эту информацию.

Просмотр списка текущих юнитов

Чтобы запросить список текущих юнитов systemd, используйте команду list-units:

systemctl list-units

Эта команда покажет список всех юнитов, которые в настоящее время существуют в системе systemd. Результат будет выглядеть примерно так:

UNIT LOAD ACTIVE SUB DESCRIPTION
atd.service loaded active running ATD daemon
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
dbus.service loaded active running D-Bus System Message Bus
dcron.service loaded active running Periodic Command Scheduler
dkms.service loaded active exited Dynamic Kernel Modules System
[email protected] loaded active running Getty on tty1
. . .

В выводе есть такие столбцы:

  • UNIT – название юнита systemd.
  • LOAD – сообщает, была ли конфигурация юнита обработана systemd. Конфигурация загруженных юнитов хранится в памяти.
  • ACTIVE – сводное состояние юнита. Обычно это позволяет быстро определить, успешно ли запущен текущий юнит.
  • SUB: состояние более низкого уровня, которое сообщает подробную информацию об устройстве. Это часто зависит от типа юнита, состояния и фактического метода, в котором запущен юнит.
  • DESCRIPTION – краткое описание функций юнита.

Поскольку команда list-units показывает по умолчанию только активные юниты, все вышеперечисленные записи будут показывать loaded в столбце LOAD и active в столбце ACTIVE. Такой формат является поведением systemctl по умолчанию при вызове без дополнительных команд, поэтому вы увидите то же самое, если вы вызываете systemctl без аргументов:

С помощью systemctl можно запрашивать различную информацию путем добавления флагов. Например, чтобы увидеть все юниты, которые загрузила (или попыталась загрузить) система systemd, независимо от того, активны ли они в данный момент, вы можете использовать флаг -all:

systemctl list-units --all

Эта команда сообщит о юнитах, которые загрузила или попыталась загрузить система systemd, независимо от их текущего состояния. После запуска некоторые юниты становятся неактивными, а юниты, которые пыталась загрузить systemd, не были найдены на диске.

Вы можете использовать другие флаги для фильтрации результатов. Например, флаг —state= можно использовать для определения состояний LOAD, ACTIVE или SUB. Флаг —all нужно оставить, чтобы система отображала неактивные юниты:

systemctl list-units --all --state=inactive

Еще один популярный фильтр – это —type=. Он позволяет отфильтровать юниты по типу. К примеру, чтобы запросить только активные юниты, можно ввести:

systemctl list-units --type=service

Список юнит-файлов

Команда list-units отображает только юниты, которые система systemd попыталась обработать и загрузить в память. Поскольку systemd избирательно читает только те юнит-файлы, которые кажутся ей необходимыми, список не будет включать все доступные юнит-файлы. Чтобы просмотреть список всех доступных юнит-файлов (включая те, что systemd не пыталась загрузить), используйте команду list-unit-files.

systemctl list-unit-files

Юниты являются представлениями ресурсов, о которых знает systemd. Поскольку systemd не обязательно читает все определения юнитов, она представляет только информацию о самих файлах. Вывод состоит из двух столбцов: UNIT FILE и STATE.

UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
dev-hugepages.mount static
dev-mqueue.mount static
proc-fs-nfsd.mount static
proc-sys-fs-binfmt_misc.mount static
sys-fs-fuse-connections.mount static
sys-kernel-config.mount static
sys-kernel-debug.mount static
tmp.mount static
var-lib-nfs-rpc_pipefs.mount static
org.cups.cupsd.path enabled
. . .

Обычно столбец STATE содержит значения enabled, disabled, static или masked. В этом контексте static означает, что в юнит-файле нет раздела install, который используется для включения юнита. Таким образом, эти юниты невозможно включить. Обычно это означает, что юнит выполняет одноразовое действие или используется только как зависимость другого юнита и не должен запускаться сам по себе.

Управление юнитами

Теперь вы знаете, как работать с сервисами и отображать информацию о юнитах и юнит-файлах, о которых знает systemd. Получить более конкретную информацию о юнитах можно с помощью некоторых дополнительных команд.

Отображение юнит-файла

Чтобы отобразить юнит-файл, который загрузила systemd, вы можете использовать команду cat (была добавлена в версии systemd 209). Например, чтобы увидеть юнит-файл демона планирования atd, можно ввести:

systemctl cat atd.service
Description=ATD daemon
Type=forking
ExecStart=/usr/bin/atd
WantedBy=multi-user.target

На экране вы увидите юнит-файл, который известен текущему запущенному процессу systemd. Это может быть важно, если вы недавно изменяли файлы модулей или если вы переопределяете некоторые параметры в фрагменте юнит-файла (об этом поговорим позже).

Отображение зависимостей

Чтобы просмотреть дерево зависимостей юнита, используйте команду:

systemctl list-dependencies sshd.service

Она отобразит иерархию зависимостей, с которыми системе необходимо иметь дело, чтобы запустить этот юнит. Зависимости в этом контексте – это те юниты, которые требуются для работы других юнитов, которые находятся выше в иерархии.

sshd.service
├─system.slice
└─basic.target
├─microcode.service
├─rhel-autorelabel-mark.service
├─rhel-autorelabel.service
├─rhel-configure.service
├─rhel-dmesg.service
├─rhel-loadmodules.service
├─paths.target
├─slices.target
. . .

Рекурсивные зависимости отображаются только для юнитов.target, которые указывают состояния системы. Чтобы рекурсивно перечислить все зависимости, добавьте флаг —all.

Чтобы показать обратные зависимости (юниты, зависящие от указанного элемента), вы можете добавить в команду флаг —reverse. Также полезными являются флаги —before и —after, они отображают юниты, которые зависят от указанного юнита и запускаются до или после него.

Проверка свойств юнита

Чтобы увидеть низкоуровневые свойства юнита, вы можете использовать команду show. Это отобразит список свойств указанного юнита в формате ключ=значение.

systemctl show sshd.service
Id=sshd.service
Names=sshd.service
Requires=basic.target
Wants=system.slice
WantedBy=multi-user.target
Conflicts=shutdown.target
Before=shutdown.target multi-user.target
After=syslog.target network.target auditd.service systemd-journald.socket basic.target system.slice
Description=OpenSSH server daemon
. . .

Чтобы отобразить одно из свойтсв, передайте флаг –р и укажите имя свойства. К примеру, чтобы увидеть конфликты юнита sshd.service, нужно ввести:

systemctl show sshd.service -p Conflicts
Conflicts=shutdown.target

Маскировка юнитов

Systemd может блокировать юнит (автоматически или вручную), создавая симлинк на /dev/null. Это называется маскировкой юнитов и выполняется командой mask:

sudo systemctl mask nginx.service

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

Если вы проверите list-unit-files, вы увидите, что сервис отмечен как masked:

systemctl list-unit-files
. . .
kmod-static-nodes.service static
ldconfig.service static
mandb.service static
messagebus.service static
nginx.service masked
quotaon.service static
rc-local.service static
rdisc.service disabled
rescue.service static
. . .

Если вы попробуете запустить сервис, вы получите такое сообщение:

sudo systemctl start nginx.service
Failed to start nginx.service: Unit nginx.service is masked.

Чтобы раскрыть (разблокировать) юнит и сделать его доступным, используйте unmask:

sudo systemctl unmask nginx.service

Это вернет сервис в его прежнее состояние.

Редактирование юнит-файлов

Хотя конкретный формат юнит-файлов не рассматривается в данном руководстве, systemctl предоставляет встроенные механизмы для редактирования и изменения юнит-файлов. Эта функциональность была добавлена в systemd версии 218.

Команда edit по умолчанию открывает сниппет юнит-файла:

sudo systemctl edit nginx.service

Это будет пустой файл, который можно использовать для переопределения или добавления директив в определение юнита. В каталоге /etc/systemd/system будет создан каталог, который содержит имя устройства с суффиксом.d. Например, для nginx.service будет создан каталог nginx.service.d.

Внутри этого каталога будет создан сниппет с именем override.conf. Когда юнит загружается, systemd объединит в памяти сниппет для переопределения с остальным юнит-файлом. Директивы сниппета будут иметь приоритет над теми, что указаны в исходном юнит-файле.

Если вы хотите отредактировать весь юнит-файл вместо создания сниппета, вы можете передать флаг —full:

sudo systemctl edit --full nginx.service

Это загрузит текущий юнит-файл в редактор, где его можно будет изменить. Когда редактор закроется, измененный файл будет записан в /etc/systemd/system и будет иметь приоритет над определением юнита системы (обычно он находится где-то в /lib/systemd/system).

Чтобы удалить все сделанные вами дополнения, удалите каталог конфигурации.d или измененный файл сервиса из /etc/systemd/system. Например, чтобы удалить сниппет, можно ввести:

sudo rm -r /etc/systemd/system/nginx.service.d

Чтобы удалить полный отредактированный файл, введите:

sudo rm /etc/systemd/system/nginx.service

После удаления файла или каталога нужно перезагрузить процесс systemd, чтобы система больше не пыталась ссылаться на эти файлы и вернулась к использованию системных копий. Для этого введите:

sudo systemctl daemon-reload

Изменение уровней запуска

Цели – это специальные юнит-файлы, которые описывают уровни системы или точки синхронизации. Как и другие юниты, файлы целей можно определить по суффиксу. В данном случае используется суффикс.target. Сами по себе цели ничего не делают, вместо этого они используются для группировки других юнитов.

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

Например, есть цель swap.target, которая используется для того, что чтобы сообщить, что swap готов к использованию. Юниты, которые являются частью этого процесса, могут синхронизироваться с этой целью при помощи директив WantedBy= или RequiredBy=. Юниты, которым нужен своп, могут указывать это условие через спецификации Wants=, Requires= или After=.

Проверка и настройка целей по умолчанию

Процесс systemd имеет цель по умолчанию, которую он использует при загрузке системы. Обеспечение ряда зависимостей этой единственной цели приводит систему в желаемое состояние. Чтобы найти цель по умолчанию, введите:

systemctl get-default
multi-user.target

Если вы хотите установить другую цель по умолчанию, вы можете использовать set-default. Например, если у вас установлен графический рабочий стол и вы хотите, чтобы система загружала его по умолчанию, вы можете соответствующим образом изменить цель:

sudo systemctl set-default graphical.target

Список доступных целей

Просмотреть список доступных целей можно с помощью команды:

systemctl list-unit-files --type=target

В отличие от уровней запуска, одновременно можно включать несколько целей. Активная цель указывает, что systemd будет пытаться запустить все юниты, привязанные к этой цели, и не попытается их отключить. Чтобы увидеть все активные цели, введите:

systemctl list-units --type=target

Изоляция целей

Можно запустить все юниты, связанные с целью, и остановить все юниты, которые не являются частью дерева зависимостей. Для этого используется команда isolate. Она похожа на изменение уровня запуска в других системах инициализации.

Например, если вы работаете в графической среде, где активна цель graphical.target, вы можете отключить графическую систему и перевести систему в состояние многопользовательской командной строки, изолировав multi-user.target. Поскольку graphical.target зависит от multi-user.target, но не наоборот, все графические юниты будут остановлены.

Вы можете взглянуть на зависимости изолируемой цели, прежде чем выполнять эту процедуру, чтобы убедиться, что вы не останавливаете жизненно важные сервисы:

systemctl list-dependencies multi-user.target

Если вас все устраивает, можете изолировать цель:

sudo systemctl isolate multi-user.target

Сокращения

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

К примеру, чтобы перевести систему в режим отладки, можно ввести просто rescue вместо isolate rescue.target:

sudo systemctl rescue

Это обеспечит дополнительную функциональность – оповестит всех пользователей системы о событии.

Чтобы остановить систему, вы можете использовать команду halt:

sudo systemctl halt

Чтобы начать полное завершение работы, вы можете использовать команду poweroff:

sudo systemctl poweroff

Перезапуск можно начать с помощью команды reboot:

sudo systemctl reboot

Эти команды сообщат пользователям системы о событиях, чего не сделает стандартная команда. Обратите внимание, большинство машин используют более короткие команды для этих операций, чтобы они работали правильно с systemd.

Например, чтобы перезагрузить систему, вы можете ввести просто:

Заключение

Теперь вы знакомы с основными механизмами systemctl и знаете, как управлять системой инициализации с помощью этого инструмента.

Хотя systemctl работает в основном с процессом systemd, в системе systemd есть другие компоненты, которые контролируются другими утилитами. К примеру, для управления логированием и пользовательскими сеансами используются отдельные демоны и утилиты (journald/journalctl и logind/loginctl соответственно).

В systemd, в отличие от классической системы инициализации sysv initd, вместо shell-скриптов для запуска сервисов используются специальные service-файлы. service-файлы являются подтипом более общих файлов инициализации systemd - юнит-файлов. юнит-файлы позволяют запускать не только файлы сервисов, но и создавать Unix-сокеты, обрабатывать события от устройств и т.п.

Безусловно, shell-скрипты обладают большей гибкостью, однако большинство операций, выполняемых shell-скриптами инициализации сервисов, не отличаются оригинальностью и довольно громоздки. service-файлы позволяют описывать типовые операции во много раз проще.

Системные service-файлы, установленные средствами пакетного менеджера, располагаются в каталоге /lib/systemd/system/. Пользовательские service-файлы располагаются в каталоге /etc/systemd/system/. Они имеют приоритет над системными. Если нужно изменить системный service-файл, достаточно скопировать его в каталог пользовательских service-файлов и отредактировать необходимым образом.

1. Формат service-файла

Service-файл является файлом в формате INI и состоит из трёх разделов, имена которых берутся в квадратные скобки. После строки с именем раздела следуют строки с параметрами, специфичными для данного раздела. Рассмотрим основные параметры каждого раздела.

  • Раздел Unit

    Этот раздел содержит общую информацию о сервисе, устройстве, точке монтирования и т.п.

    Description - строка описания.

    After - указывает, что этот сервис должен запускаться после указанного. Эта директива не описывает зависимость, для описания зависимостей используется директива Require .

  • Раздел Service

    Содержит информацию, специфичную для описания сервиса.

    ExecStart - путь к демону и аргументы демона для его запуска. При указании минуса перед строкой команды systemd не будет запоминать код завершения процесса.

    Type - определяет, каким образом systemd будет отслеживать, запустился ли сервис.

    • forking - запущенный процесс порождает другой процесс, а сам завершается. systemd считает сервис запущенным, когда завершается запущенный процесс. Главным процессом сервиса считается порождённый процесс.
    • dbus - после запуска сервис зарегистрируется на шине Dbus под именем, указанным в настройке BusName. systemd сможет отслеживать состояние сервиса через Dbus.
    BusName - имя сервиса, под которым он зарегистрируется на шине Dbus. Эта директива используется в том случае, когда директива Type принимает значение dbus .

    Restart - директива указывает на способ перезапуска сервиса в случае его падения.

    • restart-always - при падении перезапускать сервис всегда.
    EnvironmentFile - позволяет задать файл с переменными окружения для сервиса. В файле допускается указывать только определения переменных.
  • Раздел Install

    WantedBy - описывает, в каких случаях юнит должен быть активирован.

Пример простейшего service-файла уже был приведён в прошлой заметке:
Description=openntpd After=network.target Type=simple ExecStart=/usr/sbin/ntpd -dsf /etc/openntpd/ntpd.conf ExecStartPost=/bin/chown ntpd /var/lib/openntpd/ntpd.drift ExecStop=/sbin/hwclock -w WantedBy=multi-user.target 2. Экземпляры сервисов

Большинство сервисов запускается в единственном экземпляре, однако существуют и сервисы, которые необходимо запустить в нескольких экземплярах. Для того, чтобы не создавать отдельный service-файл для каждого экземпляра сервиса, в systemd была реализована поддержка шаблонов сервисов. Шаблон многоэкземплярного сервиса содержит символ @ в имени service-файла. Перед этим символом в имени service-файла указывается имя многоэкземплярного сервиса.

Когда возникает необходимость создать дополнительный экземпляр сервиса на основе шаблона, в каталоге /etc/systemd/system/*.wants создаётся символическая ссылка на шаблон. Имя символической ссылки совпадает с именем шаблона, но после символа @ добавляется идентификатор экземпляра сервиса. Для примера создадим экземпляр сервиса serial-getty на последовательном порту /dev/ttyS2 (команда systemctl enable для экземпляров сервисов в Debian Wheezy не поддерживается):
# systemctl start [email protected] # mkdir /etc/systemd/system/getty.target.wants/ # ln -s /lib/systemd/system/[email protected] /etc/systemd/system/getty.target.wants/[email protected] Идентификатор экземпляра сервиса подставляется в шаблон service-файла на место следующих символов-заменителей:
%I - идентификатор экземпляра сервиса подставляется в шаблон как есть,
%i - идентификатор экземпляра сервиса подставляется в шаблон в экранированном виде. Это бывает нужно, если идентификатором экземпляра сервиса является путь к устройству, содержащий косые черты. Чтобы использовать этот путь в имени юнит-файла устройства (dev-%i.device), нужно заэкранировать все специальные символы.

Что делать, если один из экземпляров сервиса нужно запустить с какими-то индивидуальными настройками, не совпадающими с шаблонными? В этом случае можно просто создать для экземпляра сервиса индивидуальный service-файл, в котором и указать необходимые настройки. systemd, прежде чем использовать шаблоны сервисов, пытается найти service-файл с указанным именем. И только если найти такой файл не удалось, пытается воспользоваться шаблоном.

Например, если необходимы какие-то индивидуальные настройки для getty на tty2, достаточно создать service-файл /etc/systemd/system/[email protected] и прописать в него индивидуальные настройки. Символы-заменители продолжают действовать и внутри этого файла. Их полный список можно найти на странице руководства systemd.unit(5).

Пример шаблона service-файла [email protected]:
Description=Serial Getty on %I BindTo=dev-%i.device After=dev-%i.device systemd-user-sessions.service ExecStart=-/sbin/agetty -s %I 115200,38400,9600 Restart=always RestartSec=0 Полную версию файла можно посмотреть в реальной системе.

3. Запуск getty на консолях

Раз уж мы коснулись темы многоэкземплярных сервисов на примере getty, разберёмся в этом вопросе подробнее.

В systemd имеется два шаблона service-файлов для терминалов:
[email protected] - шаблон для запуска виртуальных терминалов, в переменной TERM используется значение linux,
[email protected] - шаблон для запуска терминалов на последовательных портах. в переменной TERM используется значение vt102. В этом шаблоне, в отличие от предыдущего, отсутствуют настройки для очистки буфера прокрутки, поскольку он попросту отсутствует.

Главное отличие systemd от SysV init заключается в том, что терминалы запускаются по запросу, а не при загрузке системы. Имеется только два исключения: консоль tty1 запускается автоматически, в графическом режиме на ней запускается дисплейный менеджер, а в текстовом - getty, консоль tty6 тоже запускается автоматически и на ней всегда запускается getty, чтобы всегда имелась хотя-бы одна текстовая консоль для решения различных проблем.

Настройки по умолчанию можно изменить в файле /etc/systemd/systemd-logind.conf (в руководстве был указан файл /etc/systemd/logind.conf):
NAutoVTs - количество терминалов, запускаемых автоматически (по умолчанию - 6),
ReserveVT - номер зарезервированной виртуальной консоли (по умолчанию - 6).

Если необходимо настроить последовательную консоль в качестве системной, нужно добавить к строке загрузки ядра дополнительную опцию: console=ttyS0 .

Для автоматической настройки других последовательных консолей systemd использует программу systemd-getty-generator, которая обнаруживает доступные последовательные консоли и запускает на каждой из них по экземпляру сервиса [email protected]. Это, в том числе, могут быть консоли, предоставляемые системами виртуализации. Для запуска на какой-либо последовательной консоли терминала, нужно воспользоваться уже известными командами:

4. Сокет-активация

Сокет-активация - это техника запуска сервисов по факту обращения к соответствующему сокету, подобная той, что реализуется в демонах inetd и xinetd. systemd поддерживает три схемы запуска сервисов, использующие сокет-активацию:

1. Схема, ориентированная на параллельный запуск сервисов и упрощение зависимостей между ними. Например, syslog и dbus могут запускаться параллельно с сервисами, использующими их. systemd создаёт файл сокета и запускает одновременно и сервисы, обслуживающие файл сокета, и сервисы, пользующиеся им. Если сервис-потребитель запустится раньше сервиса-поставщика, то запрос попадёт в сокет-файл и будет ожидать обработки до того момента, когда запустится сервис-поставщик.

2. Схема, ориентированная на активацию по запросу одиночных редко используемых сервисов. Примером такого сервиса может быть демон печати CUPS. systemd создаёт сокет-файл, который прослушивает самостоятельно. При поступлении запроса в сокет-файл, systemd запустит CUPS и передаст сокет-файл ему.

3. Схема, ориентированная на активацию по запросу многоэкземплярных сервисов, в которых каждое соединение или запрос обрабатываются отдельным процессом. Например, сервер ssh. systemd создаёт сокет-файл и прослушивает его самостоятельно, а при поступлении запроса запускает экземпляр сервиса и передаёт ему сокет-файл соединения, оставляя за собой сокет, ожидающий соединений.

Для примера настроим сокет-активацию SSH. Для этого необходимо создать два юнит-файла: юнит-файл, описывающий сокет, и юнит-файл, описывающий сервис.

Содержимое файла sshd.socket приведено ниже:
Description=SSH Socket for Per-Connection Servers ListenStream=22 Accept=yes WantedBy=sockets.target Директива ListenStream задаёт номер TCP-порта, на котором следует ожидать подключений.

Директива Accept указывает, как systemd должен поступать с поступающими запросами. В случае значения yes, systemd самостоятельно принимает соединение и передаёт сокет-файл соединения в сервис, что соответствует третьей схеме запуска сервисов. В случае значения no, systemd передаёт прослушивающий сокет-файл сервису, не принимая соединения, что соответствует второй схеме запуска.

В свою очередь, файл [email protected] выглядит следующим образом:
Description=SSH Per-Connection Server for %I ExecStart=-/usr/sbin/sshd -i StandartInput=socket Минус перед строкой команды ExecStart означает, что systemd не будет запоминать код завершения каждого процесса. Сбросить коды завершения всех сервисов можно с помощью команды systemctl reset-failed .

Директива StandartInput указывает, что на стандартный ввод команды будут подаваться данные, принятые через сокет-файл соединения. Директива StandartOutput, если она не указана, принимает то же значение, что и директива StandartInput. В данном случае это означает, что стандартный вывод процесса будет перенаправляться в сокет-файл соединения.

Для запуска сервиса используется файл, описывающий сокет сервиса:
# systemctl enable sshd.socket # systemctl start sshd.socket Как и обычно, статус сервиса можно проверить с помощью команды systemctl status sshd.socket. Среди прочей информации в статусе будут присутствовать счётчик количества соединений, принятых с момента запуска сервиса (Accepted) и счётчик количества активных соединений (Connected).

Список активных сеансов можно увидеть с помощью команды:
# systemctl --full | grep sshd А любой из экземпляров сервиса можно принудительно завершить, указав его идентификатор:
# systemctl kill [email protected]:22-172.31.0.4:47779.service Подобным образом можно активировать только те сервисы, которые поддерживают получение сокет-файла. Сервисы, открывающие сокет-файл самостоятельно, активировать таким образом не получится.

Стоит отметить, что systemd не реализует полный набор возможностей, предоставляемых демонами inetd и xinetd. Однако, большинство из них либо устарели, либо легко реализуются другими средствами. Устаревшими можно считать, например, поддержку TCPMUX, RPC и встроенных сервисов типа echo, time, daytime, discard. Примером возможности, которую можно реализовать другими средствами, являются списки управления доступом с IP-адресов: её можно реализовать с помощью пакетного фильтра iptables. При этом, iptables позволяет организовать более тонкое и эффективное ограничение доступа, например, блокировать IP-адреса, превышающие лимит попыток подключения за единицу времени и т.п.

5. Сокет-активация контейнеров

Описанная в предыдущем разделе возможность активации сервисов по требованию оказалась особенно интересна компаниям, предоставляющим услуги веб-хостинга, поскольку позволяет экономить ресурсы сервера за счёт редко посещаемых сайтов. К стати пришлась и возможность создать один шаблон service-файла для всех сайтов клиентов, а также возможности по увеличению безопасности и ограничению использования системных ресурсов (эта тема будет подробно рассмотрена в следующей заметке).

Следующим логичным шагом в этом направлении является запуск по требованию не только сервисов, но и контейнеров с виртуальными серверами клиентов. Схема активации в этом случае выглядит так: процесс systemd, работающий на хост-системе, ожидает подключений к сокету. При поступлении запроса на подключение, запускается контейнер, а сокет передаётся на обслуживание процессу systemd, работающему внутри контейнера. Тот, в свою очередь, действует по схеме, описанной в предыдущем разделе, запуская необходимый сервис с помощью сокет-активации. Всё происходит совершенно прозрачно для клиента, разве что задержка между подключением и началом обслуживания может оказаться больше, чем обычно.

Для создания виртуального окружения в настоящее время в systemd используется утилита systemd-nspawn, которую, как надеются авторы, вскоре заменит libvirt-lxc (чуть более подробное описание systemd-nspawn появится в следующей заметке).

Внутри контейнера может быть установлен дистрибутив Linux, отличный от дистрибутива на хост-системе. Например, для установки Fedora и Debian можно воспользоваться соответствующими командами:
# yum --releasever=19 --nogpg --installroot=/srv/mycontainer/ --disablerepo="*" --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal # debootstrap --arch=amd64 unstable /srv/mycontainer/ После того, как вы убедились, что контейнер загружается и работает, можно приступить к настройке service-файла для активации контейнера /etc/systemd/system/mycontainer.service:
Description=My little container ExecStart=/usr/bin/systemd-nspawn -jbD /srv/mycontainer 3 KillMode=process В полученный контейнер пока что нельзя попасть, поэтому нужно настроить на нём SSH-сервер. Для начала, настроим ожидание подключения к SSH-серверу контейнера на хост-системе в файле /etc/systemd/system/mycontainer.socket:
Description=The SSH socket of my little container ListenStream=23 Для подключения по SSH к контейнеру будет использоваться 23 порт хост-системы. При желании можно использовать и 22 порт, ожидающий подключения на отдельном IP-адресе.

Теперь нужно настроить сокет-активацию сервера SSH внутри контейнера. Для этого можно воспользоваться файлами sshd.socket и [email protected] из предыдущего раздела, нужно только не забыть поменять 22 порт на 23. Осталось лишь создать правильные символические ссылки для включения сервиса внутри контейнера. Поскольку команда systemctl enable не поддерживается в ранних версиях systemd, можно сделать это следующим образом:
# chroot /srv/mycontainer ln -s /etc/systemd/system/sshd.socket /etc/systemd/system/sockets.target.wants В более свежих версиях systemd это можно сделать проще:
# systemctl --root=/srv/mycontainer enable sshd.socket Теперь, при попытке подключиться к 23 TCP порту на хост-системе, автоматически будет запущен контейнер, внутрь него будет передан сокет, а systemd, находящийся внутри контейнера, запустит экземпляр сервиса SSH для обслуживания подключения.

Аналогичным образом можно добавить внутрь контейнера дополнительные сервисы, добавляя дополнительные директивы ListenStream в service-файл контейнера на хост-системе. При запуске контейнера, в него будут переданы все сокеты, описанные в его service-файле. Те сокеты, обслуживание которых не настроено внутри контейнера, будут закрыты.

В команде запуска systemd-nspawn из примера service-файла контейнера, указана опция -j, которая предписывает команде создать на хост-системе символическую ссылку на файл журнала journald, работающего внутри контейнера. При вводе команды systemd-journalctl с опцией -m на хост-системе, можно просматривать объединённый журнал хост-системы и контейнеров.

В настоящее время у такого подхода к активации контейнеров есть только один существенный недостаток - после обслуживания клиента контейнер продолжает работать, вхолостую используя ресурсы хост-системы. Над исправлением этого недостатка уже ведутся работы.

6. Проверка на виртуальность

Некоторые сценарии должны выполнять запуск сервиса только внутри виртуального окружения, или наоборот - только на хост-системе. Для этого в сценарии инициализации добавляются соответствующие средства обнаружения виртуального окружения и определения его типа. Чтобы упростить эти типовые действи, в systemd были добавлены несколько средств определения виртуальных окружений, каждое из которых может пригодиться в соответствующей ситуации. Эти средства позволяют определить конкретный тип виртуализации одного из следующих типов:

1. Полная виртуализация (vm): quemu, kvm, vmware, microsoft, oracle, xen, bochs,

2. Контейнерная виртуализация (container): chroot, openvz, lxc, lxc-libvirt, systemd-nspawn.

С помощью директивы ConditionVirtualization можно указать условие запуска сервиса: yes - сервис будет запускаться внутри виртуального окружения, no - сервис будет запускаться только на хост-системе. Можно указать значение vm или container, если сервис должен быть запущен только при обнаружении виртуального окружения из одной из этих групп. Можно указать и конкретный тип виртуального окружения. Для инверсии значения опции используется восклицательный знак в начале значения. Например, значение "!xen" предписывает запуск сервиса на хост-системе и внутри любого виртуального окружения, за исключением xen.

С помощью команды systemd-detect-virt можно определить наличие виртуального окружения и его тип из скриптов. Если команда обнаружит, что она была запущена из виртуальной среды, она вернёт код завершения 0 и ненулевое значение, если виртуальная среда не обнаружена. В случае обнаружения виртуальной среды команда выводит её тип на стандартный вывод. С помощью опции -q можно отключить вывод типа виртуальный среды. Опции -c и -v позволяют обнаруживать только средства контейнерной виртуализации или только средства полной виртуализации.

Программы, работающие с шиной DBus, могут узнать тип виртуального окружения, запросив соответствующее свойство у системной шины:
$ gdbus call --system --dest org.freedesktop.systemd1 --object-path /org/freedesktop/systemd1 --method org.freedesktop.DBus.Properties.Get org.freedesktop.systemd1.Manager Virtualization Если виртуальное окружение не обнаружена, это свойство содержит пустую строку. (Команда очень проста для запоминания, не правда-ли? Слава роботам!)

В комплекте с Debian Wheezy поставляется версия systemd, в которой отсутствует поддержка проверки на виртуальность. В man systemd.unit встречается упоминание директивы ConditionVirtualization, но нет команды systemd-detect-virt, а запрос свойства DBus возвращает ошибку.

7. Документация сервисов

Файлы с описаниями сервисов могут содержать директивы со ссылками на документацию, относящуюся к данному сервису. Например, раздел Unit service-файла может выглядеть следующим образом:
Description=openntpd Documentation=man:openntpd(8) http://www.openntpd.org After=network.target Поддерживаются схемы man/info и http/https. При наличии в service-файле ссылок на документацию, в выводе информации о состоянии сервиса с помощью команды systemctl status можно будет увидеть строки Docs и ссылки на документацию. Если используется терминал, работающий в графическом режиме, ссылки будут подсвечены и при щелчке по ним откроется документация.

При отсутствии графического терминала, открыть ссылки на документацию можно с помощью следующей команды:
$ systemctl help openntpd.service К сожалению, эта возможность не поддерживается в systemd, поставляющемся в комплекте с Debian Wheezy.

8. Сторожевые таймеры

Systemd поддерживает два вида сторожевых таймеров - аппаратные и программные.

Аппаратный сторожевой таймер принимает сигналы от программного обеспечения, работающего на компьютере и позволяет автоматически перезагрузить компьютер, если в течение определённого интервала времени от программного обеспечения не поступали сигналы.

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

В совокупности оба вида сторожевых таймеров позволяют обнаруживать как аппаратные сбои компьютера, так и сбои в работе сервисов, уведомляя о сбоях администратора системы или выполняя заранее определённые действия. systemd выступает центральным звеном этой системы. Он способен принимать сигналы от сервисов, выполняя определённые действия при их сбоях, отправляя, в свою очередь, аппаратному таймеру сигналы о собственной работоспособности.

8.1. Аппаратный сторожевой таймер

Аппаратный сторожевой таймер представлен в системе файлом устройства /dev/watchdog. Настройки systemd, связанные с аппаратным таймером, находятся в файле /etc/systemd/system.conf.

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

Директива ShutdownWatchdogSec задаёт длительность, отводимую на процесс перезагрузки системы. После сработки сторожевого таймера, пока система загружается, сторожевой таймер не будет предпринимать никаких действий в течение этого периода времени. Если по истечение этого периода времени сигналы не начнут поступать, аппаратный сторожевой таймер предпримет повторную попытку перезагрузки системы, посчитав что система зависла в процессе загрузки. По умолчанию эта директива принимает значение 10min.

Определить наличие в системе аппаратного сторожевого таймера можно с помощью команды wdctl из пакета util-linux (в Debian Wheezy такой команды в этом пакете нет).

8.2. Программные сторожевые таймеры

Если сервис поддерживает периодическую отправку сигналов с помощью системного вызова sd_notify, можно настроить его перезапуск средствами systemd в случае длительного отсутствия сигналов от него. Значение периода ожидания сигналов сообщается сервису с помощью переменной окружения WATCHDOG_USEC и задаётся в микросекундах. Сервис должен отправлять сигналы с периодичностью, равной половине указанной. При отсутствии этой переменной в окружении сервиса, он не должен отправлять сигналы с помощью sd_notify.

Настройки в service-файле позволяют определить реакцию systemd на отсутствие сигналов от сервиса в течение периода ожидания.

Директива WatchdogSec задаёт период ожидания сигналов от сервиса. Это значение передаётся сервису в переменной окружения WATCHDOG_USEC.

Директива Restart задаёт настройки условий перезапуска сервиса. Значение on-failure соответствует перезапуску сервиса в случае его сбоя и включает в себя в том числе ситуацию, когда сработал сторожевой таймер.

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

Директива StartLimitBurst задаёт количество сбоев, при достижении которого будет выполнено действие.

Директива StartLimitInterval задаёт интервал времени, за который должно произойти указанное количество сбоев, чтобы действие было выполнено.

Директива StartLimitAction задаёт выполняемое действие. Значение none не задаёт никаких действий. Значение reboot указывает на необходимость перезагрузить всю систему в штатном режиме. Значение reboot-force отправит систему на перезагрузку без корректной остановки сервисов. Значение reboot-immediate отправит систему в немедленную перезагрузку без корректной остановки сервисов и размонтирования файловых систем.

Директива OnFailure позволяет указать юнит, инициируемый в случае сбоя сервиса. В этом юните может быть настроен, например, скрипт отправки уведомлений системному администратору по электронной почте или по SMS.

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