diff --git a/s4a.tex b/s4a.tex index 7f11262..509b242 100644 --- a/s4a.tex +++ b/s4a.tex @@ -2312,6 +2312,7 @@ serial-getty@serial-by\x2dpath-pci\x2d0000:00:1d.0\x2dusb\x2d0:1.4:1.1\x2dport0. пояснениями.) \section{Службы с активацией в стиле inetd} +\label{sec:inetd} В одной из предыдущих глав (гл.~\ref{sec:convert}) я рассказывал, как можно преобразовать SysV init-скрипт в юнит-файл systemd. В этой главе мы рассмотрим, @@ -4314,11 +4315,11 @@ $ gdbus call --system --dest org.freedesktop.systemd1 --object-path /org/freedes те, которые пока не~поддерживают, ее \href{http://0pointer.de/blog/projects/socket-activation.html}{не~так уж} и \href{http://0pointer.de/blog/projects/socket-activation2.html}{сложно} -добавить). Используя встроенный в systemd механизм управления -\hyperref[sec:instances]{экземплярами служб}, вы сможете подготовить +добавить). Реализованный в systemd механизм управления +\hyperref[sec:instances]{экземплярами служб} позволяет подготовить универсальные шаблоны конфигурации служб, и в соответствии с ними для каждого сайта будет запускаться свой экземпляр службы. Кроме того, не~стоит забывать, -что systemd предоставляет вам \hyperref[sec:security]{богатый арсенал} +что systemd предоставляет \hyperref[sec:security]{богатый арсенал} механизмов обеспечения безопасности и разграничения доступа, который позволит изолировать клиентские сайты друг от друга (например, службы каждого клиента будут видеть только его собственный домашний каталог, в то время как каталоги @@ -4333,6 +4334,211 @@ $ gdbus call --system --dest org.freedesktop.systemd1 --object-path /org/freedes сайтов на базе Drupal. (Стоит упомянуть, что заслуга ее внедрения в Pantheon принадлежит Дэвиду Штрауссу. Дэвид, ты крут!) +\subsection{Сокет-активация контейнеров} + +Все вышеописанные технологии уже реализованы в ранее вышедших версиях systemd. +Если ваш дистрибутив поддерживает systemd, вы можете воспользоваться этими +механизмами прямо сейчас. А теперь сделаем шаг вперед: начиная с +systemd 197 (и, соответственно, с Fedora~19), мы добавили поддержку +сокет-активации \emph{виртуальных контейнеров} с полноценными ОС внутри. И +я считаю это действительно важным достижением. + +Сокет-активация контейнеров работает следующим образом. Изначально, systemd +хост-системы слушает порты от имени контейнера (например, порт SSH, порт +веб-сервера и порт сервера СУБД). При поступлении на любой из этих портов +входящего запроса, systemd запускает контейнер и передает ему все его сокеты. +Внутри контейнера, еще один systemd (init гостевой системы) принимает эти +сокеты, после чего вступает в работу вышеописанная схема обычной сокет-активации +служб. При этом, SSH-сервер, веб-сервер и СУБД-сервер <<видят>> только ОС +контейнера~--- хотя они были активированы сокетами, созданными на хосте! Для +клиента все эти тонкости скрыты. Таким образом, мы получаем виртуальный +контейнер с собственной ОС, активируемый при поступлении входящего сетевого +соединения, причем совершенно прозрачно для клиента\footnote{Кстати говоря, +\href{https://plus.google.com/115547683951727699051/posts/cVrLAJ8HYaP}{это еще +один аргумент} в пользу важности быстрой загрузки для серверных систем.}. + +Внутри контейнера функционирует полноценная ОС, причем ее дистрибутив +не~обязательно совпадает с дистрибутивом хост-системы. Например, вы можете +установить на хосте Fedora, и запускать на нем несколько контейнеров с Debian. +Контейнеры имеют собственные init-системы, собственные SSH-серверы, собственные +списки процессов и т.д., но при этом пользуются некоторыми механизмами ОС хоста +(например, управлением памятью). + +К настоящему моменту сокет-активация контейнеров поддерживается лишь встроенным +в systemd простейшим контейнерным менеджером~--- +\hyperref[sec:chroots]{systemd-nspawn}. Мы надеемся, что соответствующая +возможность вскоре появится и в +\href{http://libvirt.org/drvlxc.html}{libvirt-lxc}. А пока рассмотрим +использование этого механизма на примере systemd-nspawn. + +Начнем с установки файлов ОС контейнера в выбранный каталог. Детальное +рассмотрение этого вопроса выходит далеко за рамки нашего обсуждения, и +при этом детально рассмотрено во многих статьях и руководствах. Поэтому +ограничусь лишь несколькими наиболее важными замечаниями. В частности, команда +для установки Fedora будет выглядеть следующим образом: +\begin{Verbatim} +$ yum --releasever=19 --nogpg --installroot=/srv/mycontainer/ --disablerepo='*' \ +> --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal +\end{Verbatim} +а для Debian~--- +\begin{Verbatim} +$ debootstrap --arch=amd64 unstable /srv/mycontainer/ +\end{Verbatim} +Также см. последние абзацы страницы руководства +\href{http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html}{systemd-nspawn(1)}. +Стоит отметить, что в настоящее время реализация системного аудита в Linux +не~поддерживает виртуальные контейнеры, и ее включение в ядре хоста вызовет +множество ошибок при попытке запустить контейнер. Отключить ее можно добавлением ++audit=0+ в строку параметров загрузки ядра хоста. + +Разумеется, внутри контейнера должен должен быть установлен systemd версии +не~ниже 197. Установить его и произвести другие необходимые настройки можно при +помощи того же \hyperref[sec:chroots]{systemd-nspawn} (пока что в режиме аналога ++chroot+, т.е. без параметра +-b+). После этого можно попробовать загрузить ОС +контейнера, используя systemd-nspawn уже с параметром +-b+. + +Итак, ваш контейнер нормально загружается и работает. Подготовим для него +service-файл, при помощи которого systemd сможет запускать и останавливать +виртуальное окружение. Для этого, создадим на хост системе файл ++/etc/systemd/system/mycontainer.service+ со следующим содержанием: +\begin{Verbatim} +[Unit] +Description=My little container + +[Service] +ExecStart=/usr/bin/systemd-nspawn -jbD /srv/mycontainer 3 +KillMode=process +\end{Verbatim} + +Теперь мы можем запускать и останавливать эту службу командами +systemctl start+ +и +stop+. Однако, пока что мы не~можем войти в эту систему\footnote{Прим. +перев.: Ручной запуск на хосте соответствующей команды +systemd-nspawn -b+ во +время работы такой службы просто создаст \emph{еще один контейнер}. Хотя +корневой каталог у них один и тот же, пространства имен (например, списки +процессов) у каждого будут свои. Впрочем, данная задача может быть решена +утилитой +nsenter+, которая должна войти в следующий релиз util-linux +(предположительно, 2.23).}. Настроим на контейнере SSH-сервер, причем таким +образом, что подключение к его порту активировало весь контейнер, а затем +активировало сервер, работающий внутри. Начнем с того, что прикажем хосту +слушать порт SSH для контейнера. Для этого создадим на хосте файл ++/etc/systemd/system/mycontainer.socket+: +\begin{Verbatim} +[Unit] +Description=The SSH socket of my little container + +[Socket] +ListenStream=23 +\end{Verbatim} + +После того, как мы запустим этот юнит командой +systemctl start+, systemd будет +слушать 23-й TCP-порт хоста. В примере выбран именной 23-й, потому что 22-й +скорее всего окажется занят SSH-сервером самого хоста. nspawn виртуализует +списки процессов и точек монтирования, но не~сетевые стеки, поэтому порты хоста +и гостей не~должны конфликтовать\footnote{Прим. перев.: Ограниченные возможности +виртуализации сети в +systemd-nspawn+ значительно затрудняют использование +описываемой технологии. Ее практическое применение будет иметь смысл после +реализации соответствующей поддержки в lxc-libvirt, либо расширения возможностей +nspawn. Впрочем, опытные администраторы легко могут найти обходные пути, +например: присваивание хосту дополнительного IP-адреса (безо всякой +виртуализации, командой +ip addr add+) и привязка слушающих сокетов к конкретным +адресам (в параметре +ListenStream=+ сокет-файлов или в директиве ++ListenAddress+ файла +sshd_config+).}. + +Пока что systemd, работающий внутри контейнера, не~знает, что делать с тем +сокетами, которые ему передает systemd хоста. Если вы попробуете подключиться к +порту 23, контейнер запустится, но сетевое соединение немедленно будет закрыто, +так как этому сокету не~соответствует пока никакой сервер. Давайте это исправим! + +Настройка сокет-активации службы SSH была детально рассмотрена +\hyperref[sec:inetd]{в одной из предыдущих статей}, поэтому ограничусь +приведением содержимого необходимых для этого конфигурационных файлов. Файл +настроек для сокета +(+/srv/mycontainer/etc/systemd/system/sshd.socket+)\footnote{Прим. перев.: +Обратите внимание на разницу между файлами конфигурации сокетов на хосте и +в контейнере. Внутри контейнера используются параметры +Accept=yes+ и ++StandardInput=socket+, которые не~задействованы на хосте. Это обусловлено тем +фактом, что внутри контейнера сокет-активация производится в стиле inetd (служба +получает только один сокет, причем замкнутый на ее потоки STDIN и STDOUT), в то +время как на стороне хоста используется родной стиль активации systemd, при +котором запущенному процессу (в данном случае +systemd-nspawn+) просто +передаются открытые файловые дескрипторы (+fd+) всех сокетов. Одно из достоинств +такого подхода~--- возможность передавать сразу несколько сокетов, что позволяет +активировать внутри контейнера несколько серверов.}: +\begin{Verbatim} +[Unit] +Description=SSH Socket for Per-Connection Servers + +[Socket] +ListenStream=23 +Accept=yes +\end{Verbatim} + +Соответствующий ему файл конфигурации службы \\ +(+/srv/mycontainer/etc/systemd/system/sshd@.service+): +\begin{Verbatim} +[Unit] +Description=SSH Per-Connection Server for %I + +[Service] +ExecStart=-/usr/sbin/sshd -i +StandardInput=socket +\end{Verbatim} + +После чего, добавим наш сокет в зависимости к цели +sockets.target+, чтобы +systemd создавал его автоматически при загрузке контейнера\footnote{Прим. +перев.: Возиться вручную с командой +ln+ здесь совершенно необязательно. Можно +просто добавить в файл +sshd.socket+ секцию +[Install]+, содержащую параметр ++WantedBy=sockets.target+, после чего добавление правильного симлинка будет +выполняться куда более очевидной командой ++systemctl --root=/srv/mycontainer enable sshd.socket+.}: +\begin{Verbatim} +$ chroot /srv/mycontainer ln -s /etc/systemd/system/sshd.socket \ +> /etc/systemd/system/sockets.target.wants/ +\end{Verbatim} + +Собственно, все. После того, как мы запустим на хосте юнит +mycontainer.socket+, +systemd начнет прослушивать TCP-порт 23. При подключении к этому порту, systemd +запустит контейнер и передаст сокет ему. Внутри контейнера свой systemd, в +соответствии с файлом +sshd.socket+, примет этот сокет и запустит для нашего +соединения экземпляр +sshd@.service+, что позволит нам залогиниться в контейнер +по SSH. + +Если нам нужно запуститьунтри контейнера другие службы с сокет-активацией, мы +можем добавить в +mycontainer.socket+ дополнительные сокеты. Все они будут +прослушиваться, обращение к любому из них приведет к активации контейнера, и все +они будут переданы контейнеру при его активации. Внутри контейнера они будут +обработаны соответствии с настройками имеющихся там сокет-юнитов. Те сокеты, для +которых соответствующих юнитов не~найдется, будут закрыты, а те сокеты, которые +будут настроены для прослушивания внутри контейнера, но не~получены от хоста, +будут активированы и доступны изнутри контейнера (а если это сетевые или +файловые unix-сокеты, то и извне). + +Итак, давайте отступим чуть назад и полюбуемся на результаты наших трудов. Что +мы получили в итоге? Возможность настраивать на одном хосте множество +контейнеров с полноценными ОС внутри, причем контейнеры запускаются только по +запросу, что позволяет снизить потребление системных ресурсов и, соответственно, +увеличить количество контейнеров (по сравнению с принудительной их активацией +при загрузке хоста). + +Разумеется, описанный подход работает только для контейнерной виртуализации, и +неприменим к полной, т.е. может быть использован только с технологиями наподобие +libvirt-lxc или nspawn, но не~c qemu/kvm или xen. + +Если вы будете администрировать несколько таких контейнеров, вас наверняка +порадует одна из возможностей journal: при запуске на хосте утилиты +journalctl+ +с ключом +-m+, она автоматически обнаружит журналы гостевых контейнеров и +объединит их вывод с выводом журнала хоста\footnote{Прим. перев.: Этот трюк +работает благодаря опции +-j+, которую мы передаем программе +systemd-nspawn+ +при запуске контейнера (см. файл юнита выше). В соответствии с ней, в каталоге ++/var/log/journal+ хоста создается символьная ссылку на соответствующий каталог +гостя. При этом, так как сообщения от гостей имеют другие machine ID, journalctl +хоста не~выводит их, если явно не~указать +-m+. Подробности см. на страницах +руководства +\href{http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html}{systemd-nspawn(1)} +и +\href{http://www.freedesktop.org/software/systemd/man/journalctl.html}{journalctl(1)}.}. +Ловко, не~правда ли? + \end{document} vim:ft=tex:tw=80:spell:spelllang=ru