Compare commits

...

4 Commits
v8.3 ... v8.7

Author SHA1 Message Date
nnz1024
9581d6dc16 Version v8.7 (2012-01-05 04:56) [AUTO] 2017-08-17 23:05:38 +03:00
nnz1024
aaa2ec62eb Version v8.6 (2012-01-02 16:44) [AUTO] 2017-08-17 23:05:38 +03:00
nnz1024
56a4425e5a Version v8.5 (2012-01-02 01:38) [AUTO] 2017-08-17 23:05:38 +03:00
nnz1024
5c9a949351 Version v8.4 (2011-12-29 21:34) [AUTO] 2017-08-17 23:05:38 +03:00

575
s4a.tex
View File

@@ -43,9 +43,11 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
\author{Lennart P\"{o}ttering (автор)\thanks{Первоисточник (на английском
языке) опубликован на сайте автора: \url{http://0pointer.de/blog/projects}}\\%
Сергей Пташник (русский перевод)\thanks{Актуальная версия перевода
доступна на портале OpenNet: \url{http://wiki.opennet.ru/Systemd}}\\%
доступна на личной странице переводчика:
\url{http://www2.kangran.su/~nnz/pub/s4a/}}\\%
\small Данный документ доступен на условиях лицензии
\href{http://creativecommons.org/licenses/by-sa/3.0/legalcode}{CC-BY-SA}}
\href{http://creativecommons.org/licenses/by-sa/3.0/legalcode}{CC-BY-SA 3.0
Unported}}
\maketitle
\tableofcontents%\newpage
\sectiona{Предисловие автора}
@@ -58,7 +60,7 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
инициализации. Окончательный переход на systemd произошел лишь в Fedora~15.}.
Помимо Fedora, systemd также поддерживает и другие дистрибутивы, в частности,
\href{http://en.opensuse.org/SDB:Systemd}{OpenSUSE}\footnote{Прим. перев.:
сейчас systemd поддерживается практически во всех популярных дистрибутивах для
Сейчас systemd поддерживается практически во всех популярных дистрибутивах для
настольных систем.}. systemd предоставляет администраторам целый ряд новых
возможностей, значительно упрощающих процесс обслуживания системы. Эта статья
является первой в серии публикаций, планируемых в ближайшие месяцы. В каждой из
@@ -78,16 +80,16 @@ pdfauthor={Lennart Poettering, Sergey Ptashnick}}
systemd эти сообщения будут пробегать все быстрее и быстрее, вследствие чего,
читать их будет все труднее. К тому же, многие пользователи применяют
графические оболочки загрузки (например, Plymouth), полностью скрывающие эти
сообщения. Тем не~менее, информация, которую несут эти сообщения, была и
остается чрезвычайно важной~--- они показывают, успешно ли запустилась каждая
служба, или попытка ее запуска закончилась ошибкой (зеленое
сообщения. Тем не~менее, информация, которую они несут, была и остается
чрезвычайно важной~--- они показывают, успешно ли запустилась каждая служба, или
попытка ее запуска закончилась ошибкой (зеленое
\texttt{[~\textcolor{green}{OK}~]} или красное
\texttt{[~\textcolor{red}{FAILED}~]} соответственно). Итак, с ростом скорости
загрузки систем, возникает неприятная ситуация: информация о результатах
запуска служб бывает очень важна, а просматривать ее все тяжелее. systemd
предлагает выход из этой ситуации: он отслеживает и запоминает факты успешного
или неудачного запуска служб на этапе загрузки, а также сбои служб во время
работы. К таким случая относятся выходы с ненулевым кодом, ошибки
работы. К таким случаям относятся выходы с ненулевым кодом, ошибки
сегментирования и т.п. Введя +systemctl status+ в своей командной оболочке, вы
можете ознакомиться с состоянием всех служб, как <<родных>> (native) для
systemd, так и классических SysV/LSB служб, поддерживаемых в целях
@@ -208,7 +210,9 @@ ntpd.service - Network Time Service
\end{Verbatim}
systemd сообщает нам, что ntpd был запущен (с идентификатором процесса 953) и
аварийно завершил работу (с кодом выхода 255).
аварийно завершил работу (с кодом выхода 255)\footnote{Прим. перев.:
Впоследствии, про просьбам пользователей, считавших, что слово <<maintenance>>
недостаточно точно отражает ситуацию, оно было заменено на <<failed>>.}.
В последующих версиях systemd, мы планируем добавить возможность вызова в
таких ситуациях ABRT (Automated Bug Report Tool), но для этого необходима
@@ -242,14 +246,14 @@ CGI-программы, а демон cron~--- команды, предписа
к разработке демонов). Также, не~будем забывать, что процесс легко может
изменить свое имя посредством +PR_SETNAME+, или задав значение
+argv[0]+, что также усложняет процесс его опознания\footnote{Прим.
перев.: стоит отметить, что перечисленные ситуации могут возникнуть не~только
перев.: Стоит отметить, что перечисленные ситуации могут возникнуть не~только
вследствие ошибок в коде и/или конфигурации программ, но и в результате злого
умысла. Например, очень часто встречается ситуация, когда установленный на
взломанном сервере процесс-бэкдор маскируется под нормального демона, меняя
себе имя, скажем, на httpd.}.
systemd предлагает простой путь для решения обсуждаемой задачи. Запуская
очередной новый процесс, systemd помещает его в отдельную контрольную группу
новый процесс, systemd помещает его в отдельную контрольную группу
с соответствующим именем. Контрольные группы Linux предоставляют очень
удобный инструмент для иерархической структуризации процессов: когда
какой-либо процесс порождает потомка, этот потомок автоматически включается в
@@ -397,7 +401,7 @@ $ ps xawf -eo pid,user,cgroup,args
\end{landscape}
Обратите внимание на третий столбец, показывающий имя контрольной группы,
которое systemd присваивает каждому процессу. Например, процесс +udev+
в которую systemd поместил данный процесс. Например, процесс +udev+
находится в группе +name=systemd:/systemd-1/sysinit.service+. В эту группу
входят процессы, порожденные службой +sysinit.service+, которая запускается
на ранней стадии загрузки.
@@ -584,14 +588,14 @@ systemd именует группы в соответствии с назван
службам, но и процессов, запущенных в рамках пользовательских сеансов. В
последующих статьях мы обсудим этот вопрос более подробно.
\section{HOW-TO: преобразование SysV init-скрипта в systemd service-файл}
\section{Преобразование SysV init-скрипта в systemd service-файл}
\label{sec:convert}
Традиционно, службы Unix и Linux (демоны) запускаются через SysV init-скрипты.
Эти скрипты пишутся на языке Bourne Shell (+/bin/sh+), располагаются в
специальном каталоге (обычно +/etc/rc.d/init.d/+) и вызываются с одним из
стандартных параметров (+start+, +stop+, +reload+ и т.п.)~--- таким образом
указывается действие, которое необходимо прозвести над службой (запустить,
указывается действие, которое необходимо произвести над службой (запустить,
остановить, заставить перечитать конфигурацию). При запуске службы такой
скрипт, как правило, вызывает бинарник демона, который, в свою очередь,
форкается, порождая фоновый процесс (т.е. демонизируется). Заметим, что
@@ -621,7 +625,7 @@ service-файл будет работать в любом дистрибути
\href{http://0pointer.de/public/systemd-man/daemon.html}{страницу} официальной
документации.
Итак, приступим. В качестве пример возьмем init-скрипт демона ABRT (Automatic
Итак, приступим. В качестве примера возьмем init-скрипт демона ABRT (Automatic
Bug Reporting Tool, службы, занимающейся сбором crash dump'ов). Исходный
скрипт (в варианте для дистрибутива Fedora) можно загрузить
\href{http://0pointer.de/public/abrtd}{здесь}.
@@ -637,7 +641,7 @@ Bug Reporting Tool, службы, занимающейся сбором crash du
\item Строка описания службы: <<Daemon to detect crashing apps>>. Как
нетрудно заметить, комментарии в заголовке скрипта весьма
пространны и описывают не~сколько саму службу, сколько
скрипт, ее запускающий. service-файлы systemd также включают
скрипт, ее запускающий. service-файлы systemd тоже содержат
описание, но оно относится исключительно к службе, а не~к
service-файлу.
\item LSB-заголовок\footnote{LSB-заголовок~--- определенная в
@@ -663,9 +667,11 @@ Bug Reporting Tool, службы, занимающейся сбором crash du
socket-активацию, рассмотрены в статье
\href{http://0pointer.de/blog/projects/systemd.html}{Rethinking
PID~1}, в которой systemd был впервые представлен широкой
публике. Ее русский перевод можно прочитать здесь:
публике\footnote{Прим. перев.: Ее русский перевод (сделанный
совершенно независимо от данного документа, совсем другим
человеком) можно прочитать здесь:
\href{http://tux-the-penguin.blogspot.com/2010/09/systemd.html}{часть~1},
\href{http://tux-the-penguin.blogspot.com/2010/09/systemd-ii.html}{часть~2}.
\href{http://tux-the-penguin.blogspot.com/2010/09/systemd-ii.html}{часть~2}.}.
Возвращаясь к нашему примеру: в данном случае ценной
информацией о зависимостях является только строка
+Required-Start: $syslog+, сообщающая, что для работы
@@ -717,7 +723,7 @@ WantedBy=multi-user.target
поддерживают активацию через сокет. В системах, использующих такие
реализации, явное указание +After=syslog.target+ будет избыточным, так
как соответствующая функциональность поддерживается автоматически. Однако,
эту строчку стоит все-таки указать для обеспечения совместимости с системами,
эту строчку все-таки стоит указать для обеспечения совместимости с системами,
использующими устаревшие реализации демона системного лога.}. Эта информация,
как мы помним, была указана в LSB-заголовке исходного init-скрипта. В нашем
конфигурационном файле мы указываем зависимость от демона системного лога при
@@ -761,14 +767,14 @@ systemd считает службу запущенной с момента за
играет важную роль при выполнении команды +systemctl enable+, задавая, в каких
условиях должен активироваться устанавливаемый юнит. В нашем примере, служба
abrtd будет активироваться при переходе в состояние +multi-user.target+,
т.е., при каждой нормальной загрузке\footnote{Обратите внимание, что режим
графической загрузки в systemd (+graphical.target+, аналог runlevel 5
в SysV) является надстройкой над режимом многопользовательской консольной
загрузки (+multi-user.target+, аналог runlevel 3 в SysV). Таким
образом, все службы, запускаемые в режиме +multi-user.target+, будут
также запускаться и в режиме +graphical.target+.} (к <<ненормальным>>
можно отнести, например, загрузки в режиме +emergency.target+, который
является аналогом первого уровня исполнения в классической SysV).
т.е., при каждой нормальной\footnote{Прим. перев.: К <<ненормальным>> загрузкам
можно отнести, например, загрузки в режимах +emergency.target+ или
+rescue.target+ (является аналогом первого уровня исполнения в классической
SysV).} загрузке\footnote{Обратите внимание, что режим графической загрузки в
systemd (+graphical.target+, аналог runlevel 5 в SysV) является надстройкой над
режимом многопользовательской консольной загрузки (+multi-user.target+, аналог
runlevel 3 в SysV). Таким образом, все службы, запускаемые в режиме
+multi-user.target+, будут также запускаться и в режиме +graphical.target+.}.
Вот и все. Мы получили минимальный рабочий service-файл systemd. Чтобы
проверить его работоспособность, скопируем его в
@@ -802,37 +808,37 @@ WantedBy=multi-user.target
\end{Verbatim}
Чем же новый вариант отличается от предыдущего? Ну, прежде всего, мы уточнили
описание службы. Однако, ключевым изменением является замена значения +Type+ с +forking+
на +dbus+ и связанные с ней изменения: добавление имени службы в шине D-Bus
(директива +BusName+) и задание дополнительных аргументов abrtd <<+-d -s+>>. Но
зачем вообще нужна эта замена? Каков ее практический смысл? Чтобы ответить на
этот вопрос, мы снова возвращаемся к демонизации. В ходе этой операции процесс
дважды форкается и отключается от всех терминалов. Это очень удобно при запуске
демона через скрипт, но в случае использования таких продвинутых систем
инициализации, как systemd, подобное поведение не~дает никаких преимуществ, но
вызывает неоправданные задержки. Даже если мы оставим в стороне вопрос скорости
загрузки, останется такой важный аспект, как отслеживание состояния служб.
systemd решает и эту задачу, контролируя работу службы и при необходимости
реагируя на различные события. Например, при неожиданном падении основного
процесса службы, systemd должен зарегистрировать идентификатор и код выхода
процесса, также, в зависимости от настроек, он может попытаться перезапустить
службу, либо активировать какой-либо заранее заданный юнит. Операция
демонизации несколько затрудняет решение этих задач, так как обычно довольно
сложно найти связь демонизированного процесса с исходным (собственно, смысл
демонизации как раз и сводится к уничтожению этой связи) и, соответственно, для
systemd сложнее определить, какой из порожденных в рамках данной службы
процессов является основным. Чтобы упростить для него решение этой задачи, мы и
воспользовались типом запуска +dbus+. Он подходит для всех служб, которые в
конце процесса инициализации регистрируют свое имя на шине D-Bus\footnote{В
настоящее время практически все службы дистрибутива Fedora после запуска
регистрируется на шине D-Bus.}. ABRTd относится к ним. С новыми настройками,
systemd запустит процесс abrtd, который уже не~будет форкаться (согласно
указанным нами ключам <<+-d -s+>>), и в качестве момента окончания периода
запуска данной службы systemd будет рассматривать момент регистрации имени
+com.redhat.abrt+ на шине D-Bus. В этом случае основным для данной службы будет
считаться процесс, непосредственно порожденный systemd. Таким образом, systemd
располагает удобным методом для определения момента окончания запуска службы, а
также может легко отслеживать ее состояние.
описание службы. Однако, ключевым изменением является замена значения +Type+ с
+forking+ на +dbus+ и связанные с ней изменения: добавление имени службы в шине
D-Bus (директива +BusName+) и задание дополнительных аргументов abrtd
<<+-d -s+>>. Но зачем вообще нужна эта замена? Каков ее практический смысл?
Чтобы ответить на этот вопрос, мы снова возвращаемся к демонизации. В ходе
данной операции процесс дважды форкается и отключается от всех терминалов. Это
очень удобно при запуске демона через скрипт, но в случае использования таких
продвинутых систем инициализации, как systemd, подобное поведение не~дает
никаких преимуществ, но вызывает неоправданные задержки. Даже если мы оставим в
стороне вопрос скорости загрузки, останется такой важный аспект, как
отслеживание состояния служб. systemd решает и эту задачу, контролируя работу
службы и при необходимости реагируя на различные события. Например, при
неожиданном падении основного процесса службы, systemd должен зарегистрировать
идентификатор и код выхода процесса, также, в зависимости от настроек, он может
попытаться перезапустить службу, либо активировать какой-либо заранее заданный
юнит. Операция демонизации несколько затрудняет решение этих задач, так как
обычно довольно сложно найти связь демонизированного процесса с исходным
(собственно, смысл демонизации как раз и сводится к уничтожению этой связи) и,
соответственно, для systemd сложнее определить, какой из порожденных в рамках
данной службы процессов является основным. Чтобы упростить для него решение этой
задачи, мы и воспользовались типом запуска +dbus+. Он подходит для всех служб,
которые в конце процесса инициализации регистрируют свое имя на шине
D-Bus\footnote{В настоящее время практически все службы дистрибутива Fedora
после запуска регистрируется на шине D-Bus.}. ABRTd относится к ним. С новыми
настройками, systemd запустит процесс abrtd, который уже не~будет форкаться
(согласно указанным нами ключам <<+-d -s+>>), и в качестве момента окончания
периода запуска данной службы systemd будет рассматривать момент регистрации
имени +com.redhat.abrt+ на шине D-Bus. В этом случае основным для данной службы
будет считаться процесс, непосредственно порожденный systemd. Таким образом,
systemd располагает удобным методом для определения момента окончания запуска
службы, а также может легко отслеживать ее состояние.
Собственно, это все, что нужно было сделать. Мы получили простой
конфигурационный файл, в 10 строчках которого содержится больше полезной
@@ -848,7 +854,7 @@ systemd запустит процесс abrtd, который уже не~буд
для процессов, активно использующих CPU.
За более подробным описанием всех опций настройки, вы можете обратиться к
страницам рукводства
страницам руководства
\href{http://0pointer.de/public/systemd-man/systemd.unit.html}{systemd.unit},
\href{http://0pointer.de/public/systemd-man/systemd.service.html}{systemd.service},
\href{http://0pointer.de/public/systemd-man/systemd.exec.html}{systemd.exec}. Полный
@@ -867,7 +873,7 @@ service-файлы. Но, к счастью, <<проблемных>> скрип
Впрочем, этот метод не~вполне корректен, так как он действует не~только на
самого демона, но и на другие процессы с тем же именем. Иногда подобное
поведение может привести к неприятным последствиям. Более правильным будет
использование pid-файла: +kill $(cat /var/run/syslogd.pid)$+. Вот, вроде
использование pid-файла: \verb+kill $(cat /var/run/syslogd.pid)+. Вот, вроде
бы, и все, что вам нужно\ldots{} Или мы упускаем еще что-то?
Действительно, мы забываем одну простую вещь: существуют службы, такие, как
@@ -905,23 +911,25 @@ Apache, crond, atd, которые по роду служебной деятел
как бы она ни пыталась сбежать из-под нашего контроля при помощи двойного
форка или
\href{http://ru.wikipedia.org/wiki/Fork-%D0%B1%D0%BE%D0%BC%D0%B1%D0%B0}{форк-бомбардировки}%
\footnote{Прим. перев.: стоит особо отметить, что использование контрольных
\footnote{Прим. перев.: Стоит особо отметить, что использование контрольных
групп не~только упрощает процесс уничтожения форк-бомб, но и значительно
уменьшает ущерб от работающей форк-бомбы. Так как systemd автоматически
помещает каждую службу и каждый пользовательский сеанс в свою контрольную
группу по ресурсу процессорного времени, запуск форк-бомбы одним
пользователем или службой не~создаст значительных проблем с отзывчивостью
системы у других пользователей и служб. Таким образом, в качестве основной
угрозы форк-бомбардировки остаются лишь возможности исчерпания памяти и
идентификаторов процессов (PID).}.
уменьшает ущерб от работающей форк-бомбы. Так как systemd автоматически помещает
каждую службу и каждый пользовательский сеанс в свою контрольную группу по
ресурсу процессорного времени, запуск форк-бомбы одним пользователем или службой
не~создаст значительных проблем с отзывчивостью системы у других пользователей и
служб. Таким образом, в качестве основной угрозы форк-бомбардировки остаются
лишь возможности исчерпания памяти и идентификаторов процессов (PID). Впрочем, и
их тоже можно легко устранить: достаточно задать соответствующие лимиты в
конфигурационном файле службы (см.
\href{http://www.0pointer.de/public/systemd-man/systemd.exec.html}{systemd.exec(5)}).}.
В некоторый случах возникает необходимость отправить сигнал именно основному
В некоторых случаях возникает необходимость отправить сигнал именно основному
процессу службы. Например, используя +SIGHUP+, мы можем заставить демона
перечитать файлы конфигурации. Разумеется, передавать HUP вспомогательным процессам
в этом случае совершенно необязательно. Для решения подобной
задачи неплохо подойдет и классический метод с pid-файлом, однако у
systemd и на этот случай есть простое решение, избавляющее вас от
необходимости искать нужный файл:
перечитать файлы конфигурации. Разумеется, передавать HUP вспомогательным
процессам в этом случае совершенно необязательно. Для решения подобной задачи
неплохо подойдет и классический метод с pid-файлом, однако у systemd и на этот
случай есть простое решение, избавляющее вас от необходимости искать нужный
файл:
\begin{Verbatim}
# systemctl kill -s HUP --kill-who=main crond.service
@@ -1048,7 +1056,13 @@ systemd и на этот случай есть простое решение, и
\end{Verbatim}
Итак, блокировка сводится к созданию символьной ссылки
с именем соответствующей службы, указывающей на +/dev/null+.
с именем соответствующей службы, указывающей на
+/dev/null+\footnote{Прим. перев.: Впоследствии в программу
+systemctl+ была добавлена поддержка команд +mask+ и +unmask+,
упрощающих процесс блокирования и разблокирования юнитов.
Например, для блокирования службы +ntpd.service+ теперь
достаточно команды +systemctl mask ntpd.service+. Фактически
она сделает то же самое, что и приведенная выше команда +ln+.}.
После такой операции служба не~может быть запущена ни~вручную,
ни~автоматически. Символьная ссылка создается в каталоге
+/etc/systemd/system/+, а ее имя должно соответствовать имени
@@ -1077,7 +1091,7 @@ systemd и на этот случай есть простое решение, и
файлом из пакета).
Стоит отметить, что блокировка службы, как и ее отключение,
является перманентной мерой\footnote{Прим. перев.: подробно
является перманентной мерой\footnote{Прим. перев.: Подробно
описав принцип работы блокировки службы (юнита), автор забывает
привести практические примеры ситуаций, когда эта возможность
оказывается полезной.
@@ -1090,21 +1104,14 @@ systemd и на этот случай есть простое решение, и
ошибочно указано +systemctl restart+ (+service restart+), что
является прямым указанием на запуск службы, если она еще
не~запущена. Вследствие таких ошибок, отключенная служба может
<<ожить>> в самый неподходящий момент.
Другой пример~---
ограничение возможностей непривилегированного пользователя при
управлении системой. Даже если такому пользователю делегировано
(через механизмы sudo или PolicyKit) право на использование
+systemctl+, это еще не~означает, что он сможет запустить
заблокированную службу~--- права на выполнение +rm+ (удаление
блокирующей символьной ссылки) выдаются отдельно.}.
<<ожить>> в самый неподходящий момент.}.
\end{itemize}
После прочтения изложенного выше, у читателя может возникнуть вопрос: как
отменить произведенные изменения? Что ж, ничего сложного тут нет:
+systemctl start+ отменяет действия +systemctl stop+, +systemctl enable+
отменяет действие +systemctl disable+, а +rm+ отменяет действие +ln+.
отменяет действие +systemctl disable+, а +rm+ отменяет действие
+ln+.
\section{Смена корня}
@@ -1124,7 +1131,7 @@ systemd и на этот случай есть простое решение, и
вся иерархия файловых систем гостевой ОС монтируется или
создается в каталоге системы-хоста, и при запуске оболочки (или
любого другого приложения) внутри этой иерархии, в качестве
корня используется этот каталог. Система, которую <<видят>>
корня используется данный каталог. Система, которую <<видят>>
такие программы, может сильно отличаться от ОС хоста. Например,
это может быть другой дистрибутив, или даже другая аппаратная
архитектура (запуск i386-гостя на x86\_64-хосте). Гостевая ОС
@@ -1144,8 +1151,8 @@ systemd и на этот случай есть простое решение, и
init, многие параметры среды выполнения (в частности, лимиты на системные
ресурсы, переменные окружения, и т.п.) наследуются от оболочки, из которой был
запущен init-скрипт. При использовании systemd ситуация меняется радикально:
пользователь просто уведомляет init-демона о необходимости запустить ту или иную
службу, и тот запускает демона в чистом, созданном <<с нуля>> и тщательно
пользователь просто уведомляет процесс init о необходимости запустить ту или
иную службу, и тот запускает демона в чистом, созданном <<с нуля>> и тщательно
настроенном окружении, параметры которого никак не~зависят от настроек среды, из
которой была отдана команда. Такой подход полностью отменяет традиционный метод
запуска демонов в chroot-окружениях: теперь демон порождается процессом init
@@ -1173,19 +1180,19 @@ chroot в самой программе. Прежде всего, коррект
chroot-окружения требует глубокого понимания принципов работы программы.
Например, нужно точно знать, какие каталоги нужно bind-монтировать из основной
системы, чтобы обеспечить все необходимые для работы программы каналы связи. С
учетом вышесказанного, эффективная chroot-защита обеспечивается в том случае,
когда она реализована в коде самого демона. Именно разработчик лучше других
знает (\emph{обязан} знать), как правильно сконфигурировать chroot-окружение, и
какой минимальный набор файлов, каталогов и файловых систем необходим внутри
него для нормальной работы демона. Уже сейчас существуют демоны, имеющие
встроенную поддержку chroot. К сожалению, в системе Fedora, установленной с
параметрами по умолчанию, таких демонов всего два:
учетом вышесказанного, эффективная chroot-защита обеспечивается только в том
случае, когда она реализована в коде самого демона. Именно разработчик лучше
других знает (\emph{обязан} знать), как правильно сконфигурировать
chroot-окружение, и какой минимальный набор файлов, каталогов и файловых систем
необходим внутри него для нормальной работы демона. Уже сейчас существуют
демоны, имеющие встроенную поддержку chroot. К сожалению, в системе Fedora,
установленной с параметрами по умолчанию, таких демонов всего два:
\href{http://avahi.org/}{Avahi} и RealtimeKit. Оба они написаны одним очень
хитрым человеком ;-) (Вы можете собственноручно убедиться в этом, выполнив
команду +ls -l /proc/*/root+.)
Возвращаясь к теме нашего обсуждения: разумеется, systemd позволяет помещать
выбранных демонов в chroot, и управлять ими точно так же, как и другими.
выбранных демонов в chroot, и управлять ими точно так же, как и остальными.
Достаточно лишь указать параметр +RootDirectory=+ в соответствующем
service-файле. Например:
\begin{Verbatim}
@@ -1252,7 +1259,7 @@ InaccessibleDirectories=/home
руководства}.)
Фактически, FSNS по множеству параметров превосходят +chroot()+. Скорее всего,
Avahi и ReltimeKit в ближайшем будущем перейдут с +chroot()+ к использованию
Avahi и RealtimeKit в ближайшем будущем перейдут от +chroot()+ к использованию
FSNS.
Итак, мы рассмотрели вопросы использования chroot для обеспечения безопасности.
@@ -1267,7 +1274,7 @@ chroot-окружения, по сути, весьма примитивны: о
отличается лишь содержимое файловой системы, все остальное у них общее.
Например, если вы обновляете дистрибутив, установленный в chroot-окружении, и
пост-установочный скрипт пакета отправляет +SIGTERM+ процессу init для его
перезапуска\footnote{Прим. перев.: во избежание путаницы отметим, что перезапуск
перезапуска\footnote{Прим. перев.: Во избежание путаницы отметим, что перезапуск
процесса init (PID~1) <<на лету>> при получении +SIGTERM+ поддерживается только
в systemd, в классическом SysV init такой возможности нет.}, на него среагирует
именно хост-система! Кроме того, хост и chroot'нутая система будут иметь общую
@@ -1288,7 +1295,7 @@ systemd имеет целый ряд возможностей, полезных
Таким образом, пакетные скрипты смогут включить/отключить запуск <<своих>> служб
при загрузке (или в других ситуациях), однако команды наподобие
+systemctl restart+ (обычно выполняется при обновлении пакета) не~дадут никакого
эффекта внутри chroot-окружения\footnote{Прим. перев.: автор забывает отметить
эффекта внутри chroot-окружения\footnote{Прим. перев.: Автор забывает отметить
не~вполне очевидный момент: такое поведение +systemctl+ проявляется только в
<<мертвых>> окружениях, т.е. в тех, где не~запущен процесс init, и
соответственно отсутствуют управляющие сокеты в +/run/systemd+. Такая ситуация
@@ -1304,7 +1311,7 @@ debootstrap/febootstrap. В этом случае возможности +system
+chroot(1)+~--- она не~только подменяет корневой каталог, но и создает отдельные
пространства имен для дерева файловых систем (FSNS) и для идентификаторов
процессов (PID NS), предоставляя легковесную реализацию системного
контейнера\footnote{Прим. перев.: используемые в +systemd-nspawn+ механизмы
контейнера\footnote{Прим. перев.: Используемые в +systemd-nspawn+ механизмы
ядра Linux, такие, как FS NS и PID NS, также лежат в основе
\href{http://lxc.sourceforge.net/}{LXC}, системы контейнерной изоляции для
Linux, которая позиционируется как современная альтернатива классическому
@@ -1323,7 +1330,7 @@ Linux, которая позиционируется как современна
ему в штатном режиме. Также, в отличие от +chroot(1)+, внутри окружения
будут автоматически смонтированы +/proc+ и +/sys+.
Следующий пример иллюстрирует возможность запустить Debian в на Fedora-хосте
Следующий пример иллюстрирует возможность запустить Debian на Fedora-хосте
всего тремя командами:
\begin{Verbatim}
# yum install debootstrap
@@ -1342,22 +1349,25 @@ Linux, которая позиционируется как современна
После быстрой загрузки вы получите приглашение оболочки, запущенной внутри
полноценной ОС, функционирующей в контейнере. Изнутри контейнера невозможно
увидеть процессы, которые находятся вне его. Контейнер сможет пользоваться сетью
хоста, однако не~имеет возможности изменить ее настройки (это может привести к
серии ошибок в процессе загрузки гостевой ОС, но ни~одна из этих ошибок
не~должна быть критической). Контейнер получает доступ к +/sys+ и +/proc/sys+,
однако, во избежание вмешательства контейнера в конфигурацию ядра и аппаратного
обеспечения хоста, эти каталоги будут смонтированы только для чтения. Обратите
внимание, что эта защита блокирует лишь \emph{случайные}, \emph{непредвиденные}
попытки изменения параметров. При необходимости, процесс внутри контейнера,
обладающий достаточными полномочиями, сможет перемонтировать эти файловые
системы в режиме чтения-записи.
хоста\footnote{Прим. перев.: Впоследствии в +systemd-nspawn+ была добавлена
опция +--private-network+, позволяющая изолировать систему внутри контейнера от
сети хоста: такая система будет видеть только свой собственный интерфейс
обратной петли.}, однако не~имеет возможности изменить ее настройки (это может
привести к серии ошибок в процессе загрузки гостевой ОС, но ни~одна из этих
ошибок не~должна быть критической). Контейнер получает доступ к +/sys+ и
+/proc/sys+, однако, во избежание вмешательства контейнера в конфигурацию ядра и
аппаратного обеспечения хоста, эти каталоги будут смонтированы только для
чтения. Обратите внимание, что эта защита блокирует лишь \emph{случайные},
\emph{непредвиденные} попытки изменения параметров. При необходимости, процесс
внутри контейнера, обладающий достаточными полномочиями, сможет перемонтировать
эти файловые системы в режиме чтения-записи.
Итак, что же такого хорошего в +systemd-nspawn+?
\begin{enumerate}
\item Использовать эту утилиту очень просто. Вам даже не~нужно вручную монтировать
внутри окружения +/proc+ и +/sys+~--- она сделает это за вас, а
ядро автоматически отмонтирует их, когда последний процесс
контейнера завершится.
\item Использовать эту утилиту очень просто. Вам даже не~нужно вручную
монтировать внутри окружения +/proc+ и +/sys+~--- она сделает
это за вас, а ядро автоматически отмонтирует их, когда последний
процесс контейнера завершится.
\item Обеспечивается надежная изоляция, предотвращающая случайные
изменения параметров ОС хоста изнутри контейнера.
\item Теперь вы можете загрузить внутри контейнера полноценную ОС, а
@@ -1481,60 +1491,59 @@ $ systemd-analyze blame
Рассмотрим повнимательнее первого осквернителя нашей загрузки: службу
+udev-settle.service+. Почему ей требуется так много времени для запуска, и что
мы можем с этим сделать? Эта служба выполняет очень простую задачу: она ожидает,
пока udev завершит опрос устройств, после чего завершается. Опрос же устройств
может занимать довольно много времени. Например, в нашем случае опрос устройств
занимает более 6~секунд из-за подключенного к компьютеру 3G-модема, в котором
отсутствует SIM-карта. Этот модем очень долго отвечает на запросы udev. Опрос
устройств является частью схемы, обеспечивающей работу ModemManager'а и
мы можем с этим сделать? Данная служба выполняет очень простую функцию: она
ожидает, пока udev завершит опрос устройств, после чего завершается. Опрос же
устройств может занимать довольно много времени. Например, в нашем случае опрос
устройств длится более 6~секунд из-за подключенного к компьютеру 3G-модема, в
котором отсутствует SIM-карта. Этот модем очень долго отвечает на запросы udev.
Опрос устройств является частью схемы, обеспечивающей работу ModemManager'а и
позволяющей NetworkManager'у упростить для вас настройку 3G. Казалось бы,
очевидно, что виновником задержки является именно ModemManager, так как опрос
устройств для него занимает слишком много времени. Но такое обвинение будет
заведомо ошибочным. Дело в том, что опрос устройств очень часто оказывается довольно
длительной процедурой. Медленный опрос 3G-устройств для ModemManager является
частным случаем, отражающим это общее правило. Хорошая система опроса устройств
обязательно должна учитывать тот факт, что операция опроса любого из устройств
может затянуться надолго. Истинной причиной наших проблем является необходимость
ожидать завершения опроса устройств, т.е., наличие службы
заведомо ошибочным. Дело в том, что опрос устройств очень часто оказывается
довольно длительной процедурой. Медленный опрос 3G-устройств для ModemManager
является частным случаем, отражающим это общее правило. Хорошая система опроса
устройств обязательно должна учитывать тот факт, что операция опроса любого из
устройств может затянуться надолго. Истинной причиной наших проблем является
необходимость ожидать завершения опроса, т.е., наличие службы
+udev-settle.service+ как обязательной части нашего процесса загрузки.
Но почему эта служба вообще присутствует в нашем процессе загрузки? На самом
деле, мы можем прекрасно обойтись и без нее. Она нужна лишь как часть
используемой в Fedora схемы инициализации устройств хранения, а именно,
набора скриптов, выполняющих настройку LVM, RAID и multipath-устройств. На
сегодняшний день, реализация этих систем не~поддерживает собственного механизма
поиска и опроса устройств, и поэтому их запуск должен производиться только после
того, как эта работа уже проделана~--- тогда они могут просто последовательно
используемой в Fedora схемы инициализации устройств хранения, а именно, набора
скриптов, выполняющих настройку LVM, RAID и multipath-устройств. На сегодняшний
день, реализация этих систем не~поддерживает собственного механизма поиска и
опроса устройств, и поэтому их запуск должен производиться только после того,
как эта работа уже проделана~--- тогда они могут просто последовательно
перебирать все диски. Однако, такой подход противоречит одному из
фундаментальных требований к современным компьютерам:
возможности подключать и отключать оборудование в любой момент, как при
выключенном компьютере, так и при включенном. Для некоторых
технологий невозможно точно определить момент завершения формирования списка устройств
(например, это характерно для USB и iSCSI), и поэтому процесс опроса
таких устройств обязательно должен включать некоторую фиксированную задержку,
гарантирующую, что все подключенные устройства успеют отозваться. С точки зрения
скорости загрузки это, безусловно, негативный эффект: соответствующие скрипты
заставляют нас ожидать завершения опроса устройств, хотя большинство этих
устройств не~являются необходимыми на данной стадии загрузки. В частности, в
рассматриваемой нами системе LVM, RAID и multipath вообще
не~используются!\footnote{Наиболее правильным решением в данном случае будет
ожидание событий подключения устройств (реализованное через libudev или
аналогичную технологию) с соответствующей обработкой каждого такого события~---
подобный подход позволит нам продолжить загрузку, как только будут готовы все
устройства, необходимые для ее продолжения. Для того, чтобы загрузка была
быстрой, мы должны ожидать завершения инициализации только тех устройств, которые
\emph{действительно} необходимы для ее продолжения на данной стадии. Ожидать
остальные устройства в данном случае смысла нет. Кроме того, стоит отметить, что
в числе программ, не~приспособленных для работы с динамически меняющимся
оборудованием и построенных в предположении о неизменности списка устройств,
кроме служб хранения, есть и другие подсистемы. Например, в нашем случае работа
initrd занимает так много времени главным образом из-за того, что для запуска
Plymouth необходимо дождаться завершения инициализации всех устройств
видеовывода. По неизвестной причине (во всяком случае, неизвестной для меня)
подгрузка модулей для моих видеокарт Intel занимает довольно продолжительное
время, что приводит к беспричинной задержке процесса загрузки. (Нет, я протестую
не~против опроса устройств, но против необходимости ожидать его завершения, чтобы
продолжить загрузку.)}
фундаментальных требований к современным компьютерам: возможности подключать и
отключать оборудование в любой момент, как при выключенном компьютере, так и при
включенном. Для некоторых технологий невозможно точно определить момент
завершения формирования списка устройств (например, это характерно для USB и
iSCSI), и поэтому процесс опроса таких устройств обязательно должен включать
некоторую фиксированную задержку, гарантирующую, что все подключенные устройства
успеют отозваться. С точки зрения скорости загрузки это, безусловно, негативный
эффект: соответствующие скрипты заставляют нас ожидать завершения опроса
устройств, хотя большинство этих устройств не~являются необходимыми на данной
стадии загрузки. В частности, в рассматриваемой нами системе LVM, RAID и
multipath вообще не~используются!\footnote{Наиболее правильным решением в данном
случае будет ожидание событий подключения устройств (реализованное через libudev
или аналогичную технологию) с соответствующей обработкой каждого такого
события~--- подобный подход позволит нам продолжить загрузку, как только будут
готовы все устройства, необходимые для ее продолжения. Для того, чтобы загрузка
была быстрой, мы должны ожидать завершения инициализации только тех устройств,
которые \emph{действительно} необходимы для ее продолжения на данной стадии.
Ожидать остальные устройства в данном случае смысла нет. Кроме того, стоит
отметить, что в числе программ, не~приспособленных для работы с динамически
меняющимся оборудованием и построенных в предположении о неизменности списка
устройств, кроме служб хранения, есть и другие подсистемы. Например, в нашем
случае работа initrd занимает так много времени главным образом из-за того, что
для запуска Plymouth необходимо дождаться завершения инициализации всех
устройств видеовывода. По неизвестной причине (во всяком случае, неизвестной для
меня) подгрузка модулей для моих видеокарт Intel занимает довольно
продолжительное время, что приводит к беспричинной задержке процесса загрузки.
(Нет, я возражаю не~против опроса устройств как такового, но против
необходимости ожидать его завершения, чтобы продолжить загрузку.)}
С учетом вышесказанного, мы можем спокойно исключить +udev-settle.service+ из
нашего процесса загрузки, так как мы не~используем ни~LVM, ни~RAID,
@@ -1549,8 +1558,8 @@ Plymouth необходимо дождаться завершения иници
После перезагрузки мы видим, что загрузка стала на одну секунду быстрее. Но
почему выигрыш оказался таким маленьким? Из-за второго осквернителя нашей
загрузки~--- cryptsetup. На рассматриваемой нами системе зашифрован раздел
+/home+. Специально для тестирования я записал пароль в файл, чтобы исключить
влияние скорости ручного набора пароля. К сожалению, для подключения
+/home+. Специально для нашего тестирования я записал пароль в файл, чтобы
исключить влияние скорости ручного набора пароля. К сожалению, для подключения
шифрованного раздела cryptsetup требует более пяти секунд. Будем ленивы, и
вместо того, чтобы исправлять ошибку в cryptsetup\footnote{На самом деле, я
действительно пытался исправить эту ошибку. Задержки в cryptsetup, по
@@ -1567,7 +1576,7 @@ cryptsetup, что снижение этого времени с 1 секунд
может продолжить загрузку и приступить к запуску служб. Но первое обращение
к +/home+ (в отличие, например, от +/var+), происходит на поздней стадии
процесса загрузки (когда пользователь входит в систему). Следовательно, нам
нужно сделать так, чтобы этот каталога автоматически монтировался при загрузке,
нужно сделать так, чтобы этот каталог автоматически монтировался при загрузке,
но процесс загрузки не~ожидал завершения работы +cryptsetup+, +fsck+ и +mount+
для этого раздела. Как же сделать точку монтирования доступной, не~ожидая, пока
завершится процесс монтирования? Этого можно достичь, воспользовавшись
@@ -1620,7 +1629,7 @@ $ eog plot.svg
именно происходило во время загрузки, и отображает соответствующие графики
использования процессора и ввода-вывода. +systemd-analyze plot+ оперирует более
высокоуровневой информацией: сколько времени затратила та или иная служба во
время запуска, и какие службы были вынуждены ее ожидать. Используя оба эти
время запуска, и какие службы были вынуждены ее ожидать. Используя оба этих
инструмента, вы значительно упростите себе поиск причин замедления вашей
загрузки.
@@ -1737,7 +1746,7 @@ LVM, RAID и multipath). Если они вам не~нужны, вы легко
конфигурация общесистемной локали.
\item
\hreftt{http://0pointer.de/public/systemd-man/modules-load.d.html}{/etc/modules-load.d/*.conf}:
каталог\footnote{Прим. перев.: для описания этого и трех
каталог\footnote{Прим. перев.: Для описания этого и трех
последующих каталогов автор пользуется термином <<drop-in
directory>>. Этот термин означает каталог, в который можно
поместить множество независимых файлов настроек, и при чтении
@@ -1791,8 +1800,8 @@ LVM, RAID и multipath). Если они вам не~нужны, вы легко
наличия уникального и постоянного идентификатора компьютера.
\item
\hreftt{http://0pointer.de/public/systemd-man/machine-info.html}{/etc/machine-info}:
новый конфигурационный файл, хранящий информации о полном имени
(описательном) хоста (например, <<Компьютер Леннарта>>) и
новый конфигурационный файл, хранящий информации о полном
(описательном) имени хоста (например, <<Компьютер Леннарта>>) и
значке, которым он будет обозначаться в графических оболочках,
работающих с сетью (раньше этот значок мог определяться,
например, файлом +/etc/favicon.png+). Данный конфигурационный
@@ -1809,19 +1818,18 @@ LVM, RAID и multipath). Если они вам не~нужны, вы легко
момент эти файлы полностью поддерживаются только дистрибутивами, основанными на
systemd, но уже сейчас в их число входят практически все ключевые дистрибутивы,
\href{http://www.ubuntu.com/}{за исключением
одного}\footnote{Прим. перев.: в конце 2010~года энтузиаст Andrew Edmunds
одного}\footnote{Прим. перев.: В конце 2010~года энтузиаст Andrew Edmunds
\href{http://cgit.freedesktop.org/systemd/commit/?id=858dae181bb5461201ac1c04732d3ef4c67a0256}{добавил}
в systemd базовую поддержку Ubuntu и
\href{https://wiki.ubuntu.com/systemd}{подготовил} соответствующие пакеты,
однако его инициатива не~встретила поддержки среди менеджеров Canonical. На
момент написания этих строк (май 2011 года) проект остается заброшенным уже пять
месяцев (с середины декабря 2010~г.).}. В этом есть что-то от <<пролемы курицы и
яйца>>: стандарт становится начинает работать как стандарт только тогда, когда
ему начинают следовать. В будущем мы намерены аккуратно форсировать процесс
перехода на новые конфигурационные файлы: поддержка старых файлов будет удалена
из systemd. Разумеется, этот процесс будет идти медленно, шаг за шагом. Но
конечной его целью является переход всех дистрибутивов на единый набор базовых
конфигурационных файлов.
момент написания этих строк проект остается заброшенным с декабря 2010~г.}. В
этом есть что-то от <<проблемы курицы и яйца>>: стандарт становится настоящим
стандартом только тогда, когда ему начинают следовать. В будущем мы намерены
аккуратно форсировать процесс перехода на новые конфигурационные файлы:
поддержка старых файлов будет удалена из systemd. Разумеется, этот процесс будет
идти медленно, шаг за шагом. Но конечной его целью является переход всех
дистрибутивов на единый набор базовых конфигурационных файлов.
Многие из этих файлов используются не~только программами для настройки системы,
но и апстримными проектами. Например, мы предлагаем проектам Mono, Java, WINE и
@@ -1847,7 +1855,7 @@ shell-скриптов, выполняющих тривиальные задач
выбрали то, что должно устроить большинство людей. Форматы конфигурационных
файлов максимально просты, и их можно легко читать и записывать даже из
shell-скриптов. Да, +/etc/bikeshed.conf+ могло бы быть неплохим именем
для файла конфигурации!\footnote{Прим. перев.: здесь автор намекает на
для файла конфигурации!\footnote{Прим. перев.: Здесь автор намекает на
\href{http://en.wikipedia.org/wiki/Parkinson's_Law_of_Triviality}{Паркинсоновский
Закон Тривиальности}, который гласит, что самые жаркие споры возникают вокруг
наиболее простых вопросов. В частности, в качестве примера Паркинсон приводит
@@ -1887,7 +1895,7 @@ shed)~--- если первое из этих решений принимает
зоопарк их различных реализаций в разных дистрибутивах.
Назначение этих каталогов определено весьма расплывчато. Абсолютное большинство
находящихся в них файлов являются включаемыми\footnote{Прим. перев.: здесь автор
находящихся в них файлов являются включаемыми\footnote{Прим. перев.: Здесь автор
использует термин sourcable, происходящий от bash'овской директивы +source+,
обеспечивающей включение в скрипт кода из внешнего файла. В классическом POSIX
shell это соответствует оператору-точке <<+.+>>. В отличие от прямого запуска
@@ -1927,7 +1935,7 @@ init-скрипта, или даже сами не~являющиеся скри
\item Режим остановки для демона.
\item Общесистемные настройки, например, системная локаль, часовой пояс,
параметры клавиатуры для консоли.
\item Избыточные информация о системных настройках, например, указание,
\item Избыточная информация о системных настройках, например, указание,
установлены ли аппаратные часы по Гринвичу или по местному
времени.
\item Списки правил брандмауэра, не~являются скриптами (!).
@@ -2056,11 +2064,13 @@ systemd?
Одно из немногих исключений из этого правила~--- к сожалению, в
настоящее время не~поддерживается автоматическая загрузка
модулей на основании информации о возможностях процессора,
однако это будет исправлено в ближайшем будущем. В случае, если
нужный вам модуль ядра все же не~может быть подгружен
автоматически, все равно существует гораздо более удобные методы
указать его принудительную подгрузку~--- например, создав
соответствующий файл в каталоге
однако это будет исправлено в ближайшем будущем\footnote{Прим.
перев.: Патчи от разработчиков systemd уже приняты в ядро, и
соответствующая функция поддерживается Linux, начиная с версии
3.3.}. В случае, если нужный вам модуль ядра все же не~может
быть подгружен автоматически, все равно существует гораздо более
удобные методы указать его принудительную подгрузку~---
например, путем создания соответствующего файла в каталоге
\hreftt{http://0pointer.de/public/systemd-man/modules-load.d.html}{/etc/modules-load.d/}
(стандартный метод настройки принудительной подгрузки модулей).
\item И наконец, хотелось бы отметить, что каталог +/etc+ определен как
@@ -2091,16 +2101,16 @@ systemd?
\item Найдите для них более подходящее место. Например, в случае с
некоторыми общесистемными настройками (такими, как локаль или
часовой пояс), мы надеемся аккуратно подтолкнуть дистрибутивы в
правильно направлении (см. предыдущий эпизод).
правильно направлении (см. предыдущую главу).
\item Добавьте их поддержку в штатную систему настройки демона через
собственные файлы конфигурации. К счастью, большинство служб,
работающих в Linux, являются свободным программным обеспечением,
так что сделать это довольно просто.
\end{itemize}
Существует лишь одна причина поддерживать эти файлы еще некоторое
Существует лишь одна причина поддерживать файлы +/etc/sysconfig+ еще некоторое
время: необходимо обеспечить совместимость при обновлении. Тем не~менее, как
минимум в новых пакетах, от этих файлов лучше отказаться.
минимум в новых пакетах, от таких файлов лучше отказаться.
Если требование совместимости критично, вы можете задействовать эти
конфигурационные файлы даже в том случае, если настраиваете службы через
@@ -2143,12 +2153,19 @@ systemd?
\emph{foobar}~--- строка, идентифицирующая службу (проще говоря, ее имя), а
+.service+~--- суффикс, присутствующий в именах всех файлов конфигурации служб.
Сами эти файлы могут находиться в каталогах +/etc/systemd/systemd+ и
+/lib/systemd/system+ (а также, возможно, и в других). Для служб, работающих в
нескольких экземплярах, эта схема становится немного сложнее:
\emph{foobar}+@+\emph{quux}+.service+, где \emph{foobar}~--- имя службы,
общее для всех экземпляров, а \emph{quux}~--- идентификатор конкретного
экземпляра. Например, +serial-gett@ttyS2.service+~--- это служба getty для
COM-порта, запущенная на +ttyS2+.
+/lib/systemd/system+ (а также, возможно, и в других\footnote{Прим. перев.:
Перечень каталогов, в которых выполняется поиск общесистемных юнит-файлов,
приведен на странице руководства
\href{http://www.0pointer.de/public/systemd-man/systemd.html}{systemd(1)}
(раздел <<System unit directories>>). Указанные выше каталоги
+/etc/systemd/systemd+ и +/lib/systemd/system+ соответствуют значениям по
умолчанию для упомянутых там переменных pkg-config +systemdsystemconfdir+ и
+systemdsystemunitdir+ соответственно.}). Для служб, работающих в нескольких
экземплярах, эта схема становится немного сложнее:
\emph{foobar}+@+\emph{quux}+.service+, где \emph{foobar}~--- имя службы, общее
для всех экземпляров, а \emph{quux}~--- идентификатор конкретного экземпляра.
Например, +serial-gett@ttyS2.service+~--- это служба getty для COM-порта,
запущенная на +ttyS2+.
При необходимости, экземпляры служб можно легко создать динамически. Скажем, вы
можете, безо всяких дополнительных настроек, запустить новый экземпляр getty на
@@ -2190,7 +2207,7 @@ RestartSec=0
нем используются спецификаторы \%I и \%i. В момент загрузки юнита, systemd
заменяет эти спецификаторы на идентификатор экземпляра службы. В нашем случае,
при обращении к экземпляру +serial-getty@ttyUSB0.service+, они заменяются на
<<+ttyUSB0+>>. Результат этой замены можно проверить, например, запросив
<<+ttyUSB0+>>. Результат такой замены можно проверить, например, запросив
состояние для этой службы:
\begin{Verbatim}[commandchars=\\\{\}]
$ systemctl status serial-getty@ttyUSB0.service
@@ -2234,21 +2251,21 @@ systemd и заложен предварительный поиск файла
В приведенном выше файле, в некоторых местах используется спецификатор +%I+, а
в других~--- +%i+. У вас может возникнуть закономерный вопрос~--- чем они
отличаются? +%i+ всегда точно соответствует идентификатору экземпляра, в то
время, как +%I+ соответствует экранированной (escaped) версии этого
время, как +%I+ соответствует неэкранированной (unescaped) версии этого
идентификатора. Когда идентификатор не~содержит спецсимволов (например,
+ttyUSB0+). Но имена устройств, например, содержат слеши (<</>>), которые
не~могут присутствовать в имени юнита (и в имени файла на Unix). Поэтому, перед
использованием такого имени в качестве идентификатора устройства, оно должно
быть экранировано~--- <</>> заменяются на <<->>, а большинство других
специальных символов (включая <<->>) заменяются последовательностями вида
+\xAB+, где AB~--- ASCII-код символа, записанный в шестнадцатеричной системе
счисления\footnote{Согласен, этот алгоритм дает на выходе не~очень читабельный
результат. Но этим грешат практически все алгоритмы экранирования. В данном
случае, были использован механизм экранирования из udev, с одним изменением. В
конце концов, нам нужно было выбрать что-то. Если вы собираетесь комментировать
наш алгоритм экранирования~--- пожалуйста, оставьте свой адрес, чтобы я
мог приехать к вам и раскрасить ваш сарай для велосипедов в синий с желтыми
полосами. Спасибо!}. Например, чтобы обратиться
+ttyUSB0+), результат в обоих случаях одинаковый. Но имена устройств, например,
содержат слеши (<</>>), которые не~могут присутствовать в имени юнита (и в имени
файла на Unix). Поэтому, перед использованием такого имени в качестве
идентификатора устройства, оно должно быть экранировано~--- <</>> заменяются на
<<->>, а большинство других специальных символов (включая <<->>) заменяются
последовательностями вида +\xAB+, где AB~--- ASCII-код символа, записанный в
шестнадцатеричной системе счисления\footnote{Согласен, этот алгоритм дает на
выходе не~очень читабельный результат. Но этим грешат практически все алгоритмы
экранирования. В данном случае, был использован механизм экранирования из udev,
с одним изменением. В конце концов, нам нужно было выбрать что-то. Если вы
собираетесь комментировать наш алгоритм экранирования~--- пожалуйста, оставьте
свой адрес, чтобы я мог приехать к вам и раскрасить ваш сарай для велосипедов в
синий с желтыми полосами. Спасибо!}. Например, чтобы обратиться к
последовательному USB-порту по его адресу на шине, нам нужно использовать имя
наподобие +serial/by-path/pci-0000:00:1d.0-usb-0:1.4:1.1-port0+. Экранированная
версия этого имени~---
@@ -2260,7 +2277,12 @@ systemd и заложен предварительный поиск файла
спецификатор используется для ссылки на юнит +dev-%i.device+, соответствующий
одноименному устройству). В то время как +%I+ удобно использовать в командной
строке (+ExecStart+) и для формирования читабельных строк описания. Рассмотрим
работу этих принципов на примере нашего юнит-файла:
работу этих принципов на примере нашего юнит-файла\footnote{Прим. перев.: как
видно из нижеприведенного примера, в командной строке +systemctl+ необходимо
указывать экранированное имя юнита, что создает определенные трудности даже при
наличии в оболочке <<умного>> автодополнения. Однако, на момент написания этих
строк, в TODO проекта содержится пункт о добавлении в systemctl поддержки
неэкранированных имен юнитов.}:
\begin{landscape}
\begin{Verbatim}[fontsize=\small,commandchars=|\{\}]
# systemctl start 'serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.service'
@@ -2275,7 +2297,7 @@ serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.
\end{landscape}
Как видите, в качестве идентификатора экземпляра используется экранированная
версия, в то время как в строке описания и в командной строке +getty+
используется неэкранированная версия. Как и предполагалось.
фигурирует неэкранированный вариант, как и предполагалось.
(Небольшое замечание: помимо +%i+ и +%I+, существует еще несколько
спецификаторов, и большинство из них доступно и в обычных файлах конфигурации
@@ -2290,32 +2312,32 @@ serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0.
преобразовать SysV init-скрипт в юнит-файл systemd. В этой главе мы рассмотрим,
как провести аналогичное преобразование для служб inetd.
Начнем с небольшого экскурса в историю вопроса. По давно устоявшейся традиции,
Начнем с небольшого экскурса в историю вопроса. Уже многие годы
inetd считается одной из базовых служб Unix-систем. Работая как суперсервер, он
слушает сетевые сокеты от имени различных служб, и активирует соответствующие
службы при поступлении на эти сокеты входящих соединений. Таким образом, он
обеспечивает механизм активации по запросу (on-demand activation). Подобный
подход избавляет от необходимости держать постоянно работающими все серверные
процессы, что позволяет поддерживать множество служб даже на системах с очень
ограниченными ресурсами. На протяжении многих лет, дистрибутивы Linux
поставляются с различными реализациями inetd. Наиболее популярные из них~--- BSD
ограниченными ресурсами. В дистрибутивах Linux можно встретить
несколько различных реализаций inetd. Наиболее популярные из них~--- BSD
inetd и xinetd. Хотя inetd во многих дистрибутивах до сих пор устанавливается по
умолчанию, сейчас уже он редко используется для запуска сетевых служб~--- теперь
умолчанию, сейчас он уже редко используется для запуска сетевых служб~--- теперь
большинство из них запускаются автономно при загрузке системы (основной
аргумент в пользу такой схемы~--- она позволяет обеспечить более высокую
производительность служб).
Одной из ключевых возможностей systemd (а также launchd от Apple) является
сокет-активация~--- тот самый механизм, давным-давно реализованный inetd,
сокет-активация~--- тот же самый механизм, давным-давно реализованный inetd,
однако в данном случае ключевые цели немного другие. Сокет-активация в стиле
systemd прежде всего ориентирована на локальные сокеты (+AF_UNIX+), хотя
поддерживаются также и сетевые сокеты (+AF_INET+). И более важное отличие~---
сокет-активация в systemd обеспечивает не~только экономию системных ресурсов,
но также и эффективную параллелизацию работы (так как она
позволяет запускать клиентов и серверы одновременно, непосредственно после
создания сокета), упрощение процесса конфигурации (отпадает необходимость явно
указывать зависимости между службами) и увеличение надежности (служебный или
экстренный, в случае падения, перезапуск службы не~приводит к недоступности
но также и эффективную параллелизацию работы (так как она позволяет запускать
клиентские и серверные процессы одновременно, непосредственно после создания
сокета), упрощение процесса конфигурации (отпадает необходимость явно указывать
зависимости между службами) и увеличение надежности (перезапуск службы,
служебный или экстренный~--- в случае падения~--- не~приводит к недоступности
сокета). Тем не~менее, systemd ничуть не~хуже inetd может запускать службы в
ответ на входящие сетевые соединения.
@@ -2328,7 +2350,7 @@ systemd прежде всего ориентирована на локальны
Однако, интерфейс, традиционно используемый в inetd, еще проще. Он позволяет
передавать запускаемой службе только один сокет, который формируется из потоков
STDIN и STDOUT запущенного процесса. Поддержка этого механизма также
присутствует в systemd~--- для обеспечения совместимости с множеством служб
присутствует в systemd~--- для обеспечения совместимости со множеством служб,
поддерживающих сокет-активацию только в стиле inetd.
Прежде, чем мы перейдем к примерам, рассмотрим три различных схемы, использующих
@@ -2339,7 +2361,7 @@ STDIN и STDOUT запущенного процесса. Поддержка эт
загрузки, и единственный экземпляр службы тут же начинает
обслуживать все поступающие запросы. Такая схема подходит для
часто используемых системных служб~--- очевидно, что такие
службы лучше запускать как можно раньше, и по вомзожности
службы лучше запускать как можно раньше, и по возможности
параллельно. В качестве примера можно привести D-Bus и Syslog.
\item \textbf{Сокет-активация для одиночных служб:} сокеты создаются на
ранних стадиях загрузки, и единственный экземпляр службы
@@ -2456,28 +2478,121 @@ ExecStart=-/usr/sbin/sshd -i
StandardInput=socket
\end{Verbatim}
Большинство представленных здесь опции, как и раньше, понятны интуитивно. Особое
внимание стоит обратить лишь на +StandardInput=socket+, которая, собственно, и
включает для данной службы режим совместимости с inetd-активацией. Опция
+StandardInput=+ позволяет указать, куда будет подключен поток STDIN процесса
данной службы (подробности см.
Большинство представленных здесь опций, как всегда, понятны интуитивно. Особое
внимание стоит обратить лишь на строчку +StandardInput=socket+, которая,
собственно, и включает для данной службы режим совместимости с inetd-активацией.
Опция +StandardInput=+ позволяет указать, куда будет подключен поток STDIN
процесса данной службы (подробности см.
\href{http://0pointer.de/public/systemd-man/systemd.exec.html}{на странице
руководства}). Задав для нее значение +socket+, мы обеспечиваем подключение
этого потока к сокету соединения, как того и требует механизм inetd-активации.
Заметим, что явно указывать опцию +StandardInput=+ в данном случае
Заметим, что явно указывать опцию +StandardOutput=+ в данном случае
необязательно~--- она автоматически устанавливается в то же значение, что и
+StandardInput+, если явно не~указано что-то другое. Кроме того, можно отметить
наличие <<+-+>> перед именем бинарного файла sshd. Таким образом мы указываем
systemd игнорировать код выхода процесса sshd. По умолчанию, systemd сохраняет
коды выхода для всех экземпляров службы, завершившихся с ошибкой (сбросить эту
информацию можно командой +systemctl reset-failed+). SSH
периодически откалывает подобные номера, и мы разрешаем systemd
довольно часто завершается с ненулевым кодом выхода, и мы разрешаем systemd
не~регистрировать подобные <<ошибки>>.
Служба +sshd@.service+ предназначена для работы в виде независимых экземпляров
(такие службы мы рассматривали в предыдущей главе~\ref{sec:instances}). Для
каждого входящего соединения systemd будет создавать свой экземпляр этой службы,
и идентификатор экземпляра формируется на основе реквизитов соединения.
причем идентификатор экземпляра формируется на основе реквизитов соединения.
Быть может, вы спросите: почему для настройки inetd-службы в systemd требуется
два файла конфигурации, а не~один? Отвечаем: чтобы избежать излишнего
усложнения, мы обеспечиваем максимально прозрачную связь между работающими
юнитами и соответствующими им юнит-файлами. Такой подход позволяет независимо
оперировать юнитом сокета и юнитами соответствующих служб при формировании графа
зависимостей и при управлении юнитами. В частности, вы можете остановить
(удалить) сокет, не~затрагивая уже работающие экземпляры соответствующей службы,
или остановить любой из этих экземпляров, не~трогая другие экземпляры и сам
сокет.
Посмотрим, как наш пример будет работать. После того, как мы поместим оба
предложенных выше файла в каталог +/etc/systemd/system+, мы сможем включить
сокет (то есть, обеспечить его активацию при каждой нормальной загрузке) и
запустить его (то есть активировать в текущем сеансе работы):
\begin{Verbatim}
# systemctl enable sshd.socket
ln -s '/etc/systemd/system/sshd.socket' '/etc/systemd/system/sockets.target.wants/sshd.socket'
# systemctl start sshd.socket
# systemctl status sshd.socket
sshd.socket - SSH Socket for Per-Connection Servers
Loaded: loaded (/etc/systemd/system/sshd.socket; enabled)
Active: active (listening) since Mon, 26 Sep 2011 20:24:31 +0200; 14s ago
Accepted: 0; Connected: 0
CGroup: name=systemd:/system/sshd.socket
\end{Verbatim}
Итак, наш сокет уже прослушивается, но входящих соединений на него пока
не~поступало (счетчик +Accepted:+ показывает количество принятых соединений
с момента создания сокета, счетчик +Connected:+~--- количество активных
соединений на текущий момент).
Подключимся к нашему серверу с двух разных хостов, и посмотрим на список служб:
\begin{Verbatim}[fontsize=\small]
$ systemctl --full | grep ssh
sshd@172.31.0.52:22-172.31.0.4:47779.service loaded active running SSH Per-Connection Server
sshd@172.31.0.52:22-172.31.0.54:52985.service loaded active running SSH Per-Connection Server
sshd.socket loaded active listening SSH Socket for Per-Connection Servers
\end{Verbatim}
Как и следовало ожидать, работают два экземпляра нашей службы, по одному на
соединение, и их в названиях указаны IP-адреса и TCP-порты источника и
получателя. (Заметим, что в случае с локальными сокетами типа +AF_UNIX+ там были
бы указаны идентификаторы процесса и пользователя, соответствующие подключенному
клиенту.) Таким образом, мы можем независимо выслеживать и убивать отдельные
экземпляры sshd (например, если нам нужно прервать конкретный удаленный сеанс):
\begin{Verbatim}
# systemctl kill sshd@172.31.0.52:22-172.31.0.4:47779.service
\end{Verbatim}
Вот, пожалуй, и все, что вам нужно знать о портировании inetd-служб в systemd и
дальнейшем их использовании.
Применительно к SSH, в большинстве случаев схема с inetd-активацией позволяет
сэкономить системные ресурсы и поэтому оказывается более эффективным решением,
чем использование обычного service-файла sshd, обеспечивающего запуск одиночной
службы без использования сокет-активации (поставляется в составе пакета и может
быть включен при необходимости). В ближайшее время я собираюсь направить
соответствующий запрос относительно нашего пакета SSH в багтрекер Fedora.
В завершение нашей дискуссии, сравним возможности xinetd и systemd, и выясним,
может ли systemd полностью заменить xinetd, или нет. Вкратце: systemd
поддерживает далеко не~все возможности xinetd и поэтому отнюдь не~является его
полноценной заменой на все случаи жизни. В частности, если вы загляните в
\href{http://linux.die.net/man/5/xinetd.conf}{список параметров конфигурации}
xinetd, вы заметите, что далеко не~все эти опции доступны в systemd. Например, в
systemd нет и никогда не~будет встроенных служб +echo+, +time+, +daytime+,
+discard+ и т.д. Кроме того, systemd не~поддерживает TCPMUX и RPC. Впрочем,
большинство этих опций уже не~актуальны в наше время. Подавляющее большинство
inetd-служб не~используют эти опции (в частности, ни~одна из имеющихся в Fedora
xinetd-служб не~требует поддержки перечисленных опций). Стоит отметить, что
xinetd имеет некоторые интересные возможности, отсутствующие в systemd,
например, списки контроля доступа для IP-адресов (IP ACL). Однако, большинство
администраторов, скорее всего, согласятся, что настройка барндмауэра является
более эффективным решением подобных задач, а для ценителей устаревших технологий
systemd предлагает поддержку tcpwrap. С другой стороны, systemd тоже
предоставляет ряд возможностей, отсутствующих в xinetd, в частности,
индивидуальный контроль над каждым экземпляром службы (см. выше), и куда более
полный
\href{http://0pointer.de/public/systemd-man/systemd.exec.html}{список настроек}
для контроля окружения, в котором запускаются экземпляры. Я надеюсь, что
возможностей systemd должно быть достаточно для решения большинства задач, а в
тех редких случаях, когда вам потребуются специфические опции xinetd~--- ничто
не~мешает вам запустить его в дополнение к systemd. Таким образом, уже сейчас в
большинстве случаев xinetd можно выкинуть из числа обязательных системных
компонентов. Можно сказать, что systemd не~просто возвращает функциональность
классического юниксового inetd, но еще и восстанавливает ее ключевую
роль в Linux-системах.
Теперь, вооруженные этими знаниями, вы можете портировать свои службы с inetd на
systemd. Но, конечно, будет лучше, если этим займутся разработчики из апстрима
приложения, или сопровождающие вашего дистрибутива.
\end{document}