Compare commits

...

4 Commits
v12.0 ... v13.2

Author SHA1 Message Date
nnz1024
a0a5e1f4ac Version v13.2 (2012-11-23 19:56) [AUTO] 2017-08-17 23:05:39 +03:00
nnz1024
e66acaaf28 Version v13.1 (2012-10-28 03:50) [AUTO] 2017-08-17 23:05:39 +03:00
nnz1024
0d4aa4ac00 Version v13.0 (2012-07-17 18:57) [AUTO] 2017-08-17 23:05:39 +03:00
nnz1024
6c4fa8f89f Version v12.1 (2012-07-13 20:45) [AUTO] 2017-08-17 23:05:39 +03:00

804
s4a.tex
View File

@@ -2,7 +2,7 @@
\usepackage{cmap} % Copy-paste из PDF без проблем с кодировкой
\usepackage[utf8]{inputenc}
\usepackage[english,russian]{babel} % Русские переносы и проч.
\usepackage{graphicx,color}
\usepackage{graphicx,color,pmboxdraw}
\usepackage[T1,T2A]{fontenc}
\usepackage{indentfirst} % Отступ в первом абзаце главы
\usepackage{fancyvrb} % Продвинутые листинги и in-line commands
@@ -18,18 +18,8 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
% Несколько сокращений
\newcommand{\sectiona}[1]{\section*{#1}\addcontentsline{toc}{section}{#1}}
\newcommand{\hreftt}[2]{\href{#1}{\texttt{#2}}}
\newcommand{\tbs}{\textbackslash}
\newcommand{\hrf}[2]{\href{#1}{#2}}
\newenvironment{caveat}[1][]{\smallskip\par\textbf{Предупреждение#1: }}%
{\smallskip\par}
% Примерный аналог символа \testSFii (присутствует в листингах),
% но без использования пакета pmboxdraw, средствами graphicx
\newcommand{\mytextSFii}{\raisebox{0pt}[0pt][\depth]{%
\reflectbox{\rotatebox[origin=t]{270}{$\neg$}}}}
% Из-за бага в пакете fancyvrb, в окружениях Verbatim нельзя использовать URL,
% содержащие дефисы. Поэтому их определение приходится выносить за пределы
% окружения
\newcommand{\defhref}[3]{\newcommand{#1}{\href{#2}{#3}}}
% Настройка макета страницы
\setlength{\hoffset}{-1.5cm}
\addtolength{\textwidth}{2cm}
@@ -207,7 +197,11 @@ JOB = Pending job for the unit.
внимательно посмотрев на листинг выше, вы можете заметить, что служба ntpd
(сервер точного времени) находится в состоянии, обозначенном как maintenance.
Чтобы узнать, что же произошло с ntpd, воспользуемся командой
+systemctl status+:
+systemctl status+\footnote{Прим. перев.: Стоит заметить, что формат вывода
данной команды менялся по мере развития systemd~--- появлялись дополнительные
поля с информацией, был добавлен вывод журнала службы
(см.~главу~\ref{sec:journal}) и т.д. Здесь приведен пример вывода этой команды
на момент написания исходной статьи (лето 2010 года).}:
\begin{Verbatim}[commandchars=\\\{\}]
[root@lambda] ~# systemctl status ntpd.service
ntpd.service - Network Time Service
@@ -1499,23 +1493,25 @@ $ systemd-analyze blame
значительно меньше, чем сумма времен инициализации каждой из них.
Рассмотрим повнимательнее первого осквернителя нашей загрузки: службу
+udev-settle.service+. Почему ей требуется так много времени для запуска, и что
мы можем с этим сделать? Данная служба выполняет очень простую функцию: она
ожидает, пока udev завершит опрос устройств, после чего завершается. Опрос же
устройств может занимать довольно много времени. Например, в нашем случае опрос
устройств длится более 6~секунд из-за подключенного к компьютеру 3G-модема, в
котором отсутствует SIM-карта. Этот модем очень долго отвечает на запросы udev.
Опрос устройств является частью схемы, обеспечивающей работу ModemManager'а и
позволяющей NetworkManager'у упростить для вас настройку 3G. Казалось бы,
очевидно, что виновником задержки является именно ModemManager, так как опрос
устройств для него занимает слишком много времени. Но такое обвинение будет
заведомо ошибочным. Дело в том, что опрос устройств очень часто оказывается
довольно длительной процедурой. Медленный опрос 3G-устройств для ModemManager
является частным случаем, отражающим это общее правило. Хорошая система опроса
устройств обязательно должна учитывать тот факт, что операция опроса любого из
устройств может затянуться надолго. Истинной причиной наших проблем является
необходимость ожидать завершения опроса, т.е., наличие службы
+udev-settle.service+ как обязательной части нашего процесса загрузки.
+udev-settle.service+\footnote{Прим. перев.: После объединения проектов systemd
и udev, эта служба называется +systemd-udev-settle.service+.} Почему ей
требуется так много времени для запуска, и что мы можем с этим сделать? Данная
служба выполняет очень простую функцию: она ожидает, пока udev завершит опрос
устройств, после чего завершается. Опрос же устройств может занимать довольно
много времени. Например, в нашем случае опрос устройств длится более 6~секунд
из-за подключенного к компьютеру 3G-модема, в котором отсутствует SIM-карта.
Этот модем очень долго отвечает на запросы udev. Опрос устройств является
частью схемы, обеспечивающей работу ModemManager'а и позволяющей
NetworkManager'у упростить для вас настройку 3G. Казалось бы, очевидно, что
виновником задержки является именно ModemManager, так как опрос устройств для
него занимает слишком много времени. Но такое обвинение будет заведомо
ошибочным. Дело в том, что опрос устройств очень часто оказывается довольно
длительной процедурой. Медленный опрос 3G-устройств для ModemManager является
частным случаем, отражающим это общее правило. Хорошая система опроса устройств
обязательно должна учитывать тот факт, что операция опроса любого из устройств
может затянуться надолго. Истинной причиной наших проблем является необходимость
ожидать завершения опроса, т.е., наличие службы +udev-settle.service+ как
обязательной части нашего процесса загрузки.
Но почему эта служба вообще присутствует в нашем процессе загрузки? На самом
деле, мы можем прекрасно обойтись и без нее. Она нужна лишь как часть
@@ -2218,14 +2214,14 @@ RestartSec=0
при обращении к экземпляру +serial-getty@ttyUSB0.service+, они заменяются на
<<+ttyUSB0+>>. Результат такой замены можно проверить, например, запросив
состояние для нашей службы:
\begin{Verbatim}[commandchars=\\\{\}]
\begin{Verbatim}
$ 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
\mytextSFii{} 5443 /sbin/agetty -s ttyUSB0 115200,38400,9600
5443 /sbin/agetty -s ttyUSB0 115200,38400,9600
\end{Verbatim}
Собственно, это и есть ключевая идея организации экземпляров служб. Как видите,
systemd предоставляет простой в использовании механизм шаблонов, позволяющих
@@ -2235,8 +2231,8 @@ systemd предоставляет простой в использовании
Вы можете создавать дополнительные экземпляры таких служб, просто добавляя
символьные ссылки в каталоги +*.wants/+. Например, чтобы обеспечить запуск getty
на ttyUSB0 при каждой загрузке, достаточно создать такую ссылку:
\begin{Verbatim}[commandchars=\\\{\}]
# ln -s /lib/systemd/system/serial-getty@.service \tbs{}
\begin{Verbatim}
# ln -s /lib/systemd/system/serial-getty@.service \
/etc/systemd/system/getty.target.wants/serial-getty@ttyUSB0.service
\end{Verbatim}
При этом файл конфигурации, на который указывает ссылка (в нашем случае
@@ -2292,7 +2288,7 @@ systemd и заложен предварительный поиск файла
наличии в оболочке <<умного>> автодополнения. Однако, начиная с systemd v186,
при работе с +systemctl+ можно указывать неэкранированные имена юнитов.}:
\begin{landscape}
\begin{Verbatim}[fontsize=\small,commandchars=|\{\}]
\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
@@ -2300,7 +2296,7 @@ serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.
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
|mytextSFii{} 5788 /sbin/agetty -s serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0 115200 38400 9600
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}
Как видите, в качестве идентификатора экземпляра используется экранированная
@@ -2644,7 +2640,10 @@ MAC, от Mandatory Access Control), например, SELinux. Если вам
Linux уже очень давно, но при этом практически неизвестных для большинства
разработчиков. Мы постарались сделать соответствующие опции systemd максимально
простыми в использовании, чтобы заинтересовать администраторов и апстримных
разработчиков. Вот краткий перечень наиболее интересных возможностей:
разработчиков. Вот краткий перечень наиболее интересных
возможностей\footnote{Прим. перев.: В приведенном здесь списке не~упомянута
встроенная в systemd поддержка фильтров seccomp, так как она была добавлена уже
после написания исходной статьи.}:
\begin{itemize}
\item Изолирование служб от сети
\item Предоставление службам независимых каталогов +/tmp+
@@ -2748,7 +2747,7 @@ PrivateTmp=yes
сокеты (впрочем, в данном конкретном случае некоторые меры безопасности все же
присутствуют: сокеты размещаются в защищенном подкаталоге, который создается на
ранних стадиях загрузки). Разумеется, для служб, использующих +/tmp+ в целях
коммуникации, включение опции +PrivateTmp=yes+ недопустимо. К счастью, таких
коммуникации, включение опции +PrivateTmp=yes+ недопустимо. К счастью, подобных
служб сейчас уже не~так уж и много.
\end{caveat}
@@ -2770,7 +2769,7 @@ InaccessibleDirectories=/home
ReadOnlyDirectories=/var
...
\end{Verbatim}
Добавление этих двух строчек в файл конфигурации, приводит к тому, что служба
Добавление этих двух строчек в файл конфигурации приводит к тому, что служба
полностью утрачивает доступ к содержимому каталога +/home+ (она видит лишь
пустой каталог с правами доступа 000), а также не~может писать внутрь каталога
+/var+.
@@ -2866,7 +2865,7 @@ LimitFSIZE=0
...
\end{Verbatim}
Обратите внимание, что эти ограничения будут эффективно работать только в том
случае, если служба будет работать от имени простого пользователя (не~root) и
случае, если служба запускается от имени простого пользователя (не~root) и
без привилегии +CAP_SYS_RESOURCE+ (блокирование этой привилегии можно
обеспечить, например, описанной выше опцией +CapabilityBoundingSet=+). В
противном случае, ничто не~мешает процессу поменять соответствующие ограничения.
@@ -2931,6 +2930,7 @@ systemd.
чуть более безопасным.
\section{Отчет о состоянии службы и ее журнал}
\label{sec:journal}
При работе с системами, использующими systemd, одной из наиболее важных и часто
используемых команд является +systemctl status+. Она выводит отчет о состоянии
@@ -2952,7 +2952,7 @@ systemd.
Итак, мы интегрировали Journal в systemd, и научили +systemctl+ работать с ним.
Результат выглядит примерно так:
\begin{Verbatim}[fontsize=\small,commandchars=\\\{\}]
\begin{Verbatim}[fontsize=\small]
$ systemctl status avahi-daemon.service
avahi-daemon.service - Avahi mDNS/DNS-SD Stack
Loaded: loaded (/usr/lib/systemd/system/avahi-daemon.service; enabled)
@@ -2960,8 +2960,8 @@ avahi-daemon.service - Avahi mDNS/DNS-SD Stack
Main PID: 8216 (avahi-daemon)
Status: "avahi-daemon 0.6.30 starting up."
CGroup: name=systemd:/system/avahi-daemon.service
\mytextSFii{} 8216 avahi-daemon: running [omega.local]
\mytextSFii{} 8217 avahi-daemon: chroot helper
8216 avahi-daemon: running [omega.local]
8217 avahi-daemon: chroot helper
May 18 12:27:37 omega avahi-daemon[8216]: Joining mDNS multicast group on interface eth1.IPv4 with address 172.31.0.52.
May 18 12:27:37 omega avahi-daemon[8216]: New relevant interface eth1.IPv4 for mDNS.
@@ -3035,19 +3035,20 @@ Unix-администратору при переходе на systemd нужн
можно настроить, может получить ссылки на соответствующую документацию, просто
воспользовавшись давно известной командой +systemctl status+. Возьмем для
примера +systemd-logind.service+:
\defhref{\logind}{http://www.freedesktop.org/software/systemd/man/systemd-logind.service.html}%
{man:systemd-logind.service(7)}
\begin{Verbatim}[fontsize=\small,commandchars=\\\{\}]
\begin{Verbatim}[fontsize=\small,commandchars=\\\{\},%
% В окружении Verbatim ссылки, содержащие знак дефиса/минуса "-",
% повреждаются. Обходим это при помощи черной магии в стиле sysvinit:
codes={\catcode`+=\active},defineactive=\def+{-}]
$ systemctl status systemd-logind.service
systemd-logind.service - Login Service
Loaded: loaded (/usr/lib/systemd/system/systemd-logind.service; static)
Active: active (running) since Mon, 25 Jun 2012 22:39:24 +0200; 1 day and 18h ago
Docs: \logind{}
Docs: \href{http://www.freedesktop.org/software/systemd/man/systemd+logind.service.html}{man:systemd-logind.service(7)}
\href{http://www.freedesktop.org/software/systemd/man/logind.conf.html}{man:logind.conf(5)}
\url{http://www.freedesktop.org/wiki/Software/systemd/multiseat}
Main PID: 562 (systemd-logind)
CGroup: name=systemd:/system/systemd-logind.service
\mytextSFii{} 562 /usr/lib/systemd/systemd-logind
562 /usr/lib/systemd/systemd-logind
Jun 25 22:39:24 epsilon systemd-logind[562]: Watching system buttons on /dev/input/event2 (Power Button)
Jun 25 22:39:24 epsilon systemd-logind[562]: Watching system buttons on /dev/input/event6 (Video Bus)
@@ -3109,7 +3110,7 @@ URI, ссылающиеся на документацию, формируютс
В завершение, стоит отметить, что использованная нами идея не~является такой уж
новой: в SMF, системе инициализации Solaris, уже используется практика
добавления ссылок на документацию в описании службы. Однако, в Linux такой
указания ссылок на документацию в описании службы. Однако, в Linux такой
подход является принципиально новым, и systemd сейчас является наиболее
документированной и прозрачной системой загрузки для данной платформы.
@@ -3137,8 +3138,8 @@ URI, ссылающиеся на документацию, формируютс
мобильные/встраиваемые устройства, настольные системы и промышленные серверы.
Мобильные и встраиваемые системы, как правило, располагают очень скромными
ресурсами и вынуждены очень экономно расходовать энергию. Настольные системы
куда менее ограничены по мощности но, тем не~менее, все же проигрывают в этом
плане промышленным серверам. Но, как ни~странно это прозвучит, существуют
уже не~так сильно ограничены по мощности, хотя все же проигрывают в
этом плане промышленным серверам. Но, как ни~странно, существуют
возможности, востребованные в обоих крайних случаях (встраиваемые системы и
серверы), но не~очень актуальные в промежуточной ситуации (десктопы). В
частности, к ним относится поддержка
@@ -3153,17 +3154,17 @@ URI, ссылающиеся на документацию, формируютс
функциональность практически не~востребована\footnote{Тем не~менее, сейчас
аппаратные сторожевые таймеры все чаще появляются и в настольных системах, так
как стоят они относительно дешево и доступны практически во всех современных
чипсетах.}. В то же время, она весьма актуальна для высокодоступных серверных
чипсетах.}. С другой стороны, она весьма актуальна для высокодоступных серверных
систем.
Начиная с версии 183, systemd полностью поддерживает аппаратные сторожевые
таймеры (доступные через интерфейс +/dev/watchdog+), а также обеспечивает
программный сторожевой контроль системных служб. В целом эта схема (если она
задействована) работает так. systemd периодически обращается к аппаратному
задействована) работает так. systemd периодически посылает сигналы аппаратному
таймеру. В том случае, если systemd или ядро зависают, аппаратный таймер,
не~получив очередного обращения, автоматически перезапустит систему. Таким
образом, ядро и systemd защищены от бесконечного зависания на аппаратном уровне.
В то же время, сам systemd предоставляет интерфейс, реализующий логику
не~получив очередного сигнала, автоматически перезапустит систему. Таким
образом, ядро и systemd защищены от бесконечного зависания~--- на аппаратном
уровне. В то же время, сам systemd предоставляет интерфейс, реализующий логику
программных сторожевых таймеров для отдельных служб. Таким образом можно
обеспечить, например, принудительный перезапуск службы в случае ее зависания.
Для каждой службы можно независимо настроить частоту опроса и задать
@@ -3175,11 +3176,11 @@ URI, ссылающиеся на документацию, формируютс
Чтобы задействовать аппаратный таймер, достаточно задать ненулевое значение
параметра +RuntimeWatchdogSec=+ в файле +/etc/systemd/system.conf+. По умолчанию
этот параметр равен нулю (т.е. аппаратный таймер не~задействован). Установив его
равным, например, <<20s>>, мы включим аппаратный сторожевой таймер. Если в
равным, например, <<+20s+>>, мы включим аппаратный сторожевой таймер. Если в
течение 20 секунд таймер не~получит очередного сигнала <<все в порядке>>,
система автоматически перезагрузится. Отметим, что systemd отправляет такие
сигналы с периодом, равным половине заданного интервала~--- в нашем случае,
через каждые 10 секунд. Собственно, это все. Просто задав один простой параметр,
через каждые 10 секунд. Собственно, это все. Просто задав один параметр,
вы обеспечите аппаратный контроль работоспособности systemd и
ядра\footnote{Небольшой совет: если вы занимаетесь отладкой базовых системных
компонентов~--- не~забудьте отключить сторожевой таймер. Иначе ваша система
@@ -3194,10 +3195,697 @@ URI, ссылающиеся на документацию, формируютс
Стоит упомянуть здесь еще одну опцию из файла +/etc/systemd/system.conf+~---
+ShutdownWatchdogSec=+. Она позволяет настроить аппаратный сторожевой таймер для
контроля процесса перезагрузки. По умолчанию она равна <<10min>>. Если в
контроля процесса перезагрузки. По умолчанию она равна <<+10min+>>. Если в
процессе остановки системы перед перезагрузкой она зависнет, аппаратный таймер
принудительно перезагрузит ее по истечении данного интервала.
Это все, что я хотел сказать об аппаратных таймерах. Двух вышеописанных опций
должно быть вполне достаточно для полноценного использования их возможностей.
А сейчас мы рассмотрим логику программных сторожевых таймеров, обеспечивающих
контроль работоспособности отдельных служб.
Прежде всего отметим, что для полноценной поддержки сторожевого контроля,
программа должна содержать специальный код, периодически отправляющий таймеру
сигналы <<все в порядке>>. Добавить поддержку такой функциональности довольно
просто. Для начала, демон должен проверить переменную окружения +WATCHDOG_USEC=+.
Если она определена, то ее значение задает контрольный интервал в микросекундах,
сформатированный в виде текстовой (ASCII) строки. В этом случае демон должен
регулярно выполнять вызов
\hreftt{http://www.freedesktop.org/software/systemd/man/sd_notify.html}{sd\_notify}+("WATCHDOG=1")+
с периодом, равным половине указанного интервала. Таким образом, поддержка
программного сторожевого контроля со стороны демона сводится к проверке значения
переменной окружения, и выполнении определенных действий в соответствии с этим
значением.
Если интересующая вас служба обеспечивает поддержку такой
функциональности, вы можете включить для нее сторожевой контроль, задав опцию
+WatchdogSec=+ в ее юнит-файле. Эта опция задает период работы таймера
(подробнее см.
\href{http://www.freedesktop.org/software/systemd/man/systemd.service.html}{systemd.service(5)}).
Если вы зададите ее, то systemd при запуске службы передаст ей соответствующее
значение +WATCHDOG_USEC=+ и, если служба перестанет своевременно отправлять
сигналы <<все в порядке>>, присвоит ей статус сбойной (failure state).
Очевидно, что одного только присвоения статуса недостаточно для обеспечения
надежной работы системы. Поэтому нам также пригодятся настройки, определяющие,
нужно ли перезапускать зависшую службу, количество попыток перезапуска, и
дальнейшие действия, если она все равно продолжает сбоить. Чтобы включить
автоматический перезапуск службы при сбое, нужно задать опцию
+Restart=on-failure+ в ее юнит-файле. Чтобы настроить, сколько раз systemd будет
пытаться перезапустить службу, воспользуйтесь настройками +StartLimitBurst=+
+StartLimitInterval=+ (первая из них определяет предельное количество попыток,
вторая~--- интервал времени, в течение которого они подсчитываются). В том
случае, если достигнут предел количества попыток за указанное время, выполняется
действие, заданное параметром +StartLimitAction=+. По умолчанию он установлен в
+none+ (никаких дополнительных действий не~будет, службу просто оставят в покое со
статусом сбойной). В качестве альтернативы можно указать одно из трех
специальных действий: +reboot+, +reboot-force+ и +reboot-immediate+.
+reboot+ соответствует обычной перезагрузке системы, с выполнением всех
сопутствующих процедур (корректное завершение всех служб, отмонтирование
файловых систем и т.д.). +reboot-force+ действует более грубо~--- даже
не~пытаясь корректно остановить службы, оно просто убивает все их процессы,
отмонтирует файловые системы и выполняет принудительную перезагрузку (в
результате, перезагрузка происходит быстрее, чем обычно, но файловые системы
остаются неповрежденными). И наконец, +reboot-immediate+ даже не~пытается отдать
дань вежливости (убить процессы и отмонтировать файловый системы)~--- оно
немедленно выполняет жесткую перезагрузку системы (это поведение практически
аналогично срабатыванию аппаратного сторожевого таймера). Все перечисленный
настройки подробно описаны на странице руководства
\href{http://www.freedesktop.org/software/systemd/man/systemd.service.html}{systemd.service(5)})%
\footnote{Прим. перев.: Автор упускает из виду одну полезную опцию,
непосредственно относящуюся к обсуждаемому вопросу~--- +OnFailure=+, задающую
юнит, который будет активирован в случае сбоя исходного юнита. Таким образом
можно обеспечить, например, запуск скриптов, отправляющих администратору
уведомление о сбое в сочетании с дополнительной информацией (для сбора которой
целесообразно задействовать команды +systemctl status+ и +journalctl+). Кроме
того, комбинирование данной настройки с опцией +OnFailureIsolate=+ позволяет
при сбое юнита перевести систему в определенное состояние (например, остановить
некоторые службы, перейти в режим восстановления, выполнить перезагрузку).}.
Таким образом, мы мы получаем гибкий механизм для настройки сторожевого контроля
служб, их перезапуска при зависании, и реагирования в ситуации, когда перезапуск
не~помогает.
Рассмотрим применение этих настроек на простом примере:
\begin{Verbatim}
[Unit]
Description=My Little Daemon
Documentation=man:mylittled(8)
[Service]
ExecStart=/usr/bin/mylittled
WatchdogSec=30s
Restart=on-failure
StartLimitInterval=5min
StartLimitBurst=4
StartLimitAction=reboot-force
\end{Verbatim}
Данная служба будет автоматически перезапущена, если она не~передаст системному
менеджеру очередной сигнал <<все в порядке>> в течение 30 секунд после
предыдущего (кроме того, перезапуск будет произведен и в случае любого другого
сбоя, например, завершения основного процесса службы с ненулевым кодом выхода).
Если потребуется более 4 перезапусков службы за 5 минут~--- будет предпринято
специальное действие, в данном случае, быстрая перезагрузка системы с корректным
отмонтированием файловых систем.
Это все, что я хотел рассказать о сторожевых таймерах в systemd. Мы надеемся,
что поддержки аппаратного отслеживания работоспособности процесса init, в
сочетании с контролем функционирования отдельных служб, должно быть достаточно
для решения большинства задач, связанных со сторожевыми таймерами.
Разрабатываете ли вы встраиваемую либо мобильную систему, или работаете с
высокодоступными серверами~--- вам определенно стоит попробовать наши решения!
(И да, если у вас возникнет вопрос, почему с аппаратным таймером должен работать
именно init, и что мешает вынести эту логику в отдельный демон~--- пожалуйста,
перечитайте эту главу еще раз, и попытайтесь увидеть всю цепочку сторожевого
контроля как единое целое: аппаратный таймер надзирает за работой systemd, а
тот, в свою очередь, следит за отдельными службами. Кроме того, мы полагаем, что
отсутствие своевременного ответа от службы нужно рассматривать и обрабатывать
так же, как и любые другие ее сбои. И наконец, взаимодействие с
+/dev/watchdog+~--- одна из самых тривиальных задач в работе ОС (обычно, она
сводится к простому вызову +ioctl()+), и для ее решения достаточно нескольких
строк кода. С другой стороны, вынос данной функции в отдельный демон потребует
организации сложного межпроцессного взаимодействия между этим демоном и
процессом init~--- очевидно, реализация такой схемы предоставит значительно
б\'{о}льший простор для ошибок, не~говоря уже о повышенном потреблении
ресурсов.)
Отметим, что встроенная в systemd поддержка аппаратного сторожевого таймера
в~конфигурации по умолчанию отключена, и поэтому никак не~мешает работе с этим
таймером из других программ. Вы без лишних проблем можете выбрать внешний
сторожевой демон, если он лучше подходит для вашей задачи.
Да, и еще: если у вас возникнет вопрос, имеется ли в вашей системе аппаратный
таймер~--- скорее всего да, если ваш компьютер не~очень старый. Чтобы получить
точный ответ, вы можете воспользоваться утилитой
\href{http://karelzak.blogspot.de/2012/05/eject1-sulogin1-wdctl1.html}{wdctl},
включенной в последний релиз util-linux\footnote{Прим. перев.: Утилита wdctl
присутствует в util-linux, начиная с версии~2.22, которая, на~момент написания
этих строк, еще не~вышла.}. Эта программа выведет всю необходимую
информацию о вашем аппаратном сторожевом таймере.
И в завершение, я хотел бы поблагодарить ребят из
\href{http://www.pengutronix.de/}{Pengutronix}, которым приндалежит основная
заслуга реализации сторожевого контроля в systemd.
\section{Запуск getty на последовательных (и не~только) консолях}
\emph{Если вам лень читать всю статью целиком: для запуска getty на
последовательной консоли\footnote{Прим. перев.: Здесь и в дальнейшем автор
использует термин <<serial console>>. Точный перевод этого выражения на русский
язык звучит как <<консоль, подключаемая к последовательному порту>>. Однако,
для краткости изложения, при переводе используется не~вполне корректный, но
хорошо знакомый администраторам жаргонизм <<последовательная консоль>>. Также
отметим, что в данном документе термины <<консоль>> и <<терминал>> используются
как синонимы.} достаточно добавить параметр ядра \verb+console=ttyS0+, и systemd
автоматически запустит getty на этом терминале.}
Физический последовательный порт
\href{https://ru.wikipedia.org/wiki/RS-232}{RS-232}, хотя уже и стал редкостью
на современных настольных компьютерах, тем не~менее, продолжает играть
важную роль на современных серверах и встраиваемых системах. Он предоставляет
простой и надежный доступ к управлению системой, даже когда сеть упала, а
основной интерфейс управления завис. Кроме того, эмуляция последовательной
консоли часто используется при управлении виртуальными машинами.
Разумеется, в Linux уже давно реализована поддержка работы с последовательными
консолями, однако при разработке
\href{http://www.freedesktop.org/wiki/Software/systemd}{systemd} мы постарались
сделать работу с ними еще проще. В этой статье я хочу рассказать о том, как в
systemd реализован запуск \href{https://ru.wikipedia.org/wiki/Getty}{getty} на
терминалах различных типов.
Для начала, хотелось бы отметить следующий момент: в большинстве случаев, чтобы
получить приглашение к логину на последовательном терминале, вам не~нужно
совершать никаких дополнительных действий: systemd сам проверит настройки ядра,
определит их них используемую ядром консоль, и автоматически запустит на ней
getty. Таким образом, вам достаточно лишь правильно указать ядру соответствующую
консоль (например, добавив к параметрам ядра в загрузчик +console=ttyS0+).
Тем не~менее, для общего образования мы все же рассмотрим некоторые тонкости
запуска getty в systemd. Эта задача решается двумя шаблонами
юнитов\footnote{Прим. перев.: Принципы работы с шаблонами и экземплярами служб
изложены в главе~\ref{sec:instances}. Для лучшего понимания нижеприведенного
материала, рекомендуется перечитать эту главу, если вы ее подзабыли.}:
\begin{itemize}
\item +getty@.service+ отвечает за
\href{https://ru.wikipedia.org/wiki/%D0%92%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D0%BD%D1%81%D0%BE%D0%BB%D1%8C}%
{виртуальные консоли} (+/dev/tty1+ и т.д.)~--- их можно увидеть
безо всякого дополнительного оборудования, просто переключившись
на них из графического сеанса.
\item +serial-getty@.service+ обеспечивает поддержку всех прочих
разновидностей терминалов, в том числе, подключаемых к
последовательным портам (+/dev/ttyS0+ и т.д.). Этот шаблон имеет
ряд отличий от +getty@.service+, в частности, переменная \verb+$TERM+
в нем устанавливается в значение +vt102+ (должно хорошо работать
на большинстве физических терминалов), а не~+linux+ (которое
работаеть правильно только на виртуальных консолях), а также
пропущены настройки, касающиеся очистки буфера прокрутки (и
поэтому имеющие смысл только на VT).
\end{itemize}
\subsection{Виртуальные консоли}
Рассмотрим механизм запуска +getty@.service+, обеспечивающий появление
приглашений логина на виртуальных консолях (последовательны терминалы пока
оставим в покое). По устоявшейся традиции, init-системы Linux обычно
настраивались на запуск фиксированного числа экземпляров getty, как правило,
шести (на первых шести виртуальных консолях, с +tty1+ по +tty6+).
В systemd мы сделали этот процесс более динамичным: чтобы добиться большей
скорости и эффективности, мы запускаем дополнительные экземпляры getty только
при необходимости. Например, +getty@tty2.service+ стартует только после того,
как вы переключитесь на вторую виртуальную консоль. Отказавшись от
обязательного запуска нескольких экземпляров getty, мы сэкономили немного
системных ресурсов, а также сделали загрузку системы чуть-чуть быстрее. При
этом, с точки зрения пользователя, все очень просто: как только он переключается
на виртуальную консоль, на ней запускается getty, которая выводит приглашение к
логину. Пользователь может и не~подозревать о том, что до момента переключения
ничего этого не~было. Тем не~менее, если он войдет в систему и выполнит команду
+ps+, он увидит, что getty запущены только на тех консолях, на которых он уже
побывал.
По умолчанию, автоматический запуск getty производится на виртуальных консолях с
первой по шестую (чтобы свести к минимуму отличия от привычной
конфигурации)\footnote{Тем не~менее, это поведение можно легко изменить,
задавая параметр +NAutoVTs=+ в файле
\href{http://www.freedesktop.org/software/systemd/man/logind.conf.html}{logind.conf}.}
Отметим, что автоматический запуск getty на конкретной консоли производится
только при условии, что эта консоль не~занята другой программой. В частности,
при интенсивном использовании механизма
\href{https://en.wikipedia.org/wiki/Fast_user_switching}{быстрого переключения
пользователей} графические сеансы могут занять первые несколько консолей (чтобы
такое поведение не~заблокировало возможность запуска getty, мы предусмотрели
специальную защиту, см. чуть ниже).
Две консоли играют особую роль: +tty1+ и +tty6+. +tty1+, при загрузке в
графическом режиме, используется для запуска дисплейного менеджера, а при
загрузке в многопользовательском текстовом режиме, systemd принудительно
запускает на ней экземпляр getty, не~дожидаясь переключений\footnote{В данном
случае нет принципиальной разницы между принудительным запуском и запуском по
запросу: первая консоль используется по умолчанию, так что запрос на ее
активацию обязательно поступит.}.
Что касается +tty6+, то она используется исключительно для автоматического
запуска getty, и недоступна другим подсистемам, в частности, графическому
серверу\footnote{При необходимости, вы можете легко поменять резервируемую
консоль, используя параметр +ReserveVT=+ в файле
\href{http://www.freedesktop.org/software/systemd/man/logind.conf.html}{logind.conf}.}
Мы сделали так специально, чтобы гарантировать возможность входа в систему в
текстовом режиме, даже если графический сервер займет более пяти консолей.
\subsection{Последовательные консоли}
Работа с последовательными консолями (и всеми остальными видами не-виртуальных
консолей) реализована несколько иначе, чем с VT. По умолчанию, systemd запускает
один экземпляр +serial-getty@.service+ на основной консоли ядра\footnote{Если
для ядра настроен вывод в несколько консолей, \emph{основной} считается та, которая
идет \emph{первой} в +/sys/class/tty/console/active+, т.е. указана
\emph{последней} в строке параметров ядра.} (если она не~является виртуальной).
Консолью ядра~--- это та консоль, на которую выводятся сообщения ядра. Обычно
она настраивается в загрузчике, путем добавления к параметрам ядра аргумента
наподобие +console=ttyS0+\footnote{Подробнее об этой опции см. в файле
\href{https://www.kernel.org/doc/Documentation/kernel-parameters.txt}{kernel-parameters.txt}.}
Таким образом, если пользователь перенаправил вывод ядра на последовательную
консоль, то по завершении загрузки он увидит на этой консоли приглашение для
логина\footnote{Отметим, что getty, а точнее, +agetty+ на такой консоли
вызывается с параметром +-s+, и поэтому не~изменяет настроек символьной
скорость (baud rate)~--- сохраняется то значение, которое было указано в строке
параметров ядра.}. Кроме того, systemd выполняет поиск консолей, предоставляемых
системами виртуализации, и запускает +serial-getty@.service+ на первой из этих
консолей (+/dev/hvc0+, +/dev/xvc0+ или +/dev/hvsi0+). Такое поведение
реализовано специальной
\href{http://www.freedesktop.org/wiki/Software/systemd/Generators}{программой-генератором}~---
\href{http://www.freedesktop.org/software/systemd/man/systemd-getty-generator.html}{systemd-getty-generator}.
Генераторы запускаются в самом начале загрузки и автоматически настраивают
различные службы в зависимости от различных факторов.
В большинстве случаев, вышеописанного механизма автоматической настройки должно
быть достаточно, чтобы получить приглашение логина там, где нужно~--- без
каких-либо дополнительных настроек systemd. Тем не~менее, иногда возникает
необходимость в ручной настройке~--- например, когда необходимо запустить getty
сразу на нескольких последовательных консолях, или когда вывод сообщений ядра
направляется на один терминал, а управление производится с другого. Для решения
таких задач достаточно определить по экземпляру +serial-getty@.service+ для
каждого последовательного порта, на котором вы хотите запустить
getty\footnote{Отметим, что +systemctl enable+ \emph{для экземпляров служб}
работает только начиная с systemd версии 188 и старше (например, в Fedora 18). В
более ранних версиях придется напрямую манипулировать символьными ссылками:
\texttt{ln -s /usr/lib/systemd/system/serial-getty@.service
/etc/systemd/system/getty.target.wants/serial-getty@ttyS2.service ; systemctl
daemon-reload}.}:
\begin{Verbatim}
# systemctl enable serial-getty@ttyS2.service
# systemctl start serial-getty@ttyS2.service
\end{Verbatim}
После выполнения этих команд, getty будет принудительно запускаться для
указанных последовательных портов при всех последующих загрузках.
В некоторых ситуациях может возникнуть необходимость в тонкой настройке
параметров getty (например, настроенная для ядра символьная скорость непригодна
для интерактивного сеанса). Тогда просто скопируйте штатный шаблон юнита в
каталог +/etc/systemd/system+ и отредактируйте полученную копию:
\begin{Verbatim}
# cp /usr/lib/systemd/system/serial-getty@.service /etc/systemd/system/serial-getty@ttyS2.service
# vi /etc/systemd/system/serial-getty@ttyS2.service
... редактируем параметры запуска agetty ...
# ln -s /etc/systemd/system/serial-getty@ttyS2.service /etc/systemd/system/getty.target.wants/
# systemctl daemon-reload
# systemctl start serial-getty@ttyS2.service
\end{Verbatim}
В приведенном примере создает файл настроек, определяющий запуск getty на порту
+ttyS2+ (это определяется именем, под которым мы скопировали файл~---
+serial-getty@ttyS2.service+). Все изменения настроек, сделанные в этом файле,
будут распространяться только на этот порт.
Собственно, это все, что я хотел рассказать о последовательных портах,
виртуальных консолях и запуске getty на них. Надеюсь, рассказ получился
интересным.
\section{Работа с Journal}
В свое время, я уже рассказывал о некоторых возможностях journal
(см.~главу~\ref{sec:journal}), доступных из утилиты +systemctl+. Сейчас я
попробую рассказать о journal более подробно, с упором на практическое
применение его возможностей.
Если вы еще не~в курсе, что такое journal: это компонент
\href{http://www.freedesktop.org/wiki/Software/systemd}{systemd}, регистрирующий
сообщения из системного журнала (syslog), сообщения ядра (kernel log) и initrd,
а также сообщения, которые процессы служб выводят на STDOUT и STDERR. Полученная
информация индексируется и предоставляется пользователю по запросу. Journal
может работать одновременно с традиционными демоном syslog (например, rsyslog
или syslog-ng), либо полностью его заменять. Более подробно см. в
\href{http://0pointer.de/blog/projects/the-journal.html}{первом анонсе}.
Journal был включен в Fedora начиная с F17. В Fedora~18 journal вырос в мощный и
удобный механизм работы с системным журналом. Однако, и в~F17, и в~F18 journal
по умолчанию сохраняет информацию только в небольшой кольцевой буфер в каталоге
+/run/log/journal+. Как и все содержимое каталога +/run+, эта информация
теряется при перезагрузке. Такой подход сильно ограничивает использование
полезных возможностей journal, однако вполне достаточен для вывода актуальных
сообщений от служб в +systemctl status+. Начиная с Fedora~19, мы собираемся
включить сохранение логов на диск, в каталог +/var/log/journal+. При этом,
логи смогут занимать гораздо больше места\footnote{Прим. перев.: В journal
отдельно задаются ограничения на размер для логов во временном хранилище
(+/run+) и в постоянном (+/var+). При превышении лимита старые журналы
удаляются. Так как +/run+ размещается на tmpfs, т.е. в
оперативной памяти, для временного хранения по умолчанию установлены более
жесткие ограничения. При необходимости, соответствующие настройки можно задать
в файле
\href{http://www.freedesktop.org/software/systemd/man/journald.conf.html}{journald.conf}.},
а значит, смогут вместить больше полезной информации. Таким образом, journal
станет еще более удобным.
\subsection{Сохранение логов на диск}
В F17 и~F18 вы можете включить сохранение логов на диск вручную:
\begin{Verbatim}
# mkdir -p /var/log/journal
\end{Verbatim}
После этого рекомендуется перезагрузить систему, чтобы заполнить журнал овыми
записями.
Так как теперь у вас есть journal, syslog вам больше не~нужен (кроме ситуаций,
когда вам совершенно необходимо иметь +/var/log/messages+ в текстовом виде), и
вы спокойно можете удалить его:
\begin{Verbatim}
# yum remove rsyslog
\end{Verbatim}
\subsection{Основы}
Итак, приступим. Нижеприведенный текст демонстрирует возможности systemd~195,
входящего в Fedora~18\footnote{Обновление со 195-й версией systemd в настоящее
время находится
\href{https://admin.fedoraproject.org/updates/FEDORA-2012-16709/systemd-195-1.fc18}{на
тестировании} и вскоре будет включено в состав Fedora~18.}, так что, если
некоторые из описанных трюков не~сработают в F17~--- пожалуйста, дождитесь F18.
Начнем с основ. Доступ к логам journal осуществляется через утилиту
\href{http://www.freedesktop.org/software/systemd/man/journalctl.html}{journalctl(1)}.
Чтобы просто взглянуть на лог, достаточно ввести
\begin{Verbatim}
# journalctl
\end{Verbatim}
Если вы выполнили эту команду с полномочиями root, вы увидите все
журнальные сообщения, включая исходящие как от системных компонентов, так и от
залогиненных пользователей. Вывод этой команды форматируется в стиле
+/var/log/messages+, однако в нем добавлены кое-какие улучшения:
\begin{itemize}
\item Строки с приоритетом error и выше подсвечены красным.
\item Строки с приоритетом notice и warning выделены жирным шрифтом.
\item Все отметки времени сформированы с учетом вашего часового пояса.
\item Для навигации по тексту используется просмотрщик (pager), по
умолчанию +less+.
\item Выводятся \emph{все} доступные данные, включая информацию из
файлов, прошедших ротацию (rotated logs).
\item Загрузка системы отмечается специальной строкой, отделяющей
записи, сгенерированные между (пере)загрузками.
\end{itemize}
Отметим, что в данной статье не~приводятся примеры такого вывода~--- прежде
всего, для краткости изложения, но также и для того, чтобы дать вам повод
поскорее попробовать Fedora~18 с systemd~195. Надеюсь, вы поймете суть и так.
\subsection{Контроль доступа}
Итак, мы получили удобный и эффективный метод просмотра логов. Но для полного
доступа к системным сообщениям требуются привилегии root, что не~всегда
удобно~--- в наше время администраторы предпочитают работать от имени
непривилегированного пользователя, переключаясь на root только при крайней
необходимости. По умолчанию, непривилегированные пользователи могут
просматривать в journal только свои собственные логи (сообщения, сгенерированные
их процессами). Чтобы предоставить пользователю доступ ко всем системным логам,
нужно включить его в группу +adm+:
\begin{Verbatim}
# usermod -a -G adm lennart
\end{Verbatim}
Разлогинившись, а затем вновь залогинившись под именем +lennart+\footnote{Прим.
перев.: Для того, чтобы обновить групповые полномочия в уже запущенных сеансах,
можно воспользоваться командой
\href{http://linux.die.net/man/1/newgrp}{newgrp(1)}: +newgrp adm+.}, я могу
просматривать сообщения от всех пользователей и системных
компонентов\footnote{Прим. перев.: Группа +adm+ была выбрана на основании опыта
дистрибутива Debian, в котором она устанавливается в качестве группы-владельца
большинства лог-файлов. При этом авторы четко разделяют полномочия групп +adm+ и
+wheel+: если последняя используется для предоставления прав \emph{изменять}
что-либо в системе, то первая дает возможность лишь \emph{просматривать}
системную информацию.}:
\begin{Verbatim}
$ journalctl
\end{Verbatim}
\subsection{Отслеживание логов в реальном времени}
Когда вы запускаете программу +journalctl+ без параметров, она выводит все
сообщения, сгенерированные на текущий момент. Однако, иногда бывает полезно
отслеживать их появление в режиме реального времени. В классической реализации
syslog это осуществлялось командой +tail -f /var/log/messages+. В journal ее
аналог выглядит так:
\begin{Verbatim}
$ journalctl -f
\end{Verbatim}
И работает он точно так же: выводит последние десять сообщений, после чего
переходит в режим ожидания, и выводит новые сообщения по мере их появления.
\subsection{Простейшие методы выборки записей}
При вызове +journalctl+ без параметров, она выводит все сообщения, начиная с
самого первого из сохраненных. Разумеется, это огромный объем информации. На
практике иногда бывает достаточно ограничиться сообщениями, сгенерированными с
момента последней загрузки системы:
\begin{Verbatim}
$ journalctl -b
\end{Verbatim}
Но часто даже после такой фильтрации записей остается довольно много. Что ж, мы
можем ограничиться только наиболее важными. Итак, все сообщения с приоритетом
error и выше, начиная с момента последней загрузки:
\begin{Verbatim}
$ journalctl -b -p err
\end{Verbatim}
Если вы уже успели перезагрузить систему после того, как произошли интересующие
вас события, целесообразнее будет воспользоваться выборкой по времени:
\begin{Verbatim}
$ journalctl --since=yesterday
\end{Verbatim}
В результате мы увидим все сообщения, зарегистрированные начиная со вчерашнего
дня вплоть до настоящего момента. Прекрасно! Разумеется, этот критерий отбора можно
комбинировать с другими, например, с +-p err+. Но, допустим, нам нужно узнать о
чем-то, что случилось либо 15-го октября, либо 16-го:
\begin{Verbatim}
$ journalctl --since=2012-10-15 --until="2011-10-16 23:59:59"
\end{Verbatim}
Отлично, мы нашли то, что искали. Но вот вам сообщают, что сегодня ранним утром
наблюдались проблемы с CGI-скриптами Apache. Ладно, послушаем, что нам скажет
индеец:
\begin{Verbatim}
$ journalctl -u httpd --since=00:00 --until=9:30
\end{Verbatim}
Да, мы нашли это. Хм, похоже, что причиной стала проблема с диском +/dev/sdc+.
Посмотрим, что с ним случилось:
\begin{Verbatim}
$ journalctl /dev/sdc
\end{Verbatim}
Кошмар, ошибка ввода-вывода!\footnote{Ну ладно, признаюсь, здесь я немножко
считерил. Индексирование сообщений ядра по блочным устройствам пока что
не~принято в апстрим, но Ганс
\href{http://www.spinics.net/lists/linux-scsi/msg62499.html}{проделал огромную
работу}, чтобы реализовать эту функциональность, и я надеюсь, что к релизу F18
все будет.} Нужно срочно заменить диск, пока не~начались более серьезные
проблемы. Ладно, пошли дальше. Что у нас там случилось с процессом vpnc?
\begin{Verbatim}
$ journalctl /usr/sbin/vpnc
\end{Verbatim}
Хм, ничего подозрительного. Но, кажется, проблема где-то во взаимодействии между
+vpnc+ и +dhclient+. Посмотрим объединенный и отсортированный по времени списов
сообщений от этих процессов:
\begin{Verbatim}
$ journalctl /usr/sbin/vpnc /usr/sbin/dhclient
\end{Verbatim}
Отлично, мы нашли причину проблемы!
\subsection{Продвинутые методы выборки}
Да, это все, конечно, здорово, но попробуем подняться еще на ступеньку выше.
Чтобы понять описанные ниже приемы, нужно знать, что systemd добавляет к
каждой лог-записи ряд скрытых метаданных. Эти метаданные по структуре напоминают
набор переменных окружения, хотя на самом деле дают даже больше возможностей:
во-первых, метаданные могут включать большие бинарные блоки данных (впрочем, это
скорее исключение~--- обычно они содержат текст в кодировке UTF-8), и во-вторых,
в пределах одной записи поле метаданных может содержать сразу несколько
значений (и это тоже встречается нечасто~--- обычно поля содержат по одному
значению). Эти метаданные автоматически собираются и добавляются для каждой
лог-записи, безо всякого участия пользователя. И вы легко можете их использовать
для более тонкой выборки записей. Посмотрим, как они выглядят:
\begin{Verbatim}
$ journalctl -o verbose -n1
Tue, 2012-10-23 23:51:38 CEST [s=ac9e9c423355411d87bf0ba1a9b424e8;i=4301;b=5335e9cf5d954633bb99aefc0ec38c25;m=882ee28d2;t=4ccc0f98326e6;x=f21e8b1b0994d7ee]
PRIORITY=6
SYSLOG_FACILITY=3
_MACHINE_ID=a91663387a90b89f185d4e860000001a
_HOSTNAME=epsilon
_TRANSPORT=syslog
SYSLOG_IDENTIFIER=avahi-daemon
_COMM=avahi-daemon
_EXE=/usr/sbin/avahi-daemon
_SYSTEMD_CGROUP=/system/avahi-daemon.service
_SYSTEMD_UNIT=avahi-daemon.service
_SELINUX_CONTEXT=system_u:system_r:avahi_t:s0
_UID=70
_GID=70
_CMDLINE=avahi-daemon: registering [epsilon.local]
MESSAGE=Joining mDNS multicast group on interface wlan0.IPv4 with address 172.31.0.53.
_BOOT_ID=5335e9cf5d954633bb99aefc0ec38c25
_PID=27937
SYSLOG_PID=27937
_SOURCE_REALTIME_TIMESTAMP=1351029098747042
\end{Verbatim}
(Чтобы не~утомлять вас огромным количеством текста, ограничимся одной записью.
Ключ +-n+ позволяет задать число выводимых записей, в нашем случае 1. Если
указать его без параметра, будут показаны 10 последних записей.)
Задав параметр +-o verbose+, мы переключили формат вывода~--- теперь, вместо
скупых строчек, копирующих +/var/log/messages+, для каждой записи выводится
полный перечень всех метаданных. В том числе, информация о пользователе и
группе, контекст SELinux, идентификатор компьютера и т.д. Полный список
общеизвестных полей метаданных приведен на соответствующей
\href{http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html}%
{странице руководства}.
И база данных Journal индексируется по \emph{всем} этим полям! И мы можем
использовать любое из них в качестве критерия выборки:
\begin{Verbatim}
$ journalctl _UID=70
\end{Verbatim}
Как нетрудно догадаться, в результате будут выведены все сообщения от
процессов пользователя с UID 70. При необходимости, критерии можно
комбинировать:
\begin{Verbatim}
$ journalctl _UID=70 _UID=71
\end{Verbatim}
Указание двух значений для одного и того же поля эквивалентно логическому ИЛИ.
Таким образом, будут выведены записи как от процессов с UID 70, так и от
процессов с UID 71.
\begin{Verbatim}
$ journalctl _HOSTNAME=epsilon _COMM=avahi-daemon
\end{Verbatim}
А указание двух \emph{различных} полей дает эффект логического И. В результате,
будут выведены записи только от процесса +avahi-daemon+, работающего на хосте с
именем +epsilon+.
Но мы этим не~ограничимся! Мы же суровые компьютерщики, мы хотим использовать
сложные логические выражения!
\begin{Verbatim}
$ journalctl _HOSTNAME=theta _UID=70 + _HOSTNAME=epsilon _COMM=avahi-daemon
\end{Verbatim}
При помощи плюса мы можем явно задать логическое ИЛИ, применяя его к разным
полям и даже И-выражениям. Поэтому наш пример выведет как записи с хоста
+theta+ от процессов с UID 70, так и с хоста +epsilon+ от процесса
+avahi-daemon+\footnote{Прим. перев.: Стоит отметить, что приоритет логических
операций стандартный: сначала выполняются операции И, и только потом~---
операции ИЛИ. Используемая в +journalctl+ система записи выражений аналогична
принятой в классической алгебре: умножение (имеющее более высокий приоритет)
не~указывается знаком операции, а обозначается просто последовательной
записью величин.}.
\subsection{И немного магии}
Уже неплохо, правда? Но есть один недостаток~--- мы же не~сможем запомнить все
возможные значения все полей журнала! Для этого была бы нужна очень хорошая
память. Но +journalctl+ вновь приходит к нам на помощь:
\begin{Verbatim}
$ journalctl -F _SYSTEMD_UNIT
\end{Verbatim}
Эта команда выведет все значения поля +_SYSTEMD_UNIT+, зарегистрированные в базе
данных журнала на текущий момент. То есть, имена всех юнитов +systemd+, которые
писали что-либо в журнал. Аналогичный запрос работает для всех полей, так что
найти точное значение для выборки по нему~--- уже не~проблема. Но тут самое
время сообщить вам, что эта функциональность встроена в механизм автодополнения
оболочки\footnote{Прим. перев.: В исходной статье речь идет только о bash,
однако, начиная с релиза systemd 196, аналогичная функциональность доступна и
для zsh.}! Это же просто прекрасно~--- вы можете просмотреть перечень значений
поля и выбрать из него нужно прямо при вводе выражения. Возьмем для примера
метки SELinux. Помнится, имя поле начиналось с букв SE\ldots{}
\begin{Verbatim}[commandchars=\\\{\}]
$ journalctl _SE\textbf{<TAB>}
\end{Verbatim}
и оболочка сразу же дополнит:
\begin{Verbatim}
$ journalctl _SELINUX_CONTEXT=
\end{Verbatim}
Отлично, и какое там значение нам нужно?
\begin{Verbatim}[fontsize=\small]
$ journalctl _SELINUX_CONTEXT=<TAB><TAB>
kernel system_u:system_r:rtkit_daemon_t:s0
system_u:system_r:accountsd_t:s0 system_u:system_r:syslogd_t:s0
system_u:system_r:avahi_t:s0 system_u:system_r:system_cronjob_t:s0-s0:c0.c1023
system_u:system_r:bluetooth_t:s0 system_u:system_r:system_dbusd_t:s0-s0:c0.c1023
system_u:system_r:chkpwd_t:s0-s0:c0.c1023 system_u:system_r:systemd_logind_t:s0
system_u:system_r:chronyd_t:s0 system_u:system_r:systemd_tmpfiles_t:s0
system_u:system_r:crond_t:s0-s0:c0.c1023 system_u:system_r:udev_t:s0-s0:c0.c1023
system_u:system_r:devicekit_disk_t:s0 system_u:system_r:virtd_t:s0-s0:c0.c1023 c0.c1023
system_u:system_r:dhcpc_t:s0 system_u:system_r:vpnc_t:s0 sd_t:s0-s0:c0.c1023
system_u:system_r:dnsmasq_t:s0-s0:c0.c1023 system_u:system_r:xdm_t:s0-s0:c0.c1023
system_u:system_r:init_t:s0 unconfined_u:system_r:rpm_t:s0-s0:c0.c1023
system_u:system_r:local_login_t:s0-s0:c0.c1023 unconfined_u:system_r:unconfined_t:s0-s0:c0.c1023
system_u:system_r:lvm_t:s0 unconfined_u:system_r:useradd_t:s0-s0:c0.c1023
system_u:system_r:modemmanager_t:s0-s0:c0.c1023 unconfined_u:unconfined_r:unconfined_dbusd_t:s0-s0:c0.c1023
system_u:system_r:NetworkManager_t:s0 unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
system_u:system_r:policykit_t:s0
\end{Verbatim}
Ага, нас интересуют записи с меткой PolicyKit! Пользуясь дополнением, вводим:
\begin{Verbatim}
$ journalctl _SELINUX_CONTEXT=system_u:system_r:policykit_t:s0
\end{Verbatim}
Очень просто, не~правда ли! Пожалуй, самое простое из действий, связанных с
SELinux ;-) Разумеется, такое дополнение работает для всех полей Journal.
На сегодня все. Впрочем, на странице руководства
\href{http://www.freedesktop.org/software/systemd/man/journalctl.html}%
{journalctl(1)} можно узнать и о многих других возможностях, не~описанных здесь.
Например, о том, что +journalctl+ может выводить данные в формате JSON, или в
формате +/var/log/messages+, но с относительными метками времени, как в dmesg.
\section{Управление ресурсами}
Важную роль в современных компьютерных системах играют механизмы управления
использованием ресурсов: когда вы запускаете на одной системе несколько
программ, возникает необходимость распределять между ними ресурсы системы,
в соответствии с некоторыми правилами. В частности, это особенно актуально на
маломощных встраиваемых и мобильных системах, обладающих очень скудными
ресурсами. Но та же задача актуальна и для очень мощных вычислительных
кластеров, которые располагают огромными ресурсами, но при это несут и огромную
вычислительную нагрузку.
Исторически, в Linux поддерживался только одна схема управления ресурсами: все
процессы получают примерно равные доли процессорного времени или потока
ввода-вывода. При необходимости соотношение этих долей можно изменить при
помощи значения \emph{nice}, задаваемого для каждого процесса. Такой подход
очень прост, и на протяжении долгих лет покрывал все нужды пользователей Linux.
Но у него есть существенный недостаток: он оперирует лишь отдельными процессами,
но не~их группами. В результате, например, веб-сервер Apache с множеством
CGI-процессов при прочих равных получает гораздо больше ресурсов, чем служба
syslog, у которой не~так много процессов.
В процессе проектирования архитектуры systemd, мы практически сразу поняли, что
управление ресурсов должно быть одной из его базовых функций, заложенных в
основы его структуры. В современной системе~--- неважно, серверной или
встраиваемой~--- контроль использования процессора, памяти и ввода-вывода для
различных служб нельзя добавлять задним числом. Такая функциональность должна
быть доступна изначально, через базовые настройки запуска служб. При этом,
ресурсы должны распределяться на уровне служб, а не~процессов, как это делалось
при помощи значений nice или \href{http://linux.die.net/man/2/setrlimit}{POSIX
Resource Limits}.
В этой статье я попробую рассказать о методах управления механизмами
распределения ресурсов между службами systemd. Эта функциональность присутствует
в systemd уже долгое время, и давно пора рассказать о ней пользователям и
администраторам.
В свое время я
\href{http://0pointer.de/blog/projects/cgroups-vs-cgroups.html}{пояснял}, что
контрольные группы Linux (cgroups) могут работать и как механизм группировки и
отслеживания процессов, и как инструмент управления использованием ресурсов. Для
функционирования systemd необходим только первый из этих режимов, а второй
опционален. И именно этот опциональный второй режим дает вам возможность
распределять ресурсы между службами. (А сейчас очень рекомендую вам, прежде чем
продолжать чтение этой статьи, ознакомиться с
\href{https://en.wikipedia.org/wiki/Cgroups}{базовой информацией о cgroups}.
Хотя дальнейшие рассуждения и не~будут затрагивать низкоуровневые аспекты, все
же будет лучше, если у вас сформируется некоторое представление о них.)
Основными контроллерами cgroups, отвечающими за управление ресурсами, являются
\href{http://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt}{cpu},
\href{http://www.kernel.org/doc/Documentation/cgroups/memory.txt}{memory} и
\href{http://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt}{blkio}.
Для их использования необходимо, чтобы они были включены на этапе сборки ядра;
большинство дистрибутивов (в том числе и Fedora), включают их в штатных ядрах.
systemd предоставляет ряд высокоуровневых настроек, позволяющих использовать эти
контроллеры, не~вникая в технические детали их работы.
\end{document}
vim:ft=tex:tw=80:spell:spelllang=ru