Systemd: Создание Сервиса — Примеры. Как написать systemd unit-файл для автозагрузки своего сервиса - Linux admin blog Управление службами в системах sysv и systemd

Введение

Systemd - это система инициализации (init system) и системный менеджер, который получил широкое распространение и становится новым стандартом для Linux-машин. Хотя существуют обоснованные сомнения в том, является ли systemd улучшением по сравнению с традиционными системами инициализации SysV, большинство дистрибутивов уже перешли на systemd, либо планируют это сделать.

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

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

В этом руководстве мы обсудим команду systemctl , которая является центральным инструментом управления для контроля системы инициализации (init). Мы рассмотрим, как управлять сервисами, проверять состояния, изменять состояния системы и работать с файлами конфигурации. Мы охватим вопросы, как управлять службами, проверять статусы, изменять состояния системы и работать с конфигурационными файлами.

Обратите внимание: несмотря на то, что systemd стала стандартной системой инициализации для многих дистрибутивов Linux, она не реализована повсеместно во всех дистрибутивах. По мере прохождения этого руководства, если ваш терминал выводит ошибку bash: systemctl не установлен, (bash: systemctl is not installed) , то вероятно, на вашем компьютере установлена другая система инициализации.

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

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

В systemd целью (объектами) большинства действий являются «юниты » (units), которые представляют собой ресурсы, которыми systemd знает как управлять. Юниты классифицируются по типу ресурса, который они представляют, и определяются файлами, известными как файлы юнитов. Тип каждого юнита может быть определён по суффиксу в конце файла.

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

Запуск и остановка служб

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

Sudo systemctl start приложение.service

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

Sudo systemctl start приложение

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

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

Sudo systemctl stop приложение.service

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

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

Sudo systemctl restart приложение.service

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

Sudo systemctl reload приложение.service

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

Sudo systemctl reload-or-restart приложение.service

Включение и отключение служб

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

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

Sudo systemctl enable приложение.service

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

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

Sudo systemctl disable приложение.service

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

Systemctl enable --now apache2.service

Приведённая команда добавить веб-сервер Apache в автозагрузку и немедленно запустит его.

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

Символ @ («собака») в именах служб

Некоторые имена юнитов содержат символ @ (т.е. [email protected]): это означает, что они являются экземплярами юнита-шаблона, чьё действительное имя не содержит часть, которая в условном примере обозначена как string (т.е. [email protected]). string называется идентификатором экземпляра и аналогична аргументу, который передается юниту-шаблону при вызове с помощью команды systemctl: в файле юнита он будет заменять спецификатор %i .

Для большей точности работы, перед попыткой создать экземпляр [email protected] юнита-шаблона, systemd действительно ищет юнит с точным именем файла [email protected], даже не смотря на то, что такие «конфликты» довольно редки, так как большинство файлов юнитов, содержащих знак @ , подразумевают использование шаблонов. Кроме того, если юнит-шаблон вызывается без идентификатора экземпляра, ничего не получится, так как спецификатор %i не может быть подставлен.

К примеру, в файле юнита OpenVPN:

Systemctl cat [email protected]

содержится строка:

ExecStart=/usr/bin/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf

В этой строке виден спецификатор %i , при его замене получится имя файла логов и файла конфигурации.

Используя различные значения string , можно добиться настройки автозапуска OpenVPN с различными конфигурационными файлами. Например:

Systemctl enable [email protected]_tcp_443

Этой командой служба OpenVPN будет добавлена в автозапуск, при этом она будет запускаться с конфигурационным файлом /etc/openvpn/server/port_tcp_443.conf . Используя такой подход, можно настроить автозапуск одной и той же службы с разными конфигурациями. Например, OpenVPN на разных портах.

Многие службы поддерживают модель шаблоны-экземпляры. К примеру, Apache2:

Systemctl enable [email protected]

Эта команда приведёт к тому, что значение переменной окружения APACHE_CONFDIR будет установлено на /etc/apache2-test .

Проверка состояния служб

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

Systemctl status приложение.service

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

Например, при проверке состояния веб-сервера Apache вы можете увидеть вывод следующим образом:

● apache2.service - The Apache HTTP Server Loaded: loaded (/lib/systemd/system/apache2.service; disabled; vendor preset: disabled) Active: active (running) since Mon 2018-04-30 08:11:26 MSK; 11s ago Process: 2650 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS) Main PID: 2661 (apache2) Tasks: 7 (limit: 4580) Memory: 31.1M CGroup: /system.slice/apache2.service ├─2661 /usr/sbin/apache2 -k start ├─2662 /usr/sbin/apache2 -k start ├─2663 /usr/sbin/apache2 -k start ├─2664 /usr/sbin/apache2 -k start ├─2665 /usr/sbin/apache2 -k start ├─2666 /usr/sbin/apache2 -k start └─2667 /usr/sbin/apache2 -k start апр 30 08:11:25 HackWare systemd: Starting The Apache HTTP Server... апр 30 08:11:26 HackWare apachectl: AH00558: apache2: Could not reliably determine the server"s fully qualified domain name, using 127.0.1.1. Set the "ServerName" directive globally to suppress this message апр 30 08:11:26 HackWare systemd: Started The Apache HTTP Server.

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

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

Systemctl is-active приложение.service

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

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

Systemctl is-enabled приложение.service

Будет выведено enabled или disabled , и снова код выхода будет установлен на «0» или «1» в зависимости от ответа на вопрос команды.

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

Systemctl is-failed приложение.service

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

Следующая команда покажет сразу все завершившиеся неудачей юниты:

Systemctl --failed

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

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

Список текущих юнитов

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

Systemctl list-units

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

Вывод имеет следующие столбцы:

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

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

Systemctl

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

Systemctl list-units --all

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

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

Systemctl list-units --all --state=inactive

Другим распространенным фильтром является фильтр --type= . Мы можем сказать systemctl отображать только те юниты, которые нас интересуют. Например, чтобы видеть только активные юниты служб, мы можем использовать:

Systemctl list-units --type=service

Systemctl --type=service

Предыдущая команда покажет только активные службы, для вывода информации о всех службах добавьте ключ --all :

Systemctl --type=service --all

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

Systemctl list-units --type=service --state=СТАТУС

Systemctl --type=service --state=СТАТУС

В качестве СТАТУСа могут быть значения:

  • active
  • inactive
  • running
  • exited
  • dead
  • loaded
  • not-found
  • plugged
  • mounted
  • waiting
  • listening

Например, вывод служб, которые завершили свою работу:

Systemctl --type=service --state=exited

Вывод служб, которые запущены в данный момент:

Systemctl list-units --type=service --state=running

Systemctl --type=service --state=running

Вывод списка всех файлов юнитов

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

Systemctl list-unit-files

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

Если вы хотите посмотреть только юниты, добавленные в автозагрузку, то используйте следующую конструкцию:

Systemctl list-unit-files | grep enabled

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

Чуть ниже мы рассмотрим, что означает «masked ».

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

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

Показ файла юнита

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

Systemctl cat apache2.service

Будет показано что-то вроде:

Description=The Apache HTTP Server After=network.target remote-fs.target nss-lookup.target Type=forking Environment=APACHE_STARTED_BY_SYSTEMD=true ExecStart=/usr/sbin/apachectl start ExecStop=/usr/sbin/apachectl stop ExecReload=/usr/sbin/apachectl graceful PrivateTmp=true Restart=on-abort WantedBy=multi-user.target

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

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

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

Systemctl list-dependencies ssh.service

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

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

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

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

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

Systemctl show sshd.service

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

Systemctl show ssh.socket -p Conflicts

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

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

Sudo systemctl mask nginx.service

Это предотвратит запуск службы Nginx, автоматически или вручную, до тех пор, пока она замаскирована.

Если вы проверите list-unit-files , вы увидите, что служба теперь отображается как masked (замаскированная):

Systemctl list-unit-files

Если вы попытаетесь запустить службу, вы увидите следующее сообщение:

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 ssh.socket

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

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

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

Sudo systemctl edit --full ssh.socket

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

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

Sudo rm -r /etc/systemd/system/ssh.socket.d

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

Sudo rm /etc/systemd/system/ssh.service

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

Sudo systemctl daemon-reload

Настройка состояния системы (уровень запуска) с помощью целей

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

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

Например, есть swap.target , который используется для указания того, что swap готов к использованию. Юниты, которые являются частью этого процесса, могут синхронизироваться с этой целью, указывая в своей конфигурации, что они WantedBy= или RequiredBy= цель swap.target . Юниты, для которых требуется файл подкачки, могут указывать это условие, используя спецификации 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 попытался запустить все юниты, привязанные к цели, и не попытался снова их отключить (teardown). Чтобы увидеть все активные цели, введите:

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 вместо изолирования rescue.target :

Sudo systemctl rescue

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

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

Sudo systemctl halt

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

Sudo systemctl poweroff

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

Sudo systemctl reboot

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

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

Sudo reboot

Заключение

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

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

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

Systemd: быстрее света

Схема загрузки типичного Linux-дистрибутива выглядит примерно так: ядро инициализирует железо и запускает процесс /sbin/init, который, в свою очередь, запускает инициализационные скрипты. Скрипты монтируют файловые системы, настраивают сеть, различные устройства и начинают последовательный запуск демонов: syslogd, cron, cups и прочих, которые перечислены в конфигурационных файлах. В самом конце init запускает менеджер входа в систему: getty или xdm (kdm, gdm). Просто и логично, не так ли? Однако такая схема довольно примитивна, а в сравнении с Windows и Mac OS X так и вообще архаична. Их системы инициализации запускают задачи параллельно, не дожидаясь завершения одной, чтобы передать управление следующей. Если одна из них застопоривается на операции ввода-вывода, управление сразу получает другая, так что общее время загрузки сокращается, да так существенно, что традиционная система оказывается далеко позади.

В мире Linux так ведет себя только Ubuntu, да и то только последние два года. Все остальные продолжают по старинке последовательно грузить систему или используют самосборные костыли, которые распараллеливают процесс загрузки неумело и часто ошибочно (Gentoo и Arch, привет!). По-настоящему универсальное решение не найдено до сих пор, поэтому над идеей параллельной системы инициализации работают многие программисты.

Леннарт Поттеринг, сотрудник Red Hat и автор PulseAudio, один из них. Его последнее достижение - демон systemd, очередной претендент на звание убийцы /sbin/init, мимо которого можно было бы спокойно пройти, если бы идея, заложенная в его основу, не оказалась столь интересной и правильной.

Systemd отличается от любой другой системы инициализации тем, что намеренно делает сложные вещи простыми. 99% всех остальных параллельных систем инициализации провалились просто потому, что в сравнении с простым и понятным даже дикарю /sbin/ init они выглядели тяжеловесными монстрами. Чтобы обеспечить возможность параллельного запуска, не введя ОС в противоречивое состояние (которое может возникнуть, если, например, пытаться настроить сеть до загрузки сетевых драйверов или запустить демоны, не смонтировав нужную ФС), использовались различные методы синхронизации. В основном это были своеобразные «метки зависимостей», которые не давали очередному шагу инициализации отработать, если не был пройден шаг, описанный в его зависимостях.
Например, cron зависит от syslog, потому что ему надо вести логи; syslog зависит от настойки сети, потому что он способен принимать логи от удаленных машин и так далее. Из-за этого инициализационные скрипты превращались в запутанную вереницу блоков, а их составление значительно усложнялось. Systemd организован намного проще, он не следит за зависимостями, а просто запускает все, что есть, одновременно.

Я не шучу. Systemd использует механизмы контроля зависимостей только на самых ранних этапах инициализации, которые так или иначе должны происходить последовательно (монтирование корневой файловой системы, подключение swap, загрузка модулей и так далее). Когда же дело доходит до демонов, на запуск которых уходит 90% всего времени инициализации ОС, systemd забывает о зависимостях и стартует их всех сразу, показывая просто потрясающую скорость.

Это работает благодаря тому, что systemd знает об особенности работы демонов и их связи между собой.

Ведь на самом деле демонам нужны вовсе не другие демоны, а только «коммуникационные каналы», обеспечивающие обмен данными: cron не зависит от syslog, ему нужен сокет /dev/log, в который он сможет записывать свои логи, это же справедливо и в отношении любого другого демона. Все они общаются через сокеты, и единственная причина, почему демон A должен быть запущен раньше демонов B, C и D, заключается в том, что демон A должен создать сокет, который им нужен. Systemd учитывает эту особенность, поэтому его механизм параллельного запуска основан на сокетах, которые он создает для каждого демона заблаговременно, а затем запускает демоны одновременно. При этом ответственность за синхронизацию и «отслеживание зависимостей» теперь перекладываются на ядро, в рамках которого и реализован механизм сокетов.

Если, например, cron получит управление раньше syslog, ничего страшного не произойдет - cron найдет свой любимый /dev/log и даже сможет писать в него сообщения (если захочет, конечно), которые будут, нет, не выброшены, а буферизированы в сокете, но только до тех пор, пока cron не захочет записать в сокет сообщение, способное его переполнить. В этом случае ядро заблокирует процесс cron и передаст управление следующему процессу в очереди на исполнение (следующему демону). Вскоре (а может быть и сразу) очередь дойдет и до syslog, который запустится, прочитает сообщения, скопившиеся в /dev/log, обработает их и сам на чем-нибудь заблокируется (либо истратит отведенное ему время), и управление перейдет следующему демону. Типичная многозадачность без лишних костылей.

Более того, благодаря такой схеме большинство демонов могут быть запущены только тогда, когда в них возникнет реальная необходимость. Так, например, CUPS вовсе не обязательно запускать во время инициализации ОС, когда нагрузка на систему и без того высока. Логичнее стартануть его, когда на печать будет отправлен первый документ. Systemd позволяет сделать такое, следя за активностью вокруг сокетов, и применяет похожий подход для монтирования файловых систем, подключая их к точкам монтирования только при попытке получить доступ к файлам (также демоны могут быть запущены при появлении в системе определенного файла-устройства).

Справедливости ради стоит сказать, что столь гениальное решение проблемы зависимостей было придумано и реализовано в Mac OS X с самого начала ее существования, но до автора systemd почему-то никто не обращал на это внимания.

Кстати, у самого systemd есть другая и явно уникальная для Linux характеристика: он умеет группировать процессы с помощью cgroups с установкой различных лимитов среды исполнения на всю группу (ограничения ресурсов, рабочий и корневой каталоги, umask, настройки OOM killer, параметр nice, приоритет операций ввода-вывода, приоритеты использования процессора и многое другое). То есть демонов теперь можно помещать в виртуальные окружения без использования какого бы то ни было дополнительного ПО, просто прописав в файл настроек systemd несколько строк.

Systemd уже доступен для скачивания и возможно будет включен в один из будущих релизов Fedora в качестве альтернативной системы инициализации. Инструкции по установке в другие дистрибутивы можно найти на официальной страничке: freedesktop.org/wiki/Software/systemd .

Установить Systemd в Ubuntu можно, выполнив следующие команды:

$ sudo add-apt-repository ppa:andrew-edmunds/ppa
$ sudo apt-get update
$ sudo apt-get install systemd

Далее следует отредактировать /boot/grub/grub.cfg, добавив к параметрам ядра строчку init=/sbin/systemd. После перезагрузки дистрибутив будет работать с новой системой инициализации, в чем можно убедиться с помощью команды:

$ sudo systemctl units-list

Для проверки состояния, запуска, остановки и включения служб используются аргументы status, start, stop и enable.

Ulatencyd: мгновенная реакция

Какой, на твой взгляд, самый важный параметр десктопной операционной системы? Хороший графический интерфейс? Количество доступных приложений? Простота использования?

Да, все это имеет значение, но сегодня, когда этими свойствами легко наделить даже серверные ОС, решающими становятся совсем другие факторы, важнейший из которых - отзывчивость системы.

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

Для разработчиков операционных систем это прописная истина, поэтому во все времена они стремились сделать свои ОС более интерактивными. У одних это получалось хорошо (привет BeOS), у других плохо (куда же без MS), но были и такие, у кого это не получалось вообще. Долгое время разработчики Linux совершенно не интересовались темой отзывчивости Linux на десктопах. Кон Коливас множество раз указывал им на проблемы, говорил о неповоротливости и медлительности Linux, писал патчи, ночами кодил новые планировщики задач, добивался их включения в ядро. Все напрасно, раз за разом патчи отвергали, а самого автора грубо отстраняли от дел.

Однако со временем труды Кона Коливаса окупились. Инго Молнар начитался его исходников и написал планировщик CFS (Completely Fair Scheduler), а Линукс незамедлительно включил его в ядро 2.6.23. После этого положение дел на десктопах существенно улучшилось, и Linux стал намного быстрее (при этом реализация Кона все равно продолжала показывать более впечатляющие результаты).

Второй важной вехой на пути Linux к десктопу стало включение знаменитого 200-страничного патча в ядро 2.6.38, а также появление его аналога на языке bash. Так Linux научился отделять интерактивные процессы от всех остальных демонов, серверов и bash-скриптов и наделять их более высокими приоритетами. Это событие еще больше улучшило ситуацию и сделало ее практически идеальной: теперь Linux не тормозил даже тогда, когда в фоне шла пересборка ядра в несколько потоков.
Наконец, третьим важным шагом для десктопного Linux (здесь я подхожу к самому главному) стало появление демона ulatencyd, способного регулировать отзывчивость системы динамически, подстраивая ее под изменяющиеся обстоятельства.

Как и ядерный патч, ulatencyd использует механизм cgroups для группировки интерактивных процессов и изменения их приоритетов, но на этом его работа не заканчивается. Демон использует эвристические алгоритмы для выявления «наиболее интерактивных» процессов, а также явных вредителей системы, таких как форк-бомбы и программы с большими утечками памяти. При этом первые получают еще больший приоритет, а вторые жестко урезаются в возможностях (получая низкий приоритет, ограничения на доступную память), изолируются или уничтожаются. Но что самое главное, в любой момент демон можно обучить новым правилам отбора процессов, так что мы теперь можем назначать самые высокие (даже реалтаймовые) приоритеты любимым играм, видеоплеерам и браузерам.

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

Чтобы установить ulatencyd, необходимо скачать его исходники со страницы и собрать с помощью стандартных cmake и make:

$ cmake
$ make
$ sudo make install

$ sudo /usr/local/sbin/ulatencyd -v 2

И понаблюдать за тем, как он группирует процессы по приоритетам:

$ ps xaf -eo pid,session,args,cgroup

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

relayd: по трем фронтам

Какая связь между мониторингом сетевых хостов, балансировкой нагрузки и прокси-сервером? Все это функции одной машины? Да, вполне возможно. Но что если я скажу, что все эти три функции тесно связаны между собой и должны быть реализованы в рамках одного универсального приложения? Бред? Никак нет.

Возьмем, к примеру, достаточно распространенную в узких кругах функцию сервера под названием «распределение нагрузки между несколькими DNS-серверами». Что нужно для ее решения? Во-первых, умение перенаправлять DNS-трафик на другой хост (от балансировщика к одному из реальных DNS-серверов).

Это можно сделать с помощью брандмауэра или особым образом настроенного BIND (несколько тяжеловесный вариант). Вовторых, умение выбирать наиболее подходящего кандидата для обработки запроса из списка DNS-серверов. Это уже сложнее, и здесь может понадобиться специализированное ПО или опять же брандмауэр (но очень хороший). В-третьих, умение проверять DNS-сервера на доступность и удалять упавших из списка. Нужен скрипт, пингующий хосты и управляющий списками, либо особые возможности брандмауэра (а такой есть?). В общем, долгое нудное велосипедостроение или покупка специализированного решения для конкретной задачи по нереальным ценам. А что если завтра вдруг понадобится сделать нечто подобное для SMTP?

Все править или вновь открывать кошелек? Не стоит, содержимое кошелька все-таки лучше приберечь, а костыли с велосипедами оставить спортсменам. Демон relayd, появившийся в OpenBSD 4.3, позволяет решить эту и еще огромное количество других, подобных и не очень, задач всего за несколько минут.

Он включает в себя возможности балансировщика нагрузки для протоколов уровней 3, 4 и 7, прокси уровня 7 (релей) и сервиса проверки доступности сетевых узлов (из которого и вырос).

На основе relayd можно строить самые разные конфигурации, начиная от простых прокси-серверов или SSL-акселераторов и заканчивая сложными решениями вроде прозрачных web-прокси с фильтрацией запросов и распределением нагрузки между несколькими web-серверами. И все это с помощью простого конфигурационного файла, длина которого даже в самых сложных конфигурациях редко превышает 50 строк.

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

# vi /etc/relayd.conf

Переменные и макросы

Адрес и порт нашего релея

relayd_addr="127.0.0.1"
relayd_port="8053"

Адреса трех DNS-серверов, которые будут обрабатывать

запросы

table { 192.168.1.1, 192.168.1.2, 192.168.1.3 }

Общие настройки

Интервал между проверками хостов на доступность

(10 секунд)

Таймаут для проверки хостов на доступность методом TCP

(если хост не отвечает дольше 200 мс - он в дауне)

Разделяем сервер на 5 процессов для более эффективной

обработки запросов

Логировать результаты проверки хостов на доступность

Настройки DNS-протокола

Параметры оптимизации соединения

dns protocol "dnsfi lter" { tcp { nodelay, sack, socket buffer 1024, backlog 1000 } }

Настройки релея

relay dnsproxy {

Прослушиваемый адрес и порт

listen on $relayd_addr port $relayd_port

Работаем с описанным ранее протоколом

protocol "dnsfi lter"

Оправляем DNS-пакеты одному из перечисленных в таблице

DNS-серверов, предварительно проверив его на доступность

forward to port 53
mode loadbalance check tcp
}

Наиболее важные части этого конфига находятся в теле директив dns protocol и relay. Первая представляет собой нечто вроде шаблона, который используется для того, чтобы не повторять одни и те же настройки протоколов в других частях конфигурационного файла (relayd поддерживает три протокола: HTTP, DNS и TCP). Вторая - это настройка релея, в котором указаны прослушиваемый порт, проксируемый протокол, его настройки и информация о том, каким образом и какому хосту должны быть перенаправлены пакеты. В нашем случае прокси должен отправить DNS-запрос одному из трех серверов с предварительной проверкой на доступность (здесь используется проверка методом TCP-рукопожатия, но relayd поддерживает множество других методов, начиная от ping и заканчивая попыткой установить SSLсоединение). При этом, если один из DNS-серверов окажется в дауне, relayd автоматически исключит его из списка до тех пор, пока плановая проверка на доступность (интервал между проверками указан в опции interval) не покажет его работоспособность.

Для тестирования конфигурации можно использовать следующую форму запуска relayd:

# relayd -d -vv -f /etc/relayd.conf

Так демон не уйдет в фон и будет вести подробную распечатку всех своих действий. После отладки конфигурации можно настроить запуск демона во время загрузки системы. Для этого достаточно поместить строку relayd_flags=»» в файл /etc/rc.conf.local.

FreeBSD fscd: красота минимализма

Этого раздела не должно было быть в статье. Демон fscd настолько простой инструмент, что писать о нем отдельно мне казалось излишним. С другой стороны, не писать о нем нельзя, потому как это один из ярчайших примеров правильного решения задачи в стиле UNIX. А задача у разработчиков FreeBSD была следующая.
Различные системные и не очень демоны могут время от времени падать (или начинать вести себя как идиоты, что еще хуже). На домашней машине это не страшно, упавшего можно перезапустить руками или отправить комп в перезагрузку. Но что делать на сервере, где админ бывает редко?

Сервисы надо мониторить и перезапускать по мере необходимости. Как это сделать? Естественно, встроить эту функциональность в систему инициализации (ведь именно она занимается запуском демонов). И, например, в Solaris так и сделано, да настолько экстравагантно, что сам Линус Торвальдс ногу сломит, пока разберется с его настройкой. Разработчики FreeBSD поступили проще. Они написали отдельный демон, который способен работать со скриптами инициализации FreeBSD, оставаясь совершенно независимой системой. Вся соль в том, что fscd получился настолько простым, что им можно пользоваться, не читая man-страниц и не беспокоясь о том, что он может упасть. Посуди сам, чтобы заставить fscd следить за, например, sshd, нужно ввести всего одну команду:

# fscadm enable sshd /var/run/sshd.pid

Все, fscd запомнит этот выбор и автоматически включит мониторинг после перезагрузки машины. Единственное условие: у подконтрольного демона должен быть инициализационный файл в каталоге /etc/rc.d (или /usr/local/etc/rc.d) и запись в файле /etc/rc.conf, включающая его (это очевидно).

Демон fscd будет доступен только во FreeBSD 9.0, но его вполне можно скачать с официальной странички (people.freebsd.org/~trhodes/fsc) и собрать для восьмерки.

Выводы

Каждый день в мире UNIX появляется что-то новое, но очень редко это новое оказывается чем-то стоящим нашего внимания. В этой статье я рассказал о четырех системных компонентах UNIX, которые не только заслуживают особого внимания, но и несут реальную пользу. Кто знает, возможно в будущем они будут такой же неотъемлемой частью UNIX, как команда grep или демон syslog.

Links

  • дом systemd под крылом: freedesktop.org/wiki/Software/systemd ; freedesktop.org
  • исходные тексты systemd: cgit.freedesktop.org/systemd ;
  • код ulatencyd: github.com/poelzi/ulatencyd ;
  • исходники fscd: people.freebsd.org/~trhodes/fsc .

Info

  • В долгосрочной перспективе автор собирается превратить systemd в полноценный менеджер сессий, способный заменить gnomesession и kdeinit.
  • Кроме всего прочего, systemd обладает функциями монитора для демонов, так что возможности fscd встроены в него от рождения.
  • Отказ от использования скриптов - один из методов ускорить процесс загрузки. Многие задачи инициализации systemd способен произвести через прямой вызов нужных команд, без использования скриптов.
  • Прежнее название relayd - hostated (от слов host state, «состояние хоста»), было изменено на теперешнее в связи с расширением функционала.

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.

Systemd оперирует unit-файлами в качестве конфигурационных файлов. Это как.conf-файл для upstart или init-скрипты для initd. Unit-файлы также могут описывать и другие системные сущности, но в данном случае они нас интересуют как конфиг для автостарта сервиса. В Ubuntu 16.04 они лежат в /etc/systemd/ . Напишем свой unit-файл.

Допустим у нас есть программа, которую мы хотим запускать как демон. Вот я писал как создать telegram-бота. У меня получился исполняемый файл, который запускается и висит ждет сообщений. Теперь хочу чтобы он как демон стартовал при загрузке системы.

Создаем такой файл:

Description = TelegramBotMonitoring After = network.target Type = simple ExecStart = /usr/local/bin/telegram-site-monitoring -telegrambottoken 397______:___________WRDsIU -chatid -14____640 Restart = always WantedBy = multi-user.target

и кладем его в /etc/systemd/system/telegram-bot.service

Конфиг похож на обычный ini-файл:

    After - запускать этот юнит после определенных демонов или целей (цель - это набор юнитов). Здесь указан network.target , это значит, что демон запустится после того как поднимутся сетевые интерфейсы.

    Type - тип того, как запускается демон. Чаще всего используется simple , forking или one-shot . simple - демон запускается и начинает ожидать на консоле и не отфоркивается. forking - демон запускается, потом форкается и завершает родительский процесс. Многие программы именно так и запускаются, чтобы перейти в background режим. Например, nginx запускается по такой схеме. one-shot - используется для запуска скриптов которые запускаются, отрабатывают и завершаются. В моем случае это не скрипт и программа не форкается, поэтому тип - simple

    ExecStart - команда для запуска демона.

    Restart - рестартовать демон, если он завершится/упадет. При always systemd будет перезапускать демон независимо от того почему он завершился. Можно указать on-failure , тогда будет перезапускаться если демон вышел с ненулевым кодом возврата или был завершен по сигналу (kill DAEMONPID)

    WantedBy - говорим, что запускать этот демон когда система грузится в multi-user режиме

# systemctl daemon-reload

И добавляем созданный юнит в автозагрузку:

# systemctl enable telegram-bot.service Created symlink from /etc/systemd/system/multi-user.target.wants/telegram-bot.service to /etc/systemd/system/telegram-bot.service.```

Все. Сервис добавлен в автозагрузку, но еще не запущен. Запустим:

# systemctl start telegram-bot

Запустился:

# systemctl status telegram-bot ● telegram.service - TelegramBotMonitoring Loaded: loaded (/etc/systemd/system/telegram-bot.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2017-07-13 17:10:19 MSK; 5s ago Main PID: 1825 (telegram-site-m) Tasks: 4 Memory: 4.4M CPU: 39ms CGroup: /system.slice/telegram-bot.service └─1825 /usr/local/bin/telegram-site-monitoring -telegrambottoken 3972____:__________Gi03WRDsIU -chatid -14____40 Jul 13 17:10:19 ubuntu systemd: Started TelegramBotMonitoring. Jul 13 17:10:19 ubuntu telegram-site-monitoring: 2017/07/13 17:10:19 {} Jul 13 17:10:19 ubuntu telegram-site-monitoring: 2017/07/13 17:10:19 Authorized on account Jul 13 17:10:19 ubuntu telegram-site-monitoring: 2017/07/13 17:10:19 Config file: config.json Jul 13 17:10:19 ubuntu telegram-site-monitoring: 2017/07/13 17:10:19 ChatID: Jul 13 17:10:19 ubuntu telegram-site-monitoring: 2017/07/13 17:10:19 Starting monitoring thread

Шпаргалка с коммандами для управления демонами 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

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