Глава 10. Управление сервисами в systemd. 10.6. Создание и изменение файлов юнитов в systemd. Часть 2

10.6.3. Конвертация SysV Init скриптов в файлы юнитов (Unit Files)

Прежде чем заняться преобразованием скрипта SysV (далее – init-скрпт) в файл юнита, убедитесь, что преобразование еще не было выполнено в другом месте. Все основные службы, установленные в Red Hat Enterprise Linux 7, поставляются со стандартными юнит-файлами, и то же самое относится ко многим сторонним программным пакетам.
Преобразование init-скрипта в юнит-файл требует анализа init-скрипта и извлечения из него необходимой информации. На основе полученных данных вы можете создать файл юнита, как описано в разделе 10.6.2 «Создание пользовательских файлов юнита». Поскольку init-скрипты могут сильно различаться в зависимости от типа сервиса, возможно вам потребуется использовать больше параметров конфигурации для конвертации, чем описано в этой главе. Обратите внимание, что некоторые уровни настройки, которые были доступны в init-скриптах, больше не поддерживаются модулями systemd, см. Раздел 10.1.2, «Изменения совместимости».
Большая часть информации, необходимой для конвертации, указана в заголовке скрипта. В следующем примере показан начальный раздел init-скрипта, используемого для запуска службы postfix в Red Hat Enterprise Linux 6 (пример файла юнита для postfix можно найти в предыдущей части):

#!/bin/bash
#
# postfix      Postfix Mail Transfer Agent
#
# chkconfig: 2345 80 30
# description: Postfix is a Mail Transport Agent, which is the program \
#              that moves mail from one machine to another.
# processname: master
# pidfile: /var/spool/postfix/pid/master.pid
# config: /etc/postfix/main.cf
# config: /etc/postfix/master.cf
 
### BEGIN INIT INFO
# Provides: postfix MTA
# Required-Start: $local_fs $network $remote_fs
# Required-Stop: $local_fs $network $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: start and stop postfix
# Description: Postfix is a Mail Transport Agent, which is the program that 
#              moves mail from one machine to another.
### END INIT INFO

В приведенном выше примере обязательны только строки, начинающиеся с #chkconfig и #description, поэтому вы можете не найти остальных в разных init-файлах. Текст, заключенный между строками ### BEGIN INIT INFO и ### END INIT INFO, называется заголовком Linux Standard Base (LSB). Если LSB-заголовок указан, то он содержит директивы, определяющие описание службы, зависимости и уровни запуска (runlevels). Далее следует обзор аналитических задач, направленных на сбор данных, необходимых для нового юнит-файла. В качестве примера используется init-скрипт postfix, см. Итоговый файл модуля postfix в примере 10.17, «Файл юнита postfix.service».

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

Найдите описание скрипта в строке, начинающейся с #description. Используйте это описание вместе с именем сервиса в опции Description секции [Unit] в файле юнита. Заголовок LSB может содержать аналогичные данные в строках #Short-Description и #Description.

Поиск зависимостей сервиса

Заголовок LSB может содержать несколько директив, которые формируют зависимости между сервисами. Большая часть может быть переведена в опции юнита systemd, см. Таблицу 10.12, «Параметры зависимостей из заголовка LSB».

Таблица 10.12, Параметры зависимостей из заголовка LSB
Опция LSB Описание Опция юнита
Provides Задает имя сервиса при загрузке, на которое можно ссылаться в других скриптах (с префиксом “$”). Сейчас это не требуется, т.к. юнит-файлы ссылаются на другие юнит-файлы по их именам.
Required-Start Содержит загрузочные имена необходимых сервисов. Т.е. это зависимости упорядочения, имена необходимых сервисов при переводе заменяются на имена юнит-файлов соответствующих сервисов или таргетов, которым они принадлежат. Например, в случае с postfix зависимость Required-Start: $network была переведена в зависимость After=network.target. After, Before
Should-Start Определяет более слабые зависимости, чем Required-Start. Неудачные зависимости Should-Start не влияют на запуск службы. After, Before
Required-Stop, Should-Stop Определяет негативные зависимости. Conflicts

Определение таргета для запуска сервиса

Строка, начинающаяся с #chkconfig, содержит три числовых значения. Для нас важно первое число, которым представлены уровни запуска по умолчанию для данного сервиса. Используйте Таблицу 10.6, «Сравнение уровней запуска SysV с таргетами systemd», чтобы перевести эти уровни выполнения в таргеты systemd. Затем перечислите эти таргеты в опции WantedBy в разделе [Install] файла юнита. Например, postfix ранее запускался на уровнях запуска 2, 3, 4 и 5, что соответствует таргетам multi-user.target и graphical.target в Red Hat Enterprise Linux 7. Обратите внимание, что graphical.target зависит от multiuser.target, поэтому нет необходимости указывать оба, как в примере 10.17, «Файл модуля postfix.service». Вы также можете найти информацию о дефолтных и запрещенных уровнях запуска в строках #Default-Start и #Default-Stop в заголовке LSB.
Два других значения, указанные в строке #chkconfig, представляют приоритеты запуска и завершения init-скрипта. Эти значения интерпретируются systemd, если он загружает init-скрипт, но нет эквивалентного юнит-файла.

Определение файлов, используемых сервисом

Init-скрипты требуют загрузки библиотеки функций из выделенной директории и позволяют импортировать файлы конфигурации, среды и PID файлы. Переменные среды указываются в строке, начинающейся с #config в заголовке скрипта и соответствует опции EnvironmentFile в файле юнита. Файл PID, указанный в init-скрипте в строке #pidfile импортируется в файл юнита с опцией PIDFile.
Ключевой информацией, которая не включена в заголовок скрипта, является путь к исполняемому файлу сервиса и, возможно, некоторые другие файлы, необходимые для сервиса. В предыдущих версиях Red Hat Enterprise Linux init-скрипты использовали оператор Bash case, чтобы определить поведение службы при действиях по умолчанию, таких как запуск, остановка или перезапуск, а также при выполнении определенных пользователем действий. Следующий фрагмент из init-скрипта postfix показывает блок кода, который должен быть выполнен при запуске сервиса.

conf_check() {
    [ -x /usr/sbin/postfix ] || exit 5
    [ -d /etc/postfix ] || exit 6
    [ -d /var/spool/postfix ] || exit 5
}
 
make_aliasesdb() {
	if [ "$(/usr/sbin/postconf -h alias_database)" == "hash:/etc/aliases" ]
	then
		# /etc/aliases.db might be used by other MTA, make sure nothing
		# has touched it since our last newaliases call
		[ /etc/aliases -nt /etc/aliases.db ] ||
			[ "$ALIASESDB_STAMP" -nt /etc/aliases.db ] ||
			[ "$ALIASESDB_STAMP" -ot /etc/aliases.db ] || return
		/usr/bin/newaliases
		touch -r /etc/aliases.db "$ALIASESDB_STAMP"
	else
		/usr/bin/newaliases
	fi
}
 
start() {
	[ "$EUID" != "0" ] && exit 4
	# Check that networking is up.
	[ ${NETWORKING} = "no" ] && exit 1
	conf_check
	# Start daemons.
	echo -n $"Starting postfix: "
	make_aliasesdb >/dev/null 2>&1
	[ -x $CHROOT_UPDATE ] && $CHROOT_UPDATE
	/usr/sbin/postfix start 2>/dev/null 1>&2 && success || failure $"$prog start"
	RETVAL=$?
	[ $RETVAL -eq 0 ] && touch $lockfile
        echo
	return $RETVAL
}

Init-скрипт позволяет указать пользовательские функции, здесь это conf_check() и make_aliasesdb(), которые вызываются из функционального блока start(). В приведенном выше коде упоминаются несколько внешних файлов и директорий: исполняемый файл основного сервиса /usr/sbin/postfix, директории конфигураций /etc/postfix/ и /var/spool/postfix/, а также директория /usr/sbin/postconf/.
Systemd поддерживает только предопределенные действия, но позволяет выполнять пользовательские исполняемые файлы с помощью ExecStart, ExecStartPre, ExecStartPost, ExecStop и ExecReload. В случае с postfix в RHEL 7, /usr/sbin/postfix выполняется вместе со вспомогательными скриптами при запуске сервиса. Посмотрите файл юнита postfix в Примере 10.17, «Файл модуля postfix.service».
Преобразование сложных скриптов требует понимания назначения каждого оператора в скрипте. Некоторые операторы относятся к конкретной версии операционной системы, поэтому вам не нужно переводить их. С другой стороны, в новой среде могут потребоваться некоторые корректировки, как в файле юнита, так и в исполняемом файле сервиса и вспомогательных файлах.

10.6.4. Изменение существующих файлов юнитов

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

  • Создайте директори. для дополнительных файлов конфигурации в /etc/systemd/system/unit.d/. Этот метод рекомендуется в большинстве случаев. Это позволяет расширить конфигурацию дополнительными функциональными возможностями, ссылаясь при этом на исходный файл юнита. Поэтому изменения в юните, поисходящие при обновлении пакета, применяются автоматически. См. Раздел «Расширение конфигурации юнита по умолчанию» для получения дополнительной информации.
  • Создайте копию файла юнита из /usr/lib/systemd/system/ в /etc/systemd/system/ и делайте изменения в ней. Копия переопределяет исходный файл, поэтому изменения, внесенные обновлением пакета, не применяются. Этот метод полезен для внесения значительных изменений в юниты, которые должны сохраняться независимо от обновлений пакета. Подробнее см. в разделе «Переопределение конфигурации модуля по умолчанию».

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

systemctl daemon-reload

Опция daemon-reload перезагружает все файлы юнитов и воссоздает все дерево зависимостей для применения любых изменений в файлах юнитов. Того же результата можно добиться с помощью следующей команды:

init q

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

systemctl restart name.service

Важно
Чтобы изменить свойства (такие как зависимости или тайм-ауты) сервиса, который обрабатывается init-скриптом SysV, не изменяйте сам init-скрипт. Вместо этого создайте системный файл конфигурации systemd для службы, как описано в разделе «Расширение конфигурации юнита по умолчанию» и в разделе «Переопределение конфигурации юнита по умолчанию». Затем управляйте этим сервисом так же, как обычным сервисом systemd.
Например, чтобы расширить конфигурацию сервиса network, не изменяйте init-файл /etc/rc.d/init.d/network. Вместо этого создайте новую директорию /etc/systemd/system/network.service.d/ и drop-in файл /etc/systemd/system/network.service.d/my_config.conf (прим. переводчика: для себя я определяю drop-in файлы как дополнительные конфиги. Система заглядывает в каталоги конфигурации и подбирает то, что там лежит). Затем поместите измененные значения в drop-in файл. Заметка: systemd знает сервис network как network.service, поэтому созданный каталог должен называться network.service.d.

Расширение конфигурации юнитов

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

mkdir /etc/systemd/system/name.service.d/

Замените name именем сервиса, который вы хотите расширить. Вышеуказанный синтаксис применяется ко всем типам юнитов.
Создайте файл конфигурации в директории, созданной на предыдущем шаге. Имя файла должно иметь суффикс .conf . Наберите:

touch /etc/systemd/system/name.service.d/config_name.conf

Замените config_name на имя файла конфигурации. Этот файл имеет структуру обычного файла юнита, поэтому все директивы должны быть указаны в соответствующих разделах, см. Раздел 10.6.1, «Понимание структуры файла юнита».
Например, чтобы добавить зависимость, создайте файл конфигурации со следующим содержимым:

[Unit]
Requires=new_dependency
After=new_dependency

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

[Service]
Restart=always
RestartSec=30

Рекомендуется создавать небольшие файлы конфигураций, ориентированные на одну задачу. Такие файлы легко переместить или связать (создать линк) с каталогами конфигурации других сервисов.
Чтобы внесенные изменения вступили в силу, выполните от root:

systemctl daemon-reload
systemctl restart name.service

Пример 10.20. Расширение конфигурации httpd.service

Изменим юнит httpd.service так, чтобы при запуске Apache автоматически выполнялся shell-скрипт. Создайте каталог и файл конфигурации:

~]# mkdir /etc/systemd/system/httpd.service.d/
~]# touch /etc/systemd/system/httpd.service.d/custom_script.conf

Предположим, что /usr/local/bin/custom.sh – путь к скрипту, который вы хотите запустить вместе с Apache, вставьте следующий текст в файл custom_script.conf:

[Service]
ExecStartPost=/usr/local/bin/custom.sh

Чтобы принять изменения, выполните:

~]# systemctl daemon-reload
~]# systemctl restart httpd.service

Заметка

Файлы конфигурации из директорий /etc/systemd/system/ имеют приоритет над файлами юнитов в /usr/lib/systemd/system/. Следовательно, если файлы конфигурации содержат параметр, который может быть указан только один раз, например, Description или ExecStart, значение по умолчанию для этого параметра переопределяется. Обратите внимание, что в выходных данных команды systemd-delta, описанной в разделе «Мониторинг переопределенных юнитов», такие юниты всегда помечаются как [EXTENDED], хотя фактически некоторые параметры переопределяются.

Переопределение конфигурации юнита по умолчанию

Чтобы внести изменения в юнит, которые сохранятся после обновления пакета, сначала скопируйте файл в каталог /etc/systemd/system/. Для этого выполните от root:

cp /usr/lib/systemd/system/name.service /etc/systemd/system/name.service

Где name – имя сервиса, файл юнита которого вы хотите изменить. Этот синтаксис применим ко всем типам юнитов.
Откройте скопированный файл в текстовом редакторе и внесите желаемые изменения. Чтобы принять изменения, выполните от root:

systemctl daemon-reload
systemctl restart name.service

Пример 10.21. Изменение тайм-аута

Вы можете указать тайм-аут для каждой службы, чтобы предотвратить зависание системы из-за сбоя в работе службы. Обычно, тайм-аут установлен в 90 секунд для обычных сервисов и 300 секунд для SysV-совместимых сервисов.
Например, установим тайм-аут для httpd сервиса:

  1. Скопируйте юнит-файл httpd в директорию /etc/systemd/system/:
    cp /usr/lib/systemd/system/httpd.service /etc/systemd/system/httpd.service
  2. Откройте файл /etc/systemd/system/httpd.service и определите значение TimeoutStartUSec в секции [Service]:
    ...
    [Service]
    ...
    PrivateTmp=true
    TimeoutStartSec=10
     
    [Install]
    WantedBy=multi-user.target
    ...
  3. Перезагрузите демон systemd:
    systemctl daemon-reload
  4. Проверьте, что новый тайм-аут установлен:
    systemctl show httpd -p TimeoutStartUSec

Заметка
Чтобы сменить тайм-аут глобально, введите значение DefaultTimeoutStartSec в файл /etc/systemd/system.conf. Подробнее см. раздел 10.1, “Введение в systemd”.

Мониторинг переопределенных юнитов

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

systemd-delta

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

[EQUIVALENT] /etc/systemd/system/default.target → /usr/lib/systemd/system/default.target
[OVERRIDDEN] /etc/systemd/system/autofs.service → /usr/lib/systemd/system/autofs.service
 
--- /usr/lib/systemd/system/autofs.service      2014-10-16 21:30:39.000000000 -0400
+++ /etc/systemd/system/autofs.service  2014-11-21 10:00:58.513568275 -0500
@@ -8,7 +8,8 @@
 EnvironmentFile=-/etc/sysconfig/autofs
 ExecStart=/usr/sbin/automount $OPTIONS --pid-file /run/autofs.pid
 ExecReload=/usr/bin/kill -HUP $MAINPID
-TimeoutSec=180
+TimeoutSec=240
+Restart=Always
 
 [Install]
 WantedBy=multi-user.target
 
[MASKED]     /etc/systemd/system/cups.service → /usr/lib/systemd/system/cups.service
[EXTENDED]   /usr/lib/systemd/system/sssd.service → /etc/systemd/system/sssd.service.d/journal.conf
 
4 overridden configuration files found.

В таблице 10.13 «Типы различий systemd-delta» перечислены типы переопределений, которые можно увидеть в выводе systemd-delta. Обратите внимание, что если файл переопределен, systemd-delta по умолчанию отображает сводку изменений, аналогичную выводу команды diff.

Таблица 10.13, Типы различий systemd-delta
Опция LSB Описание
[MASKED] Замаскированные юниты. Как замаскировать юнит см. Раздел 10.2.7, “Удаление из автозагрузки”.
[EQUIVALENT] Неизмененные копии, которые переопределяют исходные файлы, но не отличаются по содержанию, как правило, это символические ссылки.
[REDIRECTED] Файлы, которые перенаправляют в другой файл.
[OVERRIDEN] Перезаписанные и измененные файлы.
[EXTENDED] Файлы, которые расширены файлами .conf в директории /etc/systemd/system/unit.d/.
[UNCHANGED] Неизмененные файлы, отображаются при использовании опции --type=unchanged.

Рекомендуется запускать systemd-delta после обновления системы, чтобы проверить, есть ли какие-либо обновления для юнитов по умолчанию, которые в настоящее время переопределяются пользовательской конфигурацией. Также можно ограничить вывод только определенным типом различий. Например, чтобы просмотреть только переопределенные блоки [OVERRIDEN], выполните:

systemd-delta --type=overridden

10.6.5. Работа с юнитами, созданными из шаблона (Instantiated Units)

Можно создать несколько экземпляров из одного файла конфигурации шаблона во время выполнения. Символ «@» используется для обозначения шаблона и ассоциации юнита с ним. Instantiated units могут быть запущены из другого файла юнита (с использованием параметров Requires или Wants) или с помощью команды systemctl start. Instantiated service units именуются следующим образом:

template_name@instance_name.service

Где template_name – имя файла конфигурации шаблона. Замените instance_name именем экземпляра юнита. Несколько экземпляров могут указывать на один и тот же файл шаблона с параметрами конфигурации, общими для всех экземпляров юнита. Имя шаблона юнита имеет вид:

unit_name@.service

Например, следующая настройка Wants в файле юнита:

Wants=getty@ttyA.service,getty@ttyB.service

сначала выполняет поиск для заданных сервисных юнитов. Если таких юнитов не найдено, часть между “@” и суффиксом типа игнорируется, и systemd ищет файл getty@.service, считывает из него конфигурацию и запускает сервисы.
Подстановочные знаки, называемые спецификаторами единиц, могут использоваться в любом файле конфигурации юнитов. Спецификаторы юнита заменяют определенные параметры модуля и интерпретируются во время выполнения. В таблице 10.14 «Важные спецификаторы юнитов» перечислены полезные для юнитов-шаблонов спецификаторы юнитов.

Таблица 10.14, Важные спецификаторы юнитов
Спецификатор Значение Описание
%n Полное имя юнита Полное имя юнита, включая суффикс. %N имеет то же значение, но также заменяет запрещенные символы на коды ASCII.
%p Префикс Имя юнита без суффикса типа. Для созданных экземпляров юнитов %p обозначает часть имени юнита перед символом «@».
%i Instance name Имя экземпляра Это часть имени экземпляра юнита между символом «@» и суффиксом типа. %I имеет то же значение, но также заменяет запрещенные символы на коды ASCII.
%H Host name Имя хоста Имя хоста работающей системы в момент загрузки конфигурации юнита.
%t Runtime directory Represents the runtime directory, which is either /run for the root user, or the value of the XDG_RUNTIME_DIR variable for unprivileged users.
Представляет собой runtime-директорию, которая либо /run для пользователя root, либо значение из переменной окружения XDG_RUNTIME_DIR для непривилегированных пользователей.

Полный список спецификаторов см. в мануале systemd.unit(5).

Например, шаблон getty@.service содержит следующие директивы:

[Unit]
Description=Getty on %I
...
[Service]
ExecStart=-/sbin/agetty --noclear %I $TERM
...

Когда создаются экземпляры getty@ttyA.service и getty@ttyB.service из вышеприведенного шаблона, Description = преобразуется в Getty on ttyA и Getty on ttyB.

10.7. Additional Resources – этот раздел я не вижу смысла переводить, так как он просто содержит ссылки на дополнительные источники информации. Но оставлю его тут)

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *