Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50c0e1a158 | ||
|
|
c64fc681b2 |
174
s4a.tex
174
s4a.tex
@@ -16,6 +16,7 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
|
|||||||
% Несколько сокращений
|
% Несколько сокращений
|
||||||
\newcommand{\sectiona}[1]{\section*{#1}\addcontentsline{toc}{section}{#1}}
|
\newcommand{\sectiona}[1]{\section*{#1}\addcontentsline{toc}{section}{#1}}
|
||||||
\newcommand{\hreftt}[2]{\href{#1}{\texttt{#2}}}
|
\newcommand{\hreftt}[2]{\href{#1}{\texttt{#2}}}
|
||||||
|
\newcommand{\llangl}{\reflectbox{\rotatebox[origin=c]{270}{$\neg$}}}
|
||||||
% Настройка макета страницы
|
% Настройка макета страницы
|
||||||
\setlength{\hoffset}{-1.5cm}
|
\setlength{\hoffset}{-1.5cm}
|
||||||
\addtolength{\textwidth}{2cm}
|
\addtolength{\textwidth}{2cm}
|
||||||
@@ -2110,6 +2111,179 @@ systemd?
|
|||||||
+exec+. После чего достаточно просто указать этот скрипт в опции +ExecStart=+
|
+exec+. После чего достаточно просто указать этот скрипт в опции +ExecStart=+
|
||||||
вместо бинарника демона.
|
вместо бинарника демона.
|
||||||
|
|
||||||
|
\section{Экземпляры служб}
|
||||||
|
|
||||||
|
Большинство служб в Linux/Unix являются одиночными (singleton): в каждый момент
|
||||||
|
времени на данном хосте работает только один экземпляр службы. В качестве
|
||||||
|
примера таких одиночных служб можно привести Syslogd, Postfix, Apache. Однако,
|
||||||
|
существуют службы, запускающие по несколько экземпляров себя на одном хосте.
|
||||||
|
Например, службы наподобие Dovecot IMAP запускают по одному экземпляру на каждый
|
||||||
|
локальный порт и/или IP-адрес. Другой пример, который можно встретить
|
||||||
|
практически во всех системах~--- \emph{getty}, небольшая служба, запускающаяся на
|
||||||
|
каждом TTY (от +tty1+ до +tty6+). На некоторых серверах, в зависимости от
|
||||||
|
сделанных администратором настроек или параметров загрузки, могут запускаться
|
||||||
|
дополнительные экземпляры getty, для подключаемых к COM-портам терминалов или
|
||||||
|
для консоли системы виртуализации. Еще один пример службы, работающей в
|
||||||
|
нескольких экземплярах (по крайней мере, в мире systemd)~--- \emph{fsck},
|
||||||
|
программа проверки файловой системы, которая запускается по одному экземпляру
|
||||||
|
на каждое блочное устройство, требующее такой проверки. И наконец, стоит
|
||||||
|
упомянуть службы с активацией в стиле inetd~--- при обращении через сокет, по
|
||||||
|
одному экземпляру на каждое соединение. В этой статье я попытаюсь рассказать,
|
||||||
|
как в systemd реализовано управление <<многоэкземплярными>> службами, и какие
|
||||||
|
выгоды системный администратор может извлечь из этой возможности.
|
||||||
|
|
||||||
|
Если вы читали предыдущие статьи из этого цикла, вы, скорее всего, уже знаете,
|
||||||
|
что службы systemd именуются по схеме \emph{foobar}+.service+, где
|
||||||
|
\emph{foobar}~--- строка, идентифицирующая службу (проще говоря, ее имя), а
|
||||||
|
+.service+~--- суффикс, присутствующий в именах всех файлов конфигурации служб.
|
||||||
|
Сами эти файлы могут находиться в каталогах +/etc/systemd/systemd+ и
|
||||||
|
+/lib/systemd/system+ (а также, возможно, и в других). Для служб, работающих в
|
||||||
|
нескольких экземплярах, эта схема становится немного сложнее:
|
||||||
|
\emph{foobar}+@+\emph{quux}+.service+, где \emph{foobar}~--- имя службы,
|
||||||
|
общее для всех экземпляров, а \emph{quux}~--- идентификатор конкретного
|
||||||
|
экземпляра. Например, +serial-gett@ttyS2.service+~--- это служба getty для
|
||||||
|
COM-порта, запущенная на +ttyS2+.
|
||||||
|
|
||||||
|
При необходимости, экземпляры служб можно легко создать динамически. Скажем, вы
|
||||||
|
можете, безо всяких дополнительных настроек, запустить новый экземпляр getty на
|
||||||
|
последовательном порту, просто выполнив +systemctl start+ для нового экземпляра:
|
||||||
|
\begin{Verbatim}
|
||||||
|
# systemctl start serial-getty@ttyUSB0.service
|
||||||
|
\end{Verbatim}
|
||||||
|
|
||||||
|
Получив такую команду, systemd сначала пытается найти файл конфигурации юнита с
|
||||||
|
именем, точно соответствующим запрошенному. Если такой файл найти не~удается
|
||||||
|
(при работе с экземплярами сервисов обычно так и происходит), из имени файла
|
||||||
|
удаляется идентификатор экземпляра, и полученное имя используется при поиске
|
||||||
|
\emph{шаблона} конфигурации. В нашем случае, если отсутствует файл с именем
|
||||||
|
+serial-getty@ttyUSB0.service+, используется файл-шаблон под названием
|
||||||
|
+serial-getty@.service+. Таким образом, для всех экземпляров данной службы,
|
||||||
|
используется один и тот же шаблон конфигурации. В случае с getty для COM-портов,
|
||||||
|
этот шаблон, поставляемый в комплекте с systemd
|
||||||
|
(файл +/lib/systemd/system/serial-getty@.service+) выглядит примерно так:
|
||||||
|
\begin{Verbatim}
|
||||||
|
[Unit]
|
||||||
|
Description=Serial Getty on %I
|
||||||
|
BindTo=dev-%i.device
|
||||||
|
After=dev-%i.device systemd-user-sessions.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=-/sbin/agetty -s %I 115200,38400,9600
|
||||||
|
Restart=always
|
||||||
|
RestartSec=0
|
||||||
|
\end{Verbatim}
|
||||||
|
(Заметим, что приведенная здесь версия немного сокращена, по сравнению с реально
|
||||||
|
используемой в systemd. Удалены не~относящиеся к теме нашего обсуждения
|
||||||
|
параметры конфигурации, обеспечивающие совместимость с SysV, очистку экрана и
|
||||||
|
удаление предыдущих пользователей с текущего TTY. Если вам интересно, можете
|
||||||
|
посмотреть
|
||||||
|
\href{http://cgit.freedesktop.org/systemd/plain/units/serial-getty@.service.m4}{полную
|
||||||
|
версию}.)
|
||||||
|
|
||||||
|
Этот файл похож на обычный файл конфигурации юнита, с единственным отличием: в
|
||||||
|
нем используются спецификаторы \%I и \%i. В момент загрузки юнита, systemd
|
||||||
|
заменяет эти спецификаторы на идентификатор экземпляра службы. В нашем случае,
|
||||||
|
при обращении к экземпляру +serial-getty@ttyUSB0.service+, они заменяются на
|
||||||
|
<<+ttyUSB0+>>. Результат этой замены можно проверить, например, запросив
|
||||||
|
состояние для этой службы:
|
||||||
|
\begin{Verbatim}[commandchars=\\\{\}]
|
||||||
|
$ systemctl status serial-getty@ttyUSB0.service
|
||||||
|
serial-getty@ttyUSB0.service - Getty on ttyUSB0
|
||||||
|
Loaded: loaded (/lib/systemd/system/serial-getty@.service; static)
|
||||||
|
Active: active (running) since Mon, 26 Sep 2011 04:20:44 +0200; 2s ago
|
||||||
|
Main PID: 5443 (agetty)
|
||||||
|
CGroup: name=systemd:/system/getty@.service/ttyUSB0
|
||||||
|
\llangl{} 5443 /sbin/agetty -s ttyUSB0 115200,38400,9600
|
||||||
|
\end{Verbatim}
|
||||||
|
Собственно, это и есть ключевая идея организации экземпляров служб. Как видите,
|
||||||
|
systemd предоставляет простой в использовании механизм шаблонов, позволяющих
|
||||||
|
динамически создавать экземпляры служб. Добавим несколько дополнительных
|
||||||
|
замечаний, позволяющих эффективно использовать этот механизм:
|
||||||
|
|
||||||
|
Вы можете создавать дополнительные экземпляры таких служб, просто добавляя
|
||||||
|
символьные ссылки в каталоги +*.wants/+. Например, чтобы обеспечить запуск getty
|
||||||
|
на ttyUSB0 при каждой загрузке, достаточно создать такую ссылку:
|
||||||
|
\begin{Verbatim}
|
||||||
|
# ln -s /lib/systemd/system/serial-getty@.service \
|
||||||
|
/etc/systemd/system/getty.target.wants/serial-getty@ttyUSB0.service
|
||||||
|
\end{Verbatim}
|
||||||
|
При этом файл конфигурации, на который указывает ссылка (в нашем случае
|
||||||
|
+serial-getty@.service+), будет вызван с тем именем экземпляра, которое указанно
|
||||||
|
в названии этой ссылки (в нашем случае~--- +ttyUSB0+).
|
||||||
|
|
||||||
|
Вы не~сможете обратиться к юниту-шаблону без указания идентификатора экземпляра.
|
||||||
|
В частности, команда +systemctl start serial-getty@.service+ завершится ошибкой.
|
||||||
|
|
||||||
|
Иногда возникает необходимость отказаться от использования общего шаблона
|
||||||
|
для конкретного экземпляра (т.е. конфигурация данного экземпляра настолько
|
||||||
|
сильно отличается от конфигурации остальных экземпляров данной службы, что
|
||||||
|
механизм шаблонов оказывается неэффективен). Специально для таких случаев, в
|
||||||
|
systemd и заложен предварительный поиск файла с именем, точно соответствующим
|
||||||
|
указанному (прежде чем использовать общий шаблон). Таким образом, вы можете
|
||||||
|
поместить файл с именем, точно соответствующим полному титулу экземпляра, в
|
||||||
|
каталог +/etc/systemd/system/+~--- и содержимое этого файла, при обращении
|
||||||
|
к выбранному экземпляру, полностью перекроет все настройки, сделанные в общем
|
||||||
|
шаблоне.
|
||||||
|
|
||||||
|
В приведенном выше файле, в некоторых местах используется спецификатор +%I+, а
|
||||||
|
в других~--- +%i+. У вас может возникнуть закономерный вопрос~--- чем они
|
||||||
|
отличаются? +%i+ всегда точно соответствует идентификатору экземпляра, в то
|
||||||
|
время, как +%I+ соответствует экранированной (escaped) версии этого
|
||||||
|
идентификатора. Когда идентификатор не~содержит спецсимволов (например,
|
||||||
|
+ttyUSB0+). Но имена устройств, например, содержат слеши (<</>>), которые
|
||||||
|
не~могут присутствовать в имени юнита (и в имени файла на Unix). Поэтому, перед
|
||||||
|
использованием такого имени в качестве идентификатора устройства, оно должно
|
||||||
|
быть экранировано~--- <</>> заменяются на <<->>, а большинство других
|
||||||
|
специальных символов (включая <<->>) заменяются последовательностями вида
|
||||||
|
+\xAB+, где AB~--- ASCII-код символа, записанный в шестнадцатеричной системе
|
||||||
|
счисления\footnote{Согласен, этот алгоритм дает на выходе не~очень читабельный
|
||||||
|
результат. Но этим грешат практически все алгоритмы экранирования. В данном
|
||||||
|
случае, были использован механизм экранирования из udev, с одним изменением. В
|
||||||
|
конце концов, нам нужно было выбрать что-то. Если вы собираетесь комментировать
|
||||||
|
наш алгоритм экранирования~--- пожалуйста, также укажите, где вы живете, чтобы я
|
||||||
|
мог приехать к вам и раскрасить ваш велосипедный гараж в синий с желтыми
|
||||||
|
полосами. Спасибо!}\,\footnote{Прим. перев.: В предыдущем примечании автор снова
|
||||||
|
намекает на Паркинсовский Закон Тривиальности. Действительно, выбор алгоритма
|
||||||
|
экранирования практически не~влияет ни на работу systemd, ни на управлением им
|
||||||
|
(файлы/юниты с экранированными именами, как правило либо создаются специальными
|
||||||
|
программами-генераторами, либо формируются systemd на лету; при выводе состояния
|
||||||
|
показываются и неэкранированные имена; при вводе команд, как обычно, на
|
||||||
|
помощь приходит автодополнение оболочки).}. Например, чтобы обратиться
|
||||||
|
последовательному USB-порту по его адресу на шине, нам нужно использовать имя
|
||||||
|
наподобие +serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0+. Экранированная
|
||||||
|
версия этого имени~---
|
||||||
|
+serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0+. +%I+ будет
|
||||||
|
ссылаться на первую из этих строк, +%i+~--- на вторую. С практической точки
|
||||||
|
зрения, это означает, что спецификатор +%i+ можно использовать в том случае,
|
||||||
|
когда надо сослаться на имена других юнитов, например, чтобы описать
|
||||||
|
дополнительные зависимости (в случае с +serial-getty@.service+, этот
|
||||||
|
спецификатор используется для ссылки на юнит +dev-%i.device+, соответствующий
|
||||||
|
одноименному устройству). В то время как +%I+ удобно использовать в командной
|
||||||
|
строке (+ExecStart+) и для формирования читабельных строк описания. Рассмотрим
|
||||||
|
работу этих принципов на примере нашего юнит-файла:
|
||||||
|
\begin{landscape}
|
||||||
|
\begin{Verbatim}[fontsize=\small]
|
||||||
|
# systemctl start 'serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.service'
|
||||||
|
# systemctl status 'serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.service'
|
||||||
|
serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.service - Serial Getty on serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0
|
||||||
|
Loaded: loaded (/lib/systemd/system/serial-getty@.service; static)
|
||||||
|
Active: active (running) since Mon, 26 Sep 2011 05:08:52 +0200; 1s ago
|
||||||
|
Main PID: 5788 (agetty)
|
||||||
|
CGroup: name=systemd:/system/serial-getty@.service/serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0
|
||||||
|
5788 /sbin/agetty -s serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0 115200 38400 9600
|
||||||
|
\end{Verbatim}
|
||||||
|
\end{landscape}
|
||||||
|
Как видите, в качестве идентификатора экземпляра используется экранированная
|
||||||
|
версия, в то время как в строке описания и в командной строке +getty+
|
||||||
|
используется неэкранированная версия. Как и предполагалось.
|
||||||
|
|
||||||
|
(Небольшое замечание: помимо +%i+ и +%I+, существует еще несколько
|
||||||
|
спецификаторов, и большинство из них доступно и в обычных файлах конфигурации
|
||||||
|
юнитов, а не~только в шаблонах. Подробности можно посмотреть на
|
||||||
|
\href{http://0pointer.de/public/systemd-man/systemd.unit.html}{странице
|
||||||
|
руководства}, содержащей полный перечень этих спецификаторов с краткими
|
||||||
|
пояснениями.)
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
||||||
|
|
||||||
vim:ft=tex:tw=80:spell:spelllang=ru
|
vim:ft=tex:tw=80:spell:spelllang=ru
|
||||||
|
|||||||
Reference in New Issue
Block a user