diff --git a/s4a.tex b/s4a.tex index 68a39b0..0056fcf 100644 --- a/s4a.tex +++ b/s4a.tex @@ -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} @@ -972,6 +974,7 @@ Apache, crond, atd, которые по роду служебной деятел не~отдельному процессу. \section{Три уровня выключения} +\label{sec:off} В \href{http://www.freedesktop.org/wiki/Software/systemd}{systemd} существует три уровня (разновидности) действий, направленных на прекращение работы службы @@ -3485,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 @@ -4601,7 +4612,10 @@ systemd, начиная с версии 197. Тем не~менее, наша р \appendix -\section{Диагностика проблем при работе с systemd} +\section{Диагностика неполадок\sfnote{Перевод статьи +<<\href{http://freedesktop.org/wiki/Software/systemd/Debugging}{Debugging +systemd Problems}>> с официального сайта проекта, по состоянию на 2013-01-08 +19:13:31 (ревизия \No26).}} \subsection{Диагностика проблем с загрузкой} @@ -4628,9 +4642,9 @@ X-сервера, может возникать ситуация, когда н Если ни~на одной из виртуальных консолей приглашение так и не~появилось~--- попробуйте выждать еще \emph{порядка 5 минут}. Только после этого можно -будет утверждать, что процесс загрузка завис окончательно. Если подвисание -обусловлено сбоем при запуске какой-то службы, то после истечения -тайм-аута проблемная служба будет убита, и загрузка может продолжиться. Другой +будет считать процесс загрузки окончательно зависшим. Если подвисание +обусловлено всего лишь сбоем при запуске какой-то службы, то после истечения +тайм-аута проблемная служба будет убита, и загрузка продолжится. Другой вариант~--- отсутствует устройство, которое должно быть смонтировано для нормальной работы системы. В этом случае загрузка будет остановлена, и система перейдет в \emph{аварийный режим (emergency mode)}. @@ -4893,15 +4907,363 @@ MIME-типом +text/plain+. +/proc/cmdline+. \item Копию файла +/var/log/messages+. \item Файл +dmesg.txt+, полученный после выполнения команды - +dmesg > dmesg.txt+ (перед ее выполнением лучше загрузиться с - параметрами ядра - +systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M+. +\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+, полученный в результате выполнения - команды +systemctl dump > systemd-dump.txt+. + команды +\begin{Verbatim} +systemctl dump > systemd-dump.txt +\end{Verbatim} \item Файл +systemd-test.txt+, полученный при помощи команды - +/usr/bin/systemd --test --system --log-level=debug > systemd-test.txt 2>&1+. +\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}