Работа с systemd-nspawn в Linux

Используемые термины: Docker, Podman, LXD, Linux.
В двух словах, systemd-nspawn — платформа контейнеризации на основе systemd. Ее очевидный плюс заключается в нативности (для любой системы на основе systemd требуется минимум установок и настроек). Из минусов отмечу более сложный процесс настройки и запуска контейнеров. Обо всем по порядку.
Установка systemd-nspawn
Создание образов
Для систем на базе Deb
Для систем на базе RPM
Работа с контейнерами
Создание
Запуск без init
Полноценный запуск
Настройка автозапуска
Примеры полезных команд
Установка
Для работы с systemd-nspawn нам нужно выполнить установку пакета systemd-container. В разных системах это делается, немного, по-разному.
а) На Linux Deb (Debian / Ubuntu / Astra Linux):
apt update
apt install systemd-container
б) На Linux RPM (Rocky Linux):
yum install systemd-container
Установка выполнена.
Подготовка образа
В отличие от других популярных аналогов (Docker, Podman, LXD) systemd-nspawn не имеет своего репозитория с образами, из которых мы можем легко получить контейнер. Поэтому нам необходимо создать свои собственные шаблоны.
Для systemd-nspawn образ — это система, установленная в каталог с помощью Debootstrap/Yumbootstrap. Рассмотрим процесс немного подробнее.
Инструменты Debootstrap и Yumbootstrap очень капризные. При работе с ними можно столкнуться с большим количеством разных ошибок. По возможности, я укажу решение некоторых из них.
Для минимизации проблем, мы можем выполнить установку системы в каталог на соответствующей платформе, например, если нам нужна Astra Linux, то запускаем debootstrap на Astra Linux. После готовый каталог копируем на машину, где хотим использовать systemd-nspawn.
Debootstrap (образы с deb-linux)
Для установки в каталог системы на основе Debian нам нужно использовать инструмент debootstrap. Его можно установить из базовых репозиториев. В зависимости от системы, на которой мы будем работать, наши действия будут отличаться.
а) Если работаем на Linux Deb (Debian / Ubuntu / Astra Linux):
apt install debootstrap
б) Если работаем на Linux RPM (Rocky Linux):
yum install epel-release
yum install debootstrap
После установки debootstrap можно приступать к установки системы.
Посмотрим содержимое каталога /usr/share/debootstrap/scripts:
ls /usr/share/debootstrap/scripts
В нем находится набор готовых скриптов для различных дистрибутивов Linux на основе Deb. Мы должны найти соответствующее название для системы, которую хотим установить в каталог.
Предположим, нам нужно работать с Ubuntu 22.04. Ее кодовое название Jammy. Проверяем, что такой скрипт есть:
ls /usr/share/debootstrap/scripts | grep jammy
Теперь выполним установку системы в каталог:
debootstrap jammy /var/lib/machines/image-ubuntu-jammy
* в нашем примере будет использоваться скрипт jammy для установки Ubuntu в каталог /var/lib/machines/image-ubuntu-jammy.
Мы можем получить ошибку Keyring file not available at /usr/share/keyrings/ubuntu-archive-keyring.gpg. Для решения проблемы нам нужно получить gpg-ключ и сохранить его в соответствующем каталоге. Выполняем команды:
mkdir -p /usr/share/keyrings
gpg --keyid-format long --keyserver hkp://keyserver.ubuntu.com --recv-keys 0x871920D1991BC93C
gpg --export 871920D1991BC93C > /usr/share/keyrings/ubuntu-archive-keyring.gpg
В итоге, мы должны увидеть:
...
I: Base system installed successfully.
Система установлена. При необходимости ее отредактировать, вводим:
chroot /var/lib/machines/image-ubuntu-jammy
Выполняем необходимые команды (например по инструкции С чего начать настройку любого UNIX сервера) и выходим из chroot:
exit
Готово — мы получили deb-образ, который может использоваться в качестве шаблона для контейнеров systemd-nspawn.
Yumbootstrap (образы с rpm-linux)
Утилита yumbootstrap позволит установить в каталог системы на базе RPM. Ее нет в репозиториях, но она идет в поставке с файлами для сборки установочных пакетов deb и rpm.
Перейдем в каталог для хранения исходников:
cd /usr/src
Скачаем yumbootstrap:
git clone https://github.com/dozzie/yumbootstrap.git
Если получим ошибку bash: git: command not found, выполним установку git:
apt install git
yum install git
* первая команда для систем deb, вторая — rpm.
Переходим в загруженный каталог yumbootstrap:
cd yumbootstrap
Далее команды для сборки и установки под разные типы дистрибутивов Linux будут отличаться.
а) Если работаем на Deb (Debian / Ubuntu / Astra Linux):
apt install devscripts debhelper python python-setuptools
dpkg-buildpackage -b -uc
dpkg -i ../yumbootstrap*.deb
б) Если работаем на RPM (Rocky Linux):
В процессе сборки мы можем столкнуться с рядом проблем. Рассмотрим все нюансы.
yum install rpm-build make python2 python2-setuptools
* обратите внимание, что мы устанавливаем именно python версии 2. Для 3-й версии выскакивает ошибка синтаксиса при попытке собрать пакет.
make srpm
Если мы получим ошибку error: attempt to use unversioned python, define %__python to /usr/bin/python2 or /usr/bin/python3 explicitly, открываем файл:
vi redhat/yumbootstrap.spec
Самой первой строкой добавляем:
%define __python /usr/bin/python2
...
rpmbuild --rebuild yumbootstrap-*.src.rpm
Мы можем получить ошибку python-setuptools is needed by yumbootstrap. В некоторых дистрибутивах на основе RPM нет пакета python-setuptools — либо python2-setuptools, либо python3-setuptools. Но так как сборщик требует, именно, python-setuptools, внесем правки в spec-файл:
vi redhat/yumbootstrap.spec
Редактируем значение для директивы BuildRequires:
BuildRequires: python2-setuptools
* в нашем примере теперь будет требоваться уже установленный нами пакет python2-setuptools.
После снова собираем исходники:
make srpm
Также на данном этапе мы можем столкнуться с ошибкой ERROR: ambiguous python shebang in ...: #!/usr/bin/python. Change it to python3 (or python2) explicitly. Открываем файл:
vi /usr/lib/rpm/redhat/brp-mangle-shebangs
Находим строки:
# Replace ambiguous python with python2
py_shebang=$(echo "$shebang" | sed -r -e 's@/usr/bin/python(\s|$)@/usr/bin/python2\1@')И после них добавляем блок:
if [ "$py_shebang" == "/usr/bin/python2" ]; then
shebang="/usr/bin/python2"
fi* насколько я смог разобраться, в некоторых системах неправильно определяется оригинальный путь до python2. В моем примере идет подмена неправильного /usr/bin/python на правильный /usr/bin/python2. Решение не самое изящное, но работает.
Наконец, можно устанавливать собранный пакет:
yum localinstall ~/rpmbuild/RPMS/noarch/yumbootstrap-*.rpm
После установки yumbootstrap можно установить систему в каталог.
Смотрим список дистрибутивов, для которых есть шаблоны yumbootstrap:
ls /etc/yumbootstrap/suites/
Предположим, будем работать с centos-7. Вводим команду:
yumbootstrap centos-7 /var/lib/machines/centos-7
* в нашем примере будет использоваться шаблон centos-7 для установки Ubuntu в каталог /var/lib/machines/centos-7.
Система установлена. При необходимости ее отредактировать, вводим:
chroot /var/lib/machines/centos-7
Выполняем необходимые команды (например по инструкции С чего начать настройку любого UNIX сервера) и выходим из chroot:
exit
Готово — мы получили rpm-образ, который может использоваться в качестве шаблона для контейнеров systemd-nspawn.
Создание контейнеров
Рассмотрим работу с контейнерами поэтапно:
- Сначала мы скопируем ранее созданный шаблон в папку контейнера.
- После запустим контейнер без init. В данном режиме мы сможем задать пароль учетной записи root.
- Полноценный запуск в интерактивном режиме. С целью убедиться, что контейнер работает.
- Настроим автозапуск контейнера.
Приступим.
Создание контейнера из образа
На самом деле, создать новый контейнер из образа, это скопировать ранее созданный шаблон в каталог /var/lib/machines.
Каталог не обязательно должен быть /var/lib/machines, но для systemd-nspawn предусмотрены шаблоны команд, которые удобнее использовать, если контейнеры находятся, именно, в этой папке.
Скопируем /var/lib/machines/image-ubuntu-jammy и создадим контейнер ubuntu-jammy:
cp -R /var/lib/machines/image-ubuntu-jammy /var/lib/machines/ubuntu-jammy
Идем дальше.
Запуск без init
Вводим команду типа:
systemd-nspawn -D <путь до папки контейнера>
Например:
systemd-nspawn -D /var/lib/machines/ubuntu-jammy
* в данном примере мы возьмем скопированную папку ubuntu-jammy и запустим из нее контейнер.
Введем команду:
passwd
И зададим новый пароль для пользователя root.
Выходим из контейнера, зажав Ctrl и нажав ]]] (три раза ]).
Запуск с init
Выполняем команду запуска контейнера с добавлением опции -b:
systemd-nspawn -D /var/lib/machines/ubuntu-jammy -b
Если мы увидим ошибку:
Failed to create /init.scope control group: Operation not permitted
Failed to allocate manager object: Operation not permitted
[!!!!!!] Failed to allocate manager object.
Exiting PID 1...Вводим команду:
grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
* она задает унифицированный режим работы cgroup (cgroups-v2).
После перезапускаем компьютер.
В итоге, мы должны увидеть приграшение к вводу логина и пароля. Вводим root и заданный на первом шаге пароль.
Мы должны попасть в командную строку.
Выходим из контейнера, зажав Ctrl и нажав ]]] (три раза ]).
Автозапуск контейнера
Для автостарта контейнеров предусмотрена команда machinectl.
Сначала разрешаем запуск для стандартного целевого юнита запуска контейнеров:
systemctl enable machines.target
Теперь можно разрешать автостарт контейнеров. Синтаксис следующий:
machinectl enable <имя контейнера в каталоге /var/lib/machines>
Для нашего примера команда будет такой:
machinectl enable ubuntu-jammy
И запускаем:
machinectl start ubuntu-jammy
Посмотреть список запущенных контейнеров можно командой:
machinectl list
Некоторые полезные команды
Ниже перечислим список команд для управления контейнерами.
Показать список контейнеров:
machinectl list
Статус работы контейнера:
machinectl status <имя контейнера>
Подключиться к контейнеру:
machinectl login <имя контейнера>
Запустить shell-оболочку контейнера (без пользовательского входа):
machinectl shell <имя контейнера>
Включить контейнер:
machinectl start <имя контейнера>
Перезагрузить контейнер:
machinectl reboot <имя контейнера>
Выключение контейнера:
machinectl poweroff <имя контейнера>