Compare commits

...

2 Commits
v15.0 ... v15.2

Author SHA1 Message Date
nnz1024
78ebb26a64 Version v15.2 (2013-05-01 20:53) [AUTO] 2017-08-17 23:05:41 +03:00
nnz1024
df098ff4c1 Version v15.1 (2013-04-29 00:07) [AUTO] 2017-08-17 23:05:40 +03:00

617
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}
@@ -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,598 @@ 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/PredictableNetworkInterfaceNames}%
{Predictable Network Interface Names}>> с официального сайта проекта, по
состоянию на 2013-01-22 20:22:48 (ревизия \No27).}}
Начиная с версии 197, systemd/udev присваивает сетевым интерфейсам (Ethernet,
WLAN, WWAN\footnote{Прим. перев.: WWAN (Wireless Wide Area Network)~---
относительно новый термин, обозначающий технологии глобальных беспроводных
компьютерных сетей, такие, как GPRS, 3G, WiMAX и т.д.}) стабильные,
предсказуемые имена. Новая схема именования несколько отличается от классической
(+eth0+, +eth1+, +wlan0+, \ldots{}), однако при этом лишена и многих ее
недостатков.
\subsection{Зачем?}
Классическая схема именования сетевых интерфейсов, используемая ядром,
предполагает последовательное присвоение интерфейсам имен +eth0+, +eth1+ и т.д.,
по мере опроса оборудования соответствующими драйверами (device probing). На
современных системах такой опрос не~обеспечивает гарантированного соблюдения
одного и того же порядка поступления ответов. Вследствие этого, соответствие
имен реальным интерфейсам не~является чем-то фиксированным, и очень может быть,
что интерфейс, который сейчас называется +eth0+, при следующей загрузке
превратится в +eth1+. Такая ситуация приводит к целому ряду проблем, в
частности, к проблемам с безопасностью: в настройках брандмауэра интерфейсы
идентифицируются как раз по именам.
Существует несколько подходов к решению этой проблемы. В течение многих лет udev
поддерживал механизм постоянной привязки имен к интерфейсам, на основе
MAC-адресов. Такой подход имел множество недостатков, в том числе: требование
доступности корневого каталога на запись (что возможно далеко не~всегда);
необходимость внесения изменений в образ системы после загрузки на новом
оборудовании; привязка к MAC-адресам, которые далеко не~всегда являются
фиксированными (в частности, это касается многих встраиваемых систем и
механизмов виртуализации). Тем не~менее, основная проблема такого подхода
состояла в том, что он использовал имена из того же адресного пространства
(+ethX+), что и ядро. Вследствие этого, возникали ситуации <<гонки>> между udev
и ядром, когда udev пытался присвоить интерфейсу имя, которое ядро уже выдало
другому интерфейсу, что приводило к сбою операции переименования. Вследствие
перечисленных недостатков, данный механизм был удален из
systemd/udev\footnote{Прим. перев.: См. коммит
\href{http://cgit.freedesktop.org/systemd/systemd/commit/?id=3e2147858f21943d5f4a781c60f33ac22c6096ed}%
{3e214} от 3 апреля 2012 года, в котором, среди прочего, был удален каталог
+src/udev/src/rule_generator+.}.
Другая попытка решения обсуждаемой проблемы~--- +biosdevname+, программа,
формирующая имена интерфейсов на основании их физического расположении на
материнской плате. Соответствующая информация запрашивается у BIOS. В чем-то
такая схема похожа на ту, которую udev уже давно использует для формирования
стабильных символьных ссылок на различные устройства (+/dev/*/by-path/*+), но,
тем не~менее, в ее основе лежат несколько иные алгоритмы (udev, формируя свои
символьные ссылки, опирается на идентификационные данные, предоставленные
ядром, в то время как biosdevname использует свои собственные схемы).
И наконец, многие дистрибутивы в своих сетевых скриптах поддерживают механизмы,
позволяющие присваивать интерфейсам имена, выбранные пользователем (например,
+internet0+, +dmz0+, \ldots). Если бы не~необходимость явного вмешательства
пользователя, это было бы замечательным решением.
Мы пришли к выводу, что наилучшим вариантом для настроек по умолчанию будет
схема, являющаяся обобщением и развитием механизма biosdevname. Присвоение
интерфейсам имен на основании информации об их физическом расположении имеет ряд
существенных достоинств: такие имена формируются автоматически, всегда
предсказуемы, а также остаются неизменными даже при добавлении и удалении
оборудования, что позволяет без лишних проблем заменять сломанные сетевые
устройства. Тем не~менее, такие выглядят немного сложнее, чем привычные +eth0+ и
+wlan0+, например: +enp5s0+.
\subsection{Что именно было изменено в версии 197?}
В версии 197 мы добавили в systemd/udevd встроенную поддержку нескольких
различных механизмов именования сетевых интерфейсов, получив в итоге схему,
похожую на biosdevname, но отличающуюся большей гибкостью и максимально
приближенную к алгоритмам идентификации устройств, используемым в ядре.
В частности, udev теперь штатно поддерживает следующие механизмы именования
сетевых интерфейсов:
\begin{enumerate}
\item Схема именования для устройств, встроенных в материнскую плату (на
основании информации от EFI/BIOS), например: +eno1+.
\item Схема именования для устройств, подключенных в слоты PCI Express
(также на основании информации от EFI/BIOS), например: +ens1+.
\item Схема именования, основанная на физическом расположении точки
подключения оборудования, например, +enp2s0+.
\item Схема именования на основании MAC-адреса, например,
+enx78e7d1ea46da+.
\item Классические, непредсказуемые имена, присвоенные ядром, например,
+eth0+.
\end{enumerate}
По умолчанию, systemd 197 при именовании сетевых интерфейсов последовательно
пытается применить схемы 1--3 (для первых двух требуется информация от
EFI/BIOS). Если ни одна из них не~подходит, используется схема 5. Что касается
схемы 4~--- она не~задействована по умолчанию, однако ее можно включить вручную.
Вышеописанная комбинированная схема используется лишь \emph{в последнюю
очередь}. Если у вас установлена программа biosdevname, для именования сетевых
устройств будет использоваться именно она. Кроме того, приоритет предоставляется
любым правилам, добавленным пользователем или разработчиками дистрибутива.
\subsection{Еще раз, что здесь хорошего?}
С нашей новой схемой вы получаете:
\begin{itemize}
\item Имена интерфейсов остаются неизменными после перезагрузок.
\item Имена интерфейсов остаются неизменными при добавлении или
удалении устройств.
\item Имена интерфейсов остаются неизменными при обновлении/изменении
ядра и драйверов.
\item Имена интерфейсов остаются неизменными при замене сломанных
сетевых карт новыми.
\item Имена формируются автоматически, безо всякого вмешательства
пользователя.
\item Имена являются предсказуемыми: достаточно просто взглянуть на
вывод +lspci+, чтобы узнать, как будет называться конкретное
устройство.
\item Изменения в аппаратной конфигурации не~приводят к необходимости
записи в каталог +/etc+.
\item Полная поддержка системам, корень которых доступен только
для чтения.
\item Схема именования аналогичная той, которая используется
udev для формирования стабильных символьных ссылок в каталоге
+/dev+ (+by-path+).
\item Работает как на x86, так и на~других архитектурах.
\item Работает одинаково во всех дистрибутивах, использующих на
systemd/udev.
\item От этой схемы очень легко отказаться (см. ниже).
\end{itemize}
Есть ли у нее недостатки? Да. Раньше, если на компьютере имелся всего один
сетевой интерфейс, можно было с высокой долей вероятности утверждать, что он
называется +eth0+. Теперь же, прежде чем администратор начнет настраивать сеть,
он должен как минимум просмотреть список сетевых интерфейсов.
\subsection{Мне не~нравится ваша схема. Как ее отключить?}
У вас есть три варианта:
\begin{enumerate}
\item Вы можете полностью отключить новую схему, вернувшись к
классическим непредсказуемым именам. Для этого достаточно
заблокировать (замаскировать) соответствующий файл правил udev:
\begin{Verbatim}
ln -s /dev/null /etc/udev/rules.d/80-net-name-slot.rules
\end{Verbatim}
\item Вы можете вручную назначить интерфейсам наиболее понятные для вас
имена (например, +internet0+, +dmz0+, +lan0+). Для этого,
подготовьте свои собственные правила, указав в них нужные имена
при помощи параметра +NAME+, после чего сохраните их в файл с
более высоким приоритетом, чем правила по умолчанию, например,
+/etc/udev/rules.d/70-my-net-names.rules+. (Приоритет файлов
определяется на основании алфавитной сортировки их имен.)
\item Вы можете скорректировать правила, используемые по умолчанию,
например, задействовав схему именования интерфейсов по
MAC-адресам. Для, этого скопируйте файл правил в каталог +/etc+
\begin{Verbatim}
cp /usr/lib/udev/rules.d/80-net-name-slot.rules /etc/udev/rules.d/80-net-name-slot.rules
\end{Verbatim}
после чего измените его так, как считаете нужным.
\end{enumerate}
\subsection{Как именно работает новая схема?}
Подробности технической реализации описаны в блоке комментариев в
\href{http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-net_id.c#n20}%
{исходном коде net-id built-in}. Ознакомьтесь с ним, если у вас возникают
вопросы, касающиеся расшифровки новых имен\footnote{Прим. перев.: Далее
приводится перевод упомянутого блока комментариев. Последним коммитом,
затронувшим данный файл, на момент перевода является b92be от 24 марта
2013 г.}.
\begin{Verbatim}
Предсказуемые имена сетевых интерфейсов формируются на основании:
- индексов встроенных в материнскую плату устройств (по информации EFI/BIOS)
- индексов hotplug-слотов PCI-E (по информации EFI/BIOS)
- физического расположения точки подключения оборудования
- MAC-адресов
Первые два символа в имени определяют тип интерфейса:
en -- ethernet
wl -- wlan
ww -- wwan
Последующие символы определяеются используемой схемой:
o<index> -- для устройств, встроенных в материнскую плату
s<slot>[f<function>][d<dev_id>] -- для hotplug-слотов
x<MAC> -- при именовании по MAC-адресу
p<bus>s<slot>[f<function>][d<dev_id>] -- на основании физического
расположения PCI-устройства
p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
-- идентификационная цепочка для USB-устройств
Все многофункциональные (multi-function) PCI-устройства содержат в своем имени
номер функции [f<function>] (отсчитываются от нуля).
Для USB-устройства формируется полная цепочка номеров портов хабов, через
которые оно подключено. Если итоговая строка будет длиннее 15 символов, она
не экспортируется.
Стандартные значения config == 1 и interface == 0 опускаются.
Примеры:
Подключенная к PCI сетевая карта, которая идентифцироуется прошивкой
по индексу "1":
ID_NET_NAME_ONBOARD=eno1
ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1
Сетевая карта, включенная в hotplug PCI-слот, который идентифицируется
прошивкой:
/sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1
ID_NET_NAME_MAC=enx000000000466
ID_NET_NAME_PATH=enp5s0
ID_NET_NAME_SLOT=ens1
Multi-function PCI устройство с двумя портами:
/sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0
ID_NET_NAME_MAC=enx78e7d1ea46da
ID_NET_NAME_PATH=enp2s0f0
/sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.1/net/enp2s0f1
ID_NET_NAME_MAC=enx78e7d1ea46dc
ID_NET_NAME_PATH=enp2s0f1
Подключенная к PCI wlan-карта:
/sys/devices/pci0000:00/0000:00:1c.1/0000:03:00.0/net/wlp3s0
ID_NET_NAME_MAC=wlx0024d7e31130
ID_NET_NAME_PATH=wlp3s0
Встроенный USB 3G модем:
/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.6/net/wwp0s29u1u4i6
ID_NET_NAME_MAC=wwx028037ec0200
ID_NET_NAME_PATH=wwp0s29u1u4i6
Подключенный по USB Android-смартфон:
/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/net/enp0s29u1u2
ID_NET_NAME_MAC=enxd626b3450fb5
ID_NET_NAME_PATH=enp0s29u1u2
\end{Verbatim}
\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}