Compare commits

...

3 Commits
v14.3 ... v15.1

Author SHA1 Message Date
nnz1024
df098ff4c1 Version v15.1 (2013-04-29 00:07) [AUTO] 2017-08-17 23:05:40 +03:00
nnz1024
5ffca4f1be Version v15.0 (2013-04-01 00:24) [AUTO] 2017-08-17 23:05:40 +03:00
nnz1024
751d5d1bae Version v14.4 (2013-03-08 22:32) [AUTO] 2017-08-17 23:05:40 +03:00

748
s4a.tex
View File

@@ -20,6 +20,8 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
\newcommand{\hreftt}[2]{\href{#1}{\texttt{#2}}}
\newenvironment{caveat}[1][]{\smallskip\par\textbf{Предупреждение#1: }}%
{\smallskip\par}
\newcommand{\sfnote}[1]{\texorpdfstring{\protect\footnote%
{Прим. перев.: #1}}{}}
% Настройка макета страницы
\setlength{\hoffset}{-1.5cm}
\addtolength{\textwidth}{2cm}
@@ -48,7 +50,8 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
\href{http://creativecommons.org/licenses/by-sa/3.0/legalcode}{CC-BY-SA 3.0
Unported}}
\maketitle
\tableofcontents%\newpage
\tableofcontents
\newpage
\sectiona{Предисловие автора}
Многие из вас, наверное, уже знают, что
\href{http://www.freedesktop.org/wiki/Software/systemd}{systemd}~--- это новая
@@ -67,7 +70,7 @@ Unported}}
Большинство этих возможностей можно описать легко и просто, и подобные статьи
должны быть интересны довольно широкой аудитории. Однако, время от времени мы
будем рассматривать ключевые новшества systemd, что может потребовать несколько
более подробного изложения.
более подробного изложения.
\begin{flushright}
Lennart Poettering, 23 августа 2010~г.
\end{flushright}
@@ -419,7 +422,12 @@ alias psc='ps xawf -eo pid,user,cgroup,args'
Альтернативный способ получить ту же информацию~--- воспользоваться утилитой
+systemd-cgls+, входящей в комплект поставки systemd. Она отображает иерархию
контрольных групп в виде псевдографической диаграммы-дерева:
контрольных групп в виде псевдографической диаграммы-дерева\footnote{Прим.
перев.: Стоит заметить, что в нижеприведенном листинге используется
ASCII-псевдографика. Между тем, уже довольно давно отображение иерархии
процессов в +systemd-cgls+ и +systemctl status+ производится в более
выразительной ├юникодной └псевдографике. ASCII-вариант выводится только в том
случае, если консоль не~поддерживает Unicode.}:
\begin{landscape}
\begin{Verbatim}[fontsize=\small]
@@ -966,6 +974,7 @@ Apache, crond, atd, которые по роду служебной деятел
не~отдельному процессу.
\section{Три уровня выключения}
\label{sec:off}
В \href{http://www.freedesktop.org/wiki/Software/systemd}{systemd} существует
три уровня (разновидности) действий, направленных на прекращение работы службы
@@ -2127,7 +2136,7 @@ systemd?
позволяющей прочитать из файла набор переменных окружения, который будет
установлен при запуске службы. Если же для задания настроек вам необходим
полноценный язык программирования~--- ничто не~мешает им воспользоваться.
Например, вы можете создайть в +/usr/lib/<your package>/+ простой скрипт,
Например, вы можете создать в +/usr/lib/<your package>/+ простой скрипт,
который включает соответствующие файлы, а затем запускает бинарник демона через
+exec+. После чего достаточно просто указать этот скрипт в опции +ExecStart=+
вместо бинарника демона.
@@ -3132,7 +3141,7 @@ URI, ссылающиеся на документацию, формируютс
Да, кстати: если вас интересует общий обзор процесса загрузки systemd, то вам
стоит обратить внимание на
\href{http://www.freedesktop.org/software/systemd/man/bootup.html}{новую
страницу руководства}, где представлена псевгдорафическая потоковая диаграмма,
страницу руководства}, где представлена псевдографическая потоковая диаграмма,
описывающая процесс загрузки и роль ключевых юнитов.
\section{Сторожевые таймеры}
@@ -3456,7 +3465,7 @@ getty. Таким образом, вам достаточно лишь прав
консоль, то по завершении загрузки он увидит на этой консоли приглашение для
логина\footnote{Отметим, что getty, а точнее, +agetty+ на такой консоли
вызывается с параметром +-s+, и поэтому не~изменяет настроек символьной
скорость (baud rate)~--- сохраняется то значение, которое было указано в строке
скорости (baud rate)~--- сохраняется то значение, которое было указано в строке
параметров ядра.}. Кроме того, systemd выполняет поиск консолей, предоставляемых
системами виртуализации, и запускает +serial-getty@.service+ на первой из этих
консолей (+/dev/hvc0+, +/dev/xvc0+ или +/dev/hvsi0+). Такое поведение
@@ -3479,7 +3488,15 @@ getty\footnote{Отметим, что +systemctl enable+ \emph{для экзем
более ранних версиях придется напрямую манипулировать символьными ссылками:
\texttt{ln -s /usr/lib/systemd/system/serial-getty@.service
/etc/systemd/system/getty.target.wants/serial-getty@ttyS2.service ; systemctl
daemon-reload}.}:
daemon-reload}.}\footnote{Прим. перев.: На самом деле, работать с символьными
ссылками придется даже в современных версиях systemd (на момент написания этих
строк, последней является версия 202), так как разработчики забыли включить в
файл +serial-getty@.service+ секцию +[Install]+, в результате чего попытка
выполнения +systemctl enable+ для экземпляра соответствующей службы ведет к
закономерной ошибке. Впрочем, исправить это несложно: достаточно скопировать
данный файл в +/etc/systemd/system/+, после чего дописать в него секцию
+[Install]+ с параметром +WantedBy=getty.target+, а затем выполнить
+systemctl daemon-reload+.}:
\begin{Verbatim}
# systemctl enable serial-getty@ttyS2.service
# systemctl start serial-getty@ttyS2.service
@@ -3628,7 +3645,10 @@ Journal был включен в Fedora начиная с F17. В Fedora~18 jour
большинства лог-файлов. При этом авторы четко разделяют полномочия групп +adm+ и
+wheel+: если последняя используется для предоставления прав \emph{изменять}
что-либо в системе, то первая дает возможность лишь \emph{просматривать}
системную информацию.}:
системную информацию. Начиная с версии systemd 198, группа-владелец файлов
журнала изменена с +adm+ на +systemd-journal+, однако штатный алгоритм установки
systemd все равно выдает права на их чтение группам +adm+ и +wheel+ (через
ACL).}:
\begin{Verbatim}
$ journalctl
\end{Verbatim}
@@ -3804,7 +3824,7 @@ $ journalctl -F _SYSTEMD_UNIT
однако, начиная с релиза systemd 196, аналогичная функциональность доступна и
для zsh.}! Это же просто прекрасно~--- вы можете просмотреть перечень значений
поля и выбрать из него нужно прямо при вводе выражения. Возьмем для примера
метки SELinux. Помнится, имя поле начиналось с букв SE\ldots{}
метки SELinux. Помнится, имя поля начиналось с букв SE\ldots{}
\begin{Verbatim}[commandchars=\\\{\}]
$ journalctl _SE\textbf{<TAB>}
\end{Verbatim}
@@ -3956,18 +3976,32 @@ CPUShares=1500
\end{Verbatim}
Первая строка обеспечивает включение в нашу конфигурацию файла с настройками по
умолчанию, сделанными разработчиками Apache или его сопровождающими в вашем
дистрибутиве (если это включение не~указать явно, данный файл будет проигнорирован).
Далее, мы указываем тот параметр, который хотим изменить. Сохраняем файл,
приказываем systemd перечитать конфигурацию, и перезапускаем Apache, чтобы
настройки вступили в силу\footnote{Прим. перев.: systemd версий до 197
включительно, не~поддерживает изменение параметров контрольных групп без
перезапуска службы. Но вы можете узнать контрольную группу службы командой
наподобие +systemctl show -p ControlGroup avahi-daemon.service+, и выполнить
настройки любым удобным для вас способом, например, через запись значений в
псевдофайлы cgroupfs (разумеется, при следующем запуске службы к ней будут
применены параметры, указанные в конфигурационном файле). Начиная с systemd 198,
в программу +systemctl+ добавлена поддержка команд +set-cgroup-attr+,
+unset-cgroup-attr+ и +get-cgroup-attr+.}:
дистрибутиве (если это включение не~указать явно, данный файл будет
проигнорирован). Далее, мы указываем тот параметр, который хотим
изменить\footnote{Прим. перев.: В новых версиях systemd, начиная со 198, можно
поступить проще: вместо того, чтобы создавать свой юнит-файл в каталоге +/etc+ и
включать в него содержимое штатного (из +/usr+), достаточно просто создать
каталог +/etc/systemd/system/httpd.service.d/+ и поместить в него файл
+my_resource_limit.conf+ (суффикс +.conf+ обязателен), в котором указываются
только те настройки, которые необходимо изменить (последние две строки
вышеприведенного листинга). Это никак не~отменяет основного конфигурационного
файла юнита (который может находиться в +/usr+ или +/etc+), однако настройки из
+.d+-каталогов имеют более высокий приоритет и могут перекрывать настройки
основного файла. Все вышесказанное относится и к другим примерам из этого
раздела.}. Сохраняем файл, приказываем systemd перечитать конфигурацию, и
перезапускаем Apache, чтобы настройки вступили в силу\footnote{Прим. перев.:
systemd версий до 197 включительно, не~поддерживает изменение параметров
контрольных групп без перезапуска службы. Но вы можете узнать контрольную группу
службы командой наподобие +systemctl show -p ControlGroup avahi-daemon.service+,
и выполнить настройки любым удобным для вас способом, например, через запись
значений в псевдофайлы cgroupfs (разумеется, при следующем запуске службы к ней
будут применены параметры, указанные в конфигурационном файле). Начиная с
systemd 198, в программу +systemctl+ добавлена поддержка команд
+set-cgroup-attr+, +unset-cgroup-attr+ и +get-cgroup-attr+, позволяющих
манипулировать практически всеми параметрами контрольных групп. При этом
поддерживается сохранение установленных таким образом параметров в виде
вспомогательных конфигурационных файлов в +.d+-каталогах (см. примечание
выше).}:
\begin{Verbatim}
systemctl daemon-reload
systemctl restart httpd.service
@@ -4242,7 +4276,7 @@ fi
\end{Verbatim}
Эта утилита возвращает код 0 (успех), обнаружив виртуализацию, или ненулевое
значение, если виртуализация не~выявлена. Кроме того, она выводит идентификатор
значение, если виртуализация не~выявлена. Также она выводит идентификатор
обнаруженной системы виртуализации (согласно списку выше), если это не~было
запрещено опцией +-q+. Кроме того, опции +-c+ и +-v+ позволяют ограничить
проверки только механизмами виртуализации на уровне ОС, либо полной
@@ -4343,8 +4377,8 @@ systemd в промышленных серверных платформах, м
Подобные конфигурации уже используются на рабочих серверах ряда компаний. В
частности, специалисты из \href{https://www.getpantheon.com/}{Pantheon}
используют такую схему для обслуживания масштабируемой инфраструктуры множества
сайтов на базе Drupal. (Стоит упомянуть, что заслуга ее внедрения в Pantheon
принадлежит Дэвиду Штрауссу. Дэвид, ты крут!)
сайтов на базе Drupal. (Стоит упомянуть, что заслуга ее внедрения в компании
Pantheon принадлежит Дэвиду Штрауссу. Дэвид, ты крут!)
\subsection{Сокет-активация контейнеров}
@@ -4527,13 +4561,10 @@ systemd начнет прослушивать TCP-порт 23. При подкл
классические inetd-службы, кроме встроенных) или systemd (зависят от библиотеки
+libsystemd-daemon.so+, либо содержат в исходниках заголовочный файл
+sd-daemon.h+). Службы, которые сами открывают себе слушающий сокет и
не~содержат кода для приема уже открытого сокета, так активировать нельзя.
Точнее, в случае с сетевыми и файловыми сокетами, все-таки можно, но первое
соединение/сообщение при этом будет <<потрачено>> на запуск контейнера, и до
службы в итоге дойдут только последующие, начина со второго, что сводит выгоды
практически к нулю.}, а те сокеты, которые будут настроены для прослушивания
внутри контейнера, но не~получены от хоста, будут активированы и доступны
изнутри контейнера (а если это сетевые или файловые unix-сокеты, то и извне).
не~содержат кода для приема уже открытого сокета, так активировать нельзя.}, а
те сокеты, которые будут настроены для прослушивания внутри контейнера, но
не~получены от хоста, будут активированы и доступны изнутри контейнера (а если
это сетевые или файловые unix-сокеты, то и извне).
Итак, давайте отступим чуть назад и полюбуемся на результаты наших трудов. Что
мы получили в итоге? Возможность настраивать на одном хосте множество
@@ -4579,6 +4610,661 @@ systemd, начиная с версии 197. Тем не~менее, наша р
мощных и хорошо масштабируемых серверных систем. За дополнительной информацией
обращайтесь к документации или приходите на наш IRC-канал. Спасибо за внимание!
\appendix
\section{Диагностика неполадок\sfnote{Перевод статьи
<<\href{http://freedesktop.org/wiki/Software/systemd/Debugging}{Debugging
systemd Problems}>> с официального сайта проекта, по состоянию на 2013-01-08
19:13:31 (ревизия \No26).}}
\subsection{Диагностика проблем с загрузкой}
Если система зависает во время загрузки, прежде всего нужно разобраться, на
каком этапе возникает проблема~--- до запуска systemd, или после.
Для этого надо удалить из командной стоки ядра параметры +quiet+ и +rhgb+. При
работе systemd на экран выводятся примерно такие сообщения:
\begin{Verbatim}[commandchars=\\\{\}]
Welcome to \textcolor{blue}{Fedora \emph{ВЕРСИЯ} (\emph{имя релиза})}!
Starting \emph{название}...
[ \textcolor{green}{OK} ] Stared \emph{название}...
\end{Verbatim}
(Пример можно посмотреть на
\href{http://freedesktop.org/wiki/Software/systemd/Debugging?action=AttachFile&do=view&target=f17boot.png}{скриншоте}.)
Если у вас есть доступ к оболочке, это значительно упрощает диагностику и
решение проблем. В том случае, когда до приглашения входа в систему дело так и
не~доходит, попробуйте переключиться на другую виртуальную консоль, нажав
CTRL--ALT--F<\emph{цифра}>. Дело в том, что при проблемах, связанных с запуском
X-сервера, может возникать ситуация, когда на первой консоли (+tty1+)
приглашение ко входу отсутствует, но все остальные консоли при этом работают
нормально.
Если ни~на одной из виртуальных консолей приглашение так и не~появилось~---
попробуйте выждать еще \emph{порядка 5 минут}. Только после этого можно
будет считать процесс загрузки окончательно зависшим. Если подвисание
обусловлено всего лишь сбоем при запуске какой-то службы, то после истечения
тайм-аута проблемная служба будет убита, и загрузка продолжится. Другой
вариант~--- отсутствует устройство, которое должно быть смонтировано для
нормальной работы системы. В этом случае загрузка будет остановлена, и система
перейдет в \emph{аварийный режим (emergency mode)}.
\subsubsection{Если у вас нет~доступа к оболочке}
Если система не~предоставила вам ни~нормального приглашения, ни~аварийной
оболочки, то для диагностики проблемы нужно выполнить следующие действия:
\begin{itemize}
\item Попытайтесь перезагрузить систему, нажав CTRL--ALT--DEL. Если после
этого перезагрузки не~произойдет~--- обязательно укажите данное
обстоятельство, когда будете писать отчет об ошибке (bugreport).
Чтобы перезагрузить систему, вы можете воспользоваться
\href{http://fedoraproject.org/wiki/QA/Sysrq}{SysRq} или
<<аппаратным>> методом.
\item При следующей загрузке попробуйте воспользоваться некоторыми
нижеописанными стратегиями.
\end{itemize}
\begin{description}
\item[Вывод диагностических сообщений на последовательную консоль]%
\hypertarget{it:serial}{} Если у вас под рукой есть терминал
последовательной консоли, либо дело происходит в виртуальной машине (в
частности, virt-manager позволяет просматривать вывод виртуальной машины
на последовательную консоль: меню Вид (View)~$\Rightarrow$ Текстовые
консоли (Text Consoles)), вы можете попросить systemd выводить на эту
консоль подробную отладочную информацию о ходе загрузки, добавив к
параметрам ядра следующие аргументы:
\begin{Verbatim}
systemd.log_level=debug systemd.log_target=console console=ttyS0,38400
\end{Verbatim}
\item[Загрузка в восстановительном (rescue) или аварийном (emergency)
режимах] Чтобы загрузиться в восстановительном режиме, добавьте к
параметрам ядра +systemd.unit=rescue.target+, или просто +1+. Это режим
эффективен для решения проблем, возникающих на этапе запуска обычных
служб, когда ключевые компоненты системы уже инициализированы. В такой
ситуации, вы можете просто отключить проблемную службу. Если же загрузка
не~доходит даже до восстановительного режима~--- попробуйте менее
требовательный, аварийный режим.
Для загрузки напрямую в режим аварийной оболочки, добавьте к параметрам
ядра +systemd.unit=emergency.target+, или просто +emergency+. Обратите
внимание, что в аварийном режиме корневая система по умолчанию
монтируется в режиме <<только для чтения>>, поэтому перед
восстановительными работами, связанными с записью на диск, необходимо
перемонтировать ее в режиме <<для чтения и записи>>:
\begin{Verbatim}
mount -o remount,rw /
\end{Verbatim}
Как правило, аварийная оболочка используется для исправления
некорректных записей в +/etc/fstab+. После внесения необходимых
изменений, скомандуйте +systemctl daemon-reload+, чтобы systemd увидел
ваши исправления.
Если не~работает даже аварийный режим, попробуйте загрузиться напрямую в
оболочку, добавив к параметрам ядра +init=/bin/sh+. Такая ситуация может
возникнуть вследствие повреждения бинарного файла systemd, либо
библиотек, которые он использует. В этом случае может помочь
переустановка соответствующих пакетов.
Если не~срабатывает даже +init=/bin/sh+, остается лишь попробовать
загрузиться с другого носителя.
\item[Отладочная оболочка]\hypertarget{it:dbgshell}{}
Вы можете включить специальную отладочную оболочку, которая запускается
в отдельной консоли на раннем этапе загрузки и позволяет собрать
необходимую диагностическую информацию, а также провести
восстановительные операции. Для включения отладочной оболочки
скомандуйте
\begin{Verbatim}
systemctl enable debug-shell.service
\end{Verbatim}
\textbf{Совет:} Если вы используете старую версию systemd, в которой еще
не~реализована поддержка отладочной оболочки, вы можете загрузить
соответствующий файл конфигурации юнита из
\href{http://cgit.freedesktop.org/systemd/systemd/plain/units/debug-shell.service.in}{git-репозитария
systemd}. Перед использованием этого файла, замените в нем +@sushell@+
на +/bin/bash+.
\textbf{Совет:} Если вы не~можете воспользоваться командой +systemctl+
(например, загрузились с помощью другой операционной системы), вы можете
выполнить соответствующие действия и напрямую:
\begin{Verbatim}
cd $ПУТЬ_К_ВАШЕМУ_КОРНЮ/etc/systemd/system
mkdir -p sysinit.target.wants
ln -s /lib/systemd/system/debug-shell.service sysinit.target.wants/
\end{Verbatim}
Отладочная оболочка будет запущена с правами +root+ на консоли +tty9+
при следующей загрузке системы. Чтобы переключиться на нее, нажмите
CTRL--ALT--F9. Оболочка запускается на самом раннем этапе загрузки и
позволяет вам проверять состояние служб, читать системные журналы,
выявлять зависшие задачи (командой +systemctl list-jobs+) и т.д.
\textbf{Предупреждение:} Используйте эту оболочку только для отладки!
Не~забудьте отключить ее после того, как разберетесь с проблемами.
Оставлять доступную всем и каждому оболочку с правами +root+, мягко
говоря, небезопасно.
\item[Проверка параметров ядра] Для корректной загрузки системы необходимо,
чтобы каталог +/dev+ был заполнен, хотя бы частично. Убедитесь, что ядро
Linux собрано с опциями +CONFIG_DEVTMPFS+ и +CONFIG_DEVTMPFS_MOUNT+.
Кроме того, для корректной работы systemd рекомендуется включить
поддержку контрольных групп и fanotify (опции +CONFIG_CGROUPS+ и
+CONFIG_FANOTIFY+ соответственно). Отключение этих опций может привести
к появлению сообщений об ошибках вида <<Failed to get D-Bus
connection: No connection to service manager.>> при попытке запуска
+systemctl+.
\end{description}
\subsubsection{Если у вас есть доступ к оболочке}
Если вам все-таки удалось получить доступ к оболочке системы, вы можете
воспользоваться ею для сбора диагностической информации. Загрузите систему со
следующими параметрами ядра:
\begin{Verbatim}
systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M
\end{Verbatim}
В соответствии с ними, systemd будет выводить максимально подробные сообщения о
процессе загрузки, и направлять их в кольцевой буфер ядра (последний параметр
обеспечивает соответствующее увеличение размера буфера). Дождавшись запуска
оболочки, сохраните полученный журнал:
\begin{Verbatim}
dmesg > dmesg.txt
\end{Verbatim}
Отправляя отчет об ошибке, присоедините к нему полученный файл +dmesg.txt+.
Также, вы можете просмотреть список операций, чтобы выявить зависшие задачи:
\begin{Verbatim}
systemctl list-jobs
\end{Verbatim}
Операции, находящиеся в состоянии <<waiting>>, будут запущены на исполнение
только после того, как завершатся операции, выполняемые в данный момент
(состояние <<running>>).
\subsection{Диагностика проблем с выключением системы}
При зависании системы во время выключения, как и в случае с загрузкой,
рекомендуется подождать \emph{минимум 5 минут}, чтобы отличить полное зависание
системы от временного подвисания из-за проблем с отдельными службами. Также
стоит проверить, реагирует ли система на нажатие CTRL--ALT--DEL.
Если процесс остановки системы (при выключении или перезагрузке) зависает
полностью, прежде всего нужно убедиться, способно ли ядро Linux выключить или
перезагрузить систему. Для этого воспользуйтесь одной из команд:
\begin{Verbatim}
sync && reboot -f
sync && poweroff -f
\end{Verbatim}
Если хотя бы одна из этих команд не~сработает~--- значит, проблема не~в systemd,
а в ядре.
\subsubsection{Система очень долго выключается}
Если ваша система все же может выключиться/перезагрузиться, но этот процесс
длится подозрительно долго, выполните нижеописанные операции:
\begin{itemize}
\item Загрузите систему со следующими параметрами ядра:
\begin{Verbatim}
systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M enforcing=0
\end{Verbatim}
\item Создайте файл +/lib/systemd/system-shutdown/debug.sh+, добавьте
ему право на запуск и запишите в него следующие строки:
\begin{Verbatim}
#!/bin/sh
mount -o remount,rw /
dmesg > /shutdown-log.txt
mount -o remount,ro /
\end{Verbatim}
\item Перезагрузите систему.
\end{itemize}
После этого вы можете самостоятельно проанализировать файл +/shutdown-log.txt+,
и/или присоединить его к вашему сообщению об ошибке.
\subsubsection{Система не~может выключиться самостоятельно}
Если процесс выключения или перезагрузки вашей системы не~завершается даже через
несколько минут, и вышеописанный метод с +shutdown-log+ не~сработал, вы можете
собрать диагностическую информацию другими методами (которые мы уже
рассматривали применительно к проблемам загрузки):
\begin{itemize}
\item Используйте \hyperlink{it:serial}{последовательную консоль}.
\item Воспользуйтесь \hyperlink{it:dbgshell}{отладочной оболочкой}~---
она полезна не~только на ранних стадиях загрузки, но и на
поздних стадиях остановки системы.
\end{itemize}
\subsection{Просмотр состояния службы и ее журнала}
Когда при запуске службы происходит сбой, systemd выводит весьма абстрактное
сообщение об ошибке:
\begin{Verbatim}
# systemctl start foo.service
Job failed. See system journal and 'systemctl status' for details.
\end{Verbatim}
При этом сама служба может выводить собственное сообщение, но вы (пока что) его
не~видите. Дело в том, что запуск служб происходит не~из вашей оболочки, а из
процесса systemd, и поэтому вывод программы не~привязан к вашей консоли. Тем
не~менее, это вовсе не~означает, что выводимые сообщения теряются. По умолчанию,
потоки STDOUT и STDERR, принадлежащие запускаемым службам, перенаправляются в
системный журнал (journal). Туда же попадают и сообщения, отправляемые с помощью
функции +syslog(3)+. Кроме того, systemd записывает код выхода сбойных
процессов. Посмотреть собранные данные можно, например, так:
\begin{Verbatim}
# systemctl status foo.service
foo.service - mmm service
Loaded: loaded (/etc/systemd/system/foo.service; static)
Active: failed (Result: exit-code) since Fri, 11 May 2012 20:26:23 +0200; 4s ago
Process: 1329 ExecStart=/usr/local/bin/foo (code=exited, status=1/FAILURE)
CGroup: name=systemd:/system/foo.service
May 11 20:26:23 scratch foo[1329]: Failed to parse config
\end{Verbatim}
В нашем примере, служба запустилась как процесс с идентификатором (PID) 1329,
после чего завершилась с кодом выхода 1. Если вы запустили команду
+systemctl status+ от имени пользователя +root+, либо от имени пользователя,
входящего в группу +adm+, вы также увидите последние несколько строчек,
записанные службой в журнал. В нашем примере служба выдала всего одно сообщение
(<<Failed to parse config>>).
Чтобы просмотреть весь журнал целиком, воспользуйтесь командой +journalctl+.
Если одновременно с journal вы используете и классический демон системного лога
(например, rsyslog), то все сообщения из журнала будут переданы также и этому
демону, который запишет их в традиционные лог-файлы (в какие именно~--- зависит
от его настроек, обычно +/var/log/messages+).
\subsection{Подготовка сообщений об ошибках}
Если вы собираетесь отправить сообщение об ошибке в systemd, пожалуйста,
включите в него диагностическую информацию, в частности, содержимое системных
журналов. Журналы должны быть полными (без вырезок), не~заархивированными, с
MIME-типом +text/plain+.
Прежде всего, отправьте сообщение в багтрекер своего дистрибутива. Если же вы
твердо уверены, что проблема именно в апстримном systemd, проверьте сначала
список
\href{https://bugs.freedesktop.org/buglist.cgi?query_format=advanced&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&product=systemd}{уже
известных ошибок}. Если вы не~найдете в нем своего случая~---
\href{https://bugs.freedesktop.org/enter_bug.cgi?product=systemd}{заводите новую
запись}.
\subsubsection{Что нужно включить в сообщение об ошибке}
По возможности, пожалуйста, укажите в самом сообщении, либо присоедините к нему,
следующую информацию:
\begin{itemize}
\item Строку параметров ядра, если она отличается от значения по
умолчанию. Ее можно найти в файле конфигурации загрузчика
(например, +/boot/grub2/grub.cfg+) или в специальном файле
+/proc/cmdline+.
\item Копию файла +/var/log/messages+.
\item Файл +dmesg.txt+, полученный после выполнения команды
\begin{Verbatim}
dmesg > dmesg.txt
\end{Verbatim}
Перед ее выполнением лучше загрузиться с параметрами ядра
\begin{Verbatim}
systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M
\end{Verbatim}
\item Файл +systemd-dump.txt+, полученный в результате выполнения
команды
\begin{Verbatim}
systemctl dump > systemd-dump.txt
\end{Verbatim}
\item Файл +systemd-test.txt+, полученный при помощи команды
\begin{Verbatim}
/usr/bin/systemd --test --system --log-level=debug > systemd-test.txt 2>&1
\end{Verbatim}
\end{itemize}
\section{Специальные файловые системы\sfnote{Перевод статьи
<<\href{http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems}{API
File Systems}>> с официального сайта проекта, по состоянию на 2013-01-17
11:06:59 (ревизия \No14).}}
\emph{Итак, вы запустили программу mount(8), и увидели в ее выводе множество
странных файловых систем, не~указанных в /etc/fstab. У вас могут возникнуть
вопросы: <<Как их убрать?>> или <<Как задать для них параметры монтирования?>>.}
В Linux предусмотрено несколько способов взаимодействия программ из пространства
пользователя с ядром. Наиболее популярными механизмами являются системные вызовы
(syscall), интерфейсы Netlink, а также виртуальные файловые системы (ФС), такие,
как +/proc+ и +/sys+. Подобные ФС являются лишь программными интерфейсами, и
не~предоставляют возможности для долговременного хранения данных (в частности,
между перезагрузками системы). Они просто используют классические механизмы
работы с файлами для предоставления доступа к различным данным и настройкам.
Кроме того, существуют специальные ФС, используемые программами для собственных
нужд, в частности, для хранения сегментов разделяемой памяти (shared memory),
временных файлов и сокетов. В данной статье мы обсудим все эти разновидности
\emph{специальных файловых систем}. Ниже представлен список таких ФС,
поддерживаемых в типовых Linux-системах:
\begin{itemize}
\item +/sys+ предоставляет доступ к драйверам и устройствам, а также
некоторым другим параметрам ядра
\item +/proc+ дает доступ к информации о выполняемых процессах,
настройкам ядра, а также другим параметрам
\item +/dev+ отображает файлы устройств (device nodes)
\item +/run+ содержит файлы и сокеты, используемые программами
\item +/tmp+ хранит временные и часто изменяемые объекты (X)
\item +/sys/fs/cgroup+ (и другие файловые системы, смонтированные в
подкаталогах этого каталога) позволяют работать с иерархией
контрольных групп
\item +/sys/kernel/security+, +/sys/kernel/debug+ (X),
+/sys/kernel/config+ (X) предоставляют доступ к
специализированным механизмам ядра
\item +/sys/fs/selinux+ используется для взаимодействия с SELinux
\item +/dev/shm+ содержит объекты разделяемой памяти
\item +/dev/pts+ обеспечивает доступ к псевдо-TTY устройствам
\item +/proc/sys/fs/binfmt_misc+ используется для регистрации в ядре
дополнительных бинарных форматов (X)
\item +/dev/mqueue+ содержит объекты IPC-механизма mqueue (X)
\item +/dev/hugepages+ позволяет программам запрашивать выделение
<<гигантских>> страниц памяти (X)
\item +/sys/fs/fuse/connections+ обеспечивает доступ к
FUSE-соединениям (X)
\item +/sys/firmware/efi/efivars+ предоставляет доступ к переменным EFI
\end{itemize}
systemd монтирует все эти файловые системы на ранних стадиях загрузки, даже если
они не~указаны явно в +/etc/fstab+. В зависимости от настроек вашего ядра,
некоторые из перечисленных выше ФС могут быть недоступны, и наоборот, могут
присутствовать другие специальные ФС, не~приведенные в этом списке. Все эти
механизмы играют важную роль во взаимодействии ядра с программами и программ
между собой. Именно поэтому они подключаются автоматически, безо всякого участия
пользователя. Необдуманное вмешательство в их работу (отключение или изменение
параметров) может нарушить нормальную работу ваших программ, так как они утратят
доступ к необходимым для них интерфейсам.
В абсолютном большинстве случаев достаточно настроек, используемых по умолчанию.
Однако, могут возникнуть ситуации, когда необходимо изменить параметры
монтирования специальных ФС, либо полностью отключить монтирование некоторых из
них.
Несмотря на то, что эти ФС по умолчанию отсутствуют в +/etc/fstab+, ничто
не~мешает вам их туда добавить. Параметры монтирования, которые вы при этом
укажете, будут автоматически применяться к соответствующим ФС. Проще говоря:
если вам нужно изменить параметры монтирования для специальных ФС, просто
добавьте их в +/etc/fstab+ с указанием соответствующих опций. Кроме параметров
монтирования, так можно изменить и сам тип файловой системы. В частности, этот
способ позволяет переключить +/tmp+ с +tmpfs+ на физический дисковый раздел.
Также вы можете полностью отключить монтирование некоторых (но не~всех)
специальных систем, если это действительно необходимо. Отключаемые ФС в списке
выше отмечены (X). Для их отключения, достаточно замаскировать соответствующий
юнит:
\begin{Verbatim}
systemctl mask dev-hugepages.mount
\end{Verbatim}
В результате выполнения такой операции, соответствующая ФС больше не~будет
монтироваться по умолчанию, начиная со следующей загрузки системы. О том, что
такое маскировка юнита, вы можете прочитать в~главе~\ref{sec:off}.
На всякий случай отметим, что применение к специальным ФС параметров монтирования,
указанных в +/etc/fstab+, обеспечивается службой
\hreftt{http://www.freedesktop.org/software/systemd/man/systemd-remount-fs.service.html}%
{systemd-remount-fs.service}.
\subsection*{Зачем вы мне все это рассказываете? Я просто хочу убрать tmpfs из
/tmp!}
У вас есть три варианта:
\begin{enumerate}
\item Вы можете отключить любое монтирование в +/tmp+, в результате чего
содержимое данного каталога будет храниться на том же разделе, что
и корень. Для этого достаточно выполнить команду
\begin{Verbatim}
systemctl mask tmp.mount
\end{Verbatim}
\item Вы можете смонтировать в +/tmp+ обычную файловую систему,
размещенную на диске. Для этого достаточно создать
соответствующую запись в +/etc/fstab+.
\item Если вы хотите оставить в +/tmp+ +tmpfs+, но при этом задать для
нее другой размер~--- это тоже делается через внесение в
+/etc/fstab+ соответствующей записи, предписывающей монтирование
+tmpfs+ в +/tmp+ с нужным вам значением параметра +size=+.
\end{enumerate}
\section{Запуск служб после появления сети\sfnote{Перевод статьи
<<\href{http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget}{Running
Services After the Network is up}>> с официального сайта проекта, по состоянию
на 2013-01-17 23:22:58 (ревизия \No17).}}
\emph{Итак, ваша служба настроена на запуск только после достижения цели
network.target, однако, несмотря на это, она все равно запускается до появления
сети. У вас возникают вопросы: <<Почему так происходит?>> и <<Как это
исправить?>>.}
Цель +network.target+ является systemd-шным аналогом LSB-сущности (facility)
\verb+$network+. Определение этой сущности в стандарте
\href{http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/facilname.html}%
{довольно расплывчато} и оставляет широкий простор для трактовок. Вот примеры
некоторых из них:
\begin{itemize}
\item Все заданные в настройках сетевые интерфейсы переведены в состояние
UP и получили IP-адреса.
\item Все имеющиеся физические сетевые интерфейсы, на которых
зарегистрирована несущая (link beat), получили IP-адреса.
Наличие или отсутствие явных настроек роли не~играет.
\item Доступен DNS-сервер.
\item Доступен некоторый выбранный сервер.
\item Доступен некий абстрактный <<интернет>>.
\item Все заданные в настройках ethernet-интерфейсы переведены в
состояние UP, однако процесс настройки PPP-интерфейсов еще
не~начался.
\item Активирован некий профиль сетевых настроек, задающий одно из
условий выше. В разных профилях могут использоваться разные
условия.
\item Выполняется некоторое условие (выбор условия определяется
физическим расположением системы).
\item Настроен как минимум один глобальный адрес IPv4.
\item Настроен как минимум один глобальный адрес IPv6.
\item Настроен как минимум один глобальный адрес IPv4 или IPv6.
\end{itemize}
Этот список можно продолжать и дальше. Каждый предложенный в нем вариант можно
использовать в качестве критерия появления сети, однако ни~один из них
не~подходит в качестве варианта по умолчанию, пригодного для абсолютного
большинства задач.
Современные компьютерные сети живут в очень динамичном ритме: компьютеры
перемещаются между сетями, сетевые настройки меняются, устройства подключаются и
отключаются, виртуальные сети настраиваются, перенастраиваются и выключаются.
Наличие сетевого соединения не~является чем-то постоянным и безусловным. В
разные моменты времени компьютер может быть подключен к разным сетям. И это
справедливо не~только для мобильных устройств (смартфонов, планшетов и
ноутбуков), но и, в определенной мере, для встраиваемых и серверных систем.
Программы, которые считают, что сеть является чем-то неизменным и непрерывно
доступным, не~могут нормально функционировать в таких условиях. Хорошо
написанная программа должна корректно реагировать на изменение состояния сети, и
не~унывать в беде. Если нужный ей сервер не~доступен в настоящий момент, она
должна не~зависать по тайм-ауту, а пытаться достучаться к нему снова и снова.
Если сетевое соединение утрачено, она должна отреагировать на это. Реализовать
такое реагирование в коде демона, на самом деле, не~так уж и сложно. Существует
множество хорошо известных сетевых служб, которые уже давно поддерживают такую
возможность. Подобные службы можно запускать в любой момент, они устойчивы к
сбоям, и в любой ситуации работают корректно.
+network.target+ предназначена для поддержки программ, созданных в
предположении, что сеть доступна постоянно (т.е. написанных не~очень аккуратно).
Конкретные требования таких программ могут сильно отличаться. Например,
IMAP-серверу будет достаточно наличия IP-адреса, на котором можно слушать. В то
время как для клиентов сетевых файловых систем требуется требуется доступность и
работоспособность сервера, а также, опционально, наличие работоспособного DNS.
Таким образом, конкретные требования к +network.target+ сильно зависят от
решаемой задачи.
По соображениям надежности, загрузка системы не~должна зависеть от второстепенных
служб. В частности, отсутствие ответа от DHCP-сервера не~должно завешивать
процесс загрузки системы (за исключением ситуаций, когда сетевое соединение
действительно необходимо для работы системы, например, при загрузке по сети).
По умолчанию, +network.target+ не~несет какой-либо сакральной смысловой
нагрузки. Сама по себе настройка службы на запуск после достижения этой цели
не~дает видимого эффекта. Наполнить +network.target+ смыслом должен сам
администратор, в зависимости от задачи которую он решает, и от конкретных
потребностей тех программ, с которыми ему приходится работать (а эти
потребности, в свою очередь, могут зависеть от их настроек). По умолчанию, мы
оставили +network.target+ <<пустышкой>>, что позволяет обеспечить максимальную
скорость загрузки, и предоставили администратору возможность самостоятельно
определить список проверок, который он считает наиболее целесообразным для
данной системы.
\subsection*{Короче, как заставить network.target работать?}
Конкретный рецепт зависит от решаемой вами задачи и потребностей ваших служб
(см. выше). Если вы используете NetworkManager, вы можете задействовать
специальную службу +NetworkManager-wait-online.service+:
\begin{Verbatim}
systemctl enable NetworkManager-wait-online.service
\end{Verbatim}
Включение этой службы позволит гарантировать, что загрузка продолжится только
после того, как все заданные в настройках NM сетевые интерфейсы будут переведены
в состояние UP и получат IP-адреса. Максимальное время ожидания~--- 90
секунд\footnote{Прим. перев.: В апстримной конфигурации по умолчанию сейчас
используется значение 30 секунд. См. параметр +--timeout+ программы +nm-online+
в файле настроек службы
+/usr/lib/systemd/system/NetworkManager-wait-online.service+.}.
Обратите внимание, что включение данной службы может сильно замедлить загрузку.
Если же такое вариант вас не~устраивает, вы можете подготовить собственный
service-файл, запускающий любую заданную вами программу или скрипт. Не~забудьте
указать, что он должен быть запущен до достижения цели +network.target+ (при
помощи параметра +Before=+). Кроме того, стоит указать зависимость от
+network.target+ при помощи директивы +Wants=+\footnote{Прим. перев.: Также
не~стоит забывать, что ваша служба сама должна быть кем-то активирована. Это
определяется параметром +WantedBy=+ или +RequiredBy=+ секции +[Install]+. Проще
всего указать здесь ту же самую +network.target+: в результате, ваша служба и
+network.target+ будут взаимно зависеть друг от друга, но при этом
+network.target+ будет активирована только после того, как отработает ваша
служба. Разница между +WantedBy=+ и +RequiredBy=+ состоит в том, что при
использовании Require требуется \emph{успешное} завершение запуска вашей службы.
Если он завершится с ненулевым кодом выхода или по сигналу, +network.target+
не~будет активирована. В то время как для Want достаточно просто завершения
запуска, вне зависимости от успешности. В качестве основы вы можете взять
\href{http://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/data/NetworkManager-wait-online.service.in}%
{апстримный файл} +NetworkManager-wait-online.service+. В завершение,
не~забудьте выполнить для своей службы +systemctl enable+.}.
\subsection*{А что делать нам, разработчикам?}
Если вы~--- не~администратор, а разработчик сетевой службы, то вам стоит
задуматься не~о том, что делать с +network.target+, а о том, как можно исправить
вашу службу, чтобы она нормально реагировала на изменение состояния сети. Это
позволит порадовать ваших пользователей (когда программа работает без
дополнительной возни~--- это не~может не~радовать), а также уменьшит количество
сообщений об ошибках (так как ваша программа уже не~будет паниковать по
пустякам). Кроме того, системы ваших пользователей будут грузиться быстрее,
потому что их уже не~будет задерживать необходимость ожидать появления сети (в
случае с медленным DHCP-сервером, прогресс может быть весьма ощутимым).
Можно предложить несколько подходов к решению этой задачи:
\begin{itemize}
\item Отслеживайте изменений конфигурации сети при помощи
\href{https://www.kernel.org/doc/man-pages/online/pages/man7/rtnetlink.7.html}%
{rtnetlink} и реагируйте соответствующим образом. Это наиболее
правильный, но далеко не~всегда простой способ.
\item Если вы разрабатываете серверное приложение: слушайте только
адреса 0.0.0.0 и 127.0.0.1. Оба этих псевдо-адреса должны быть
доступны постоянно. Если ваша программа будет слушать только их,
ей будут глубоко безразличны изменения конфигурации сети.
\item Если вы разрабатываете серверное приложение и вам нужно слушать
некий заданный адрес: воспользуйтесь опцией
\href{https://www.kernel.org/doc/man-pages/online/pages/man7/ip.7.html}%
{IP\_FREEBIND}, доступной на Linux-системах. Она позволит вашей
программе слушать даже те адреса, которые не~присвоены локальным
сетевым интерфейсам (в данный момент или вообще), что также
сделает ваш код устойчивым к изменению сетевой конфигурации.
\end{itemize}
\section{Моя служба не~может получить приоритет realtime\sfnote{Перевод статьи
<<\href{http://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime}%
{My Service Can't Get Realtime!}>> с официального сайта проекта, по состоянию на
2013-01-15 16:54:09 (ревизия \No1).}}
\emph{Итак, у вас есть служба, которая требует приоритет реального времени
(realtime). Однако, когда вы пытаетесь запустить ее на системе, работающей под
управлением systemd, ваша служба не~может получить этот приоритет, хотя обладает
всеми необходимыми для этого привилегиями. Вы хотите понять, почему это
происходит, и как это можно исправить.}
\subsection*{В чем же дело?}
По умолчанию, systemd помещает каждую системную службу в свою контрольную группу
в иерархии контроллера +cpu+. Такое поведение дает очень полезный эффект: службы
с множеством рабочих потоков (например, Apache с сотнями CGI-процессов),
получают примерно такую же долю процессорного времени, как и службы с небольшим
количеством рабочих потоков (например, MySQL). Проще говоря, процессорное время
распределяется уже не~\emph{между процессами}, а \emph{между службами}.
К сожалению, в настоящее время реализация cpu-контроллера в Linux имеет один
существенный недостаток: она требует явного задания realtime-бюджета времени (RT
budget) для своих контрольных групп. Если же бюджет группы не~задан, то ее
процессы не~смогут получить приоритет реального времени (соответствующая
операция будет завершаться с ошибкой +EPERM+~--- <<недостаточные полномочия>>).
systemd не~может присваивать такой бюджет \emph{каждой} группе, просто потому,
что не~знает, как его правильно делить между ними. Бюджет выдается в абсолютных
единицах времени, и их общее количество ограничено. Мы не~можем предложить
механизм распределения бюджета, который бы подходил по умолчанию для большинства
случаев. Поэтому, в конфигурации по умолчанию, приоритет реального времени
недоступен для системных служб.
\subsection*{Как это исправить?}
Обойти это ограничение несложно. Существует несколько различных путей:
\begin{itemize}
\item Можно просто отключить использование cpu-контроллера по умолчанию
для системных служб. Для этого, задайте в файле
+/etc/systemd/system.conf+ параметр +DefaultControllers=+ равным
пустой строке, после чего перезагрузите систему. (Также вы
можете отключить контроллер +cpu+ на этапе сборки ядра. systemd
не~пытается использовать контроллеры, которые не~поддерживаются
ядром.)
\item Также вы можете отключить группировку по +cpu+ только для
конкретных служб. Для этого отредактируйте конфигурацию службы,
добавив параметр +ControlGroup=cpu:/+ в секцию +[Service]+. В
результате, процессы данной службы будут помещены не~в
собственную контрольную группу (как это делалось по умолчанию),
а в корневую контрольную группу иерархии +cpu+. Процессы из
корневой группы располагают полным realtime-бюджетом.
\item И наконец, вы можете явно выделить своей службе некоторый бюджет.
Для этого добавьте в секцию +[Service]+ строку наподобие
+ControlGroupAttribute=cpu.rt_runtime_us 500000+. Подробнее о
правильном распределении бюджета читайте в
\href{http://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt}%
{документации к ядру}.
\end{itemize}
Последние две опции недоступны для SysV-служб. Тем не~менее, вы можете
подготовить для них соответствующие service-файлы, которые, помимо упомянутых
выше параметров, содержат вызов соответствующего init-скрипта с аргументом
+start+ в +ExecStart=+, и с аргументом +stop+~--- в +ExecStop=+.
(Также имеет смысл задать для них параметры +RemainAfterExit=1+ и
+Type=forking+.)
Отметим, что все вышесказанное касается только системных служб, и не~затрагивает
пользовательские сеансы. По умолчанию, программы пользователя размещаются в
корневой группе контроллера +cpu+, и поэтому вышеописанные ограничения их
не~касаются.
Мы надеемся, что в будущем ядро будет исправлено таким образом, чтобы
не~требовать явного задания realtime-бюджета для получения приоритета реального
времени (а при получении такого приоритета, бюджет процесса должен автоматически
выделяться из бюджета ближайшей родительской группы). В идеале, мы хотели бы
распространить практику выделения cpu-групп не~только на системные службы, но и
на пользовательские сеансы, чтобы уравнять пользователей в правах на
процессорное время, вне зависимости от того, сколько процессов запускает каждый
конкретный пользователь.
\end{document}
vim:ft=tex:tw=80:spell:spelllang=ru