Systemd и контейнеры: знакомство с systemd-nspawn

    PR-1505-3

    Контейнеризация сегодня — одна из самых актуальныx тем. Количество публикаций о таких популярных инструментах, как LXC или Docker, исчисляется тысячами, если не десятками тысяч.
    В этой статье бы хотели мы обсудить ещё одно решение, о котором публикаций на русском языке пока что мало. Речь идёт о systemd-nspawn — инструменте для создания изолированных сред, который является одним из компонентов systemd. А закрепление systemd в качестве стандарта в мире Linux — уже свершившийся факт. В свете этого факта есть все основания полагать, что в ближайшее время сфера применения systemd-nspawn существенно расширится, и познакомиться с этим инструментом поближе стоит уже сейчас.


    Systemd-nspawn: общая информация



    Название systemd-nspawn представляет собой сокращение от namespaces spawn. Уже из этого названия следует, что systemd-nspawn управляет только изоляцией процессов, но при этом не может изолировать ресурсы (однако это можно сделать средствами самого systemd, о чём ещё пойдёт речь ниже).

    С помощью systemd-nspawn можно создать полностью изолированое окружение, в котором автоматически будут смонтированы псевдофайловые системы /proc и /sys, а также созданы изолированный loopback-интерфейс и отдельное пространство имён для идентификаторов процессов (PID), внутри которого можно запускать ОС, основанную на ядре Linux.

    Cпециального репозитория образов, как в Docker, в systemd-nspawn не существует. Для создания и загрузки образов можно использовать любые сторонние инструменты. Поддерживаются форматы tar, raw, qcow2 и dkr (dkr — это образы для Docker; в документации к systemd-nspawn об этом в явной форме нигде не написано, а её авторы старательно избегают самого слова Docker). Работа с образами осуществляется на базе файловой системы BTRFS.

    Запускаем в контейнере Debian



    Знакомство с systemd-nspawn начнём с простого, но показательного практического примера. На сервере под управлением OC Fedora мы создадим изолированное окружение, в котором будет запущен ОС Debian. Все примеры команд ниже приводятся для Fedora 22 c systemd 219-й версии; в других дистрибутивах Linux и других версиях systemd команды могут отличаться.

    Начнём с установки необходимых зависимостей:

    sudo dnf install debootstrap bridge-utils
    


    Затем создадим файловую систему для будущего контейнера:

    sudo debootstrap --arch=amd64 jessie /var/lib/machines/container1/
    


    По завершении всех подготовительных работ можно приступать к запуску контейнера:

    sudo systemd-nspawn -D /var/lib/machines/container1/ --machine test_container 
    


    На консоли появится приглашение гостевой операционной системы:

    root@test_container
    


    Установим для неё root-пароль:

    passwd
    Enter new UNIX password: 
    Retype new UNIX password: 
    passwd: password updated successfully
    


    Выйдем из контейнера, нажав комбинацию клавиш Ctrl+]]], а затем выполним следующую команду:

    sudo systemd-nspawn -D /var/lib/machines/container1/ --machine test_container  -b
    


    В ней присутствует флаг -b (или −−boot), который указывает, что при запуске экземпляра операционной системы в контейнере нужно выполнить init с запуском всех демонов.Этот флаг можно использовать только в случае, если в контейнере будет запущена система с поддержкой systemd.В противном случае загрузка системы не гарантируется.

    По завершении всех указанных операций система предложит ввести логин и пароль.
    Итак, полноценная ОС в изолированном окружении запущена. Теперь нужно настроить для неё сеть, Выйдем из контейнера и создадим мост, через который он будет соединятся с интерфейсом на основном хосте:

    sudo brctl addbr cont-bridge
    


    Назначим для этого моста IP-адрес:

    ip a a [IP-адрес] dev cont-bridge
    


    После этого выполним команду:

    sudo systemd-nspawn -D /var/lib/machines/container1/ --machine test_container --network-bridge=cont-bridge -b
    


    Для настройки сети можно также воспользоваться опцией −−network-ipvlan, которая свяжет контейнер с указанным интерфейсом на основном хосте с помощью ipvlan:

    sudo systemd-nspawn -D /var/lib/machines/container1/ --machine test_container -b --network-ipvlan=[сетевой интерфейс]
    


    Запускаем контейнер как службу



    С помощью systemd можно настроить автоматический запуск контейнеров при загрузке системы. Для этого добавим в директорию /etc/systemd/system вот такой конфигурационный файл:

    [Unit]
    
    Description=Test Container
    
    [Service]
    
    LimitNOFILE=100000
    ExecStart=/usr/bin/systemd-nspawn --machine=test_container --directory=/var/lib/machines/container1/ -b --network-ipvlan=[сетевой интерфейс] 
    Restart=always
    
    [Install]
    
    Also=dbus.service
    


    Прокомментируем приведённый фрагмент. В cекции [Description] мы просто указываем имя контейнера. В секции [Service] мы сначала задаём лимит на количество открытых файлов в контейнере (LimitNOFILE), затем указываем команду на запуск контейнера с необходимыми опциями (ExecStart). Указание Restart=always означает, что контейнер нужно перезапустить в случае «падения». В секции [Install] указывается дополнительный юнит, который должен быть добавлен в автозапуск на хосте (в нашем случае это система межпроцесcного взаимодействия D-Bus).

    Сохраним изменения в конфигурационном файле и выполним команду:

    sudo systecmctl start test_container
    


    Запускать контейнер как службу можно и другим, более простым способом. В systemd имеется заготовка конфигурационного файла для автоматического запуска контейнеров, помещённых в директорию /var/lib/machines. Активировать запуск на базе этой заготовки можно с помощью следующих команд:

    sudo systemctl enable machine.target
    mv ~/test_container /var/lib/machines/test_container
    sudo systemctl enable systemd-nspawn@test_container.service
    


    Управление контейнерами: утилита machinectl



    Контейнерами можно управляться с помощью утилиты machinectl. Кратко рассмотрим её основные опции.

    Вывести список всех имеющихся в системе контейнеров:

    sudo machinectl list
    


    Просмотреть информацию о статусе контейнера:

    sudo machinectl status test_container
    


    Войти в контейнер:

    sudo machinectl login test_container
    


    Перезагрузить контейнер:

    sudo machinectl reboot test_container
    


    Остановить контейнер:

    sudo machinectl poweroff test_container
    


    Последняя команда cработает, если в контейнере установлена ОС, совместимая с systemd. Для операционных систем, использующих sysvinit, нужно воспользоваться опцией terminate.
    Мы рассказали лишь о самых базовых возможностях утилиты machinectl; с подробной инструкцией по её использованию можно ознакомиться, например, здесь.

    Загрузка образов



    Выше мы уже говорили, что с помощью systemd-nspawn можно запускать образами любых других форматов. Есть, однако, одно важное условие: работа с образами возможна только на базе файловой системы BTRFS, которую нужно примонтировать к директории /var/lib/machines:

    sudo dnf install btrfs-progs
    mkfs.btrs /dev/sdb
    mount /dev/sdb /var/lib/machines
    mount | grep btrfs
    
    dev/sdb on /var/lib/machines type btrfs (rw,relatime,seclabel,space_cache)
    


    Если нет свободного диска, BTRFS можно сделать и в файле.
    В более новых версиях systemd возможность загрузки образов поддерживается «из коробки», и монтировать BTRFS не нужно.

    Попробуем загрузить образ Docker:

    sudo machinectl pull-dkr --verify=no library/redis --dkr-index-url=https://index.docker.io
    


    Запуск контейнера на базе загруженного образа осуществляется просто:

    sudo systemd-nspawn --machine redis
    


    Просмотр логов контейнера



    Информация обо всех событиях, происходящих внутри контейнеров, записывается в логи. Настройки логгирования можно устанавливать непосредственно при создании контейнера с помощью опции
    −−link-journal, например:

    sudo systemd-nspawn -D /var/lib/machines/container1/ --machine test_container -b --link-journal=host
    


    Приведённая команда указывает, что логи контейнера будут храниться с на основном хосте в директории /var/log/journal/machine-id. Если же выставить опцию −−link-journal=guest, то вся логи будут храниться в контейнере в директории /var/log/journal/machine-id, а на основном хосте будет создана символическиая ссылка в директории c аналогичным адресом. Опция −−link-journal будет работать только в случае, если в контейнере будет запущена система с systemd. В противном случае корректное логгирование не гарантируется.

    Просмотреть информацию о запусках и остановках контейнера можно с помощью утилиты journalctl, о которой мы уже писали одной из предыдущих публикаций:

     journalctl -u test_container.service
    


    В journalctl предусмотрена возможность просмотра логов событий внутри контейнера.
    Для этого используется опция -M (приводим лишь небольшой фрагмент вывода):

    journalctl -M test_container
    
    
    Sep 18 11:50:21 octavia.localdomain systemd-journal[16]: Runtime journal is using 8.0M (max allowed 197.6M, trying to leave 296.4M free of 1.9G available <E2><86><92>  current limit 197.6M).
    Sep 18 11:50:21 octavia.localdomain systemd-journal[16]: Runtime journal is using 8.0M (max allowed 197.6M, trying to leave 296.4M free of 1.9G available <E2><86><92> current limit 197.6M).
    Sep 18 11:50:21 octavia.localdomain systemd-journal[16]: Journal started
    Sep 18 11:50:21 octavia.localdomain systemd[1]: Starting Slices.
    Sep 18 11:50:21 octavia.localdomain systemd[1]: Reached target Slices.
    Sep 18 11:50:21 octavia.localdomain systemd[1]: Starting Remount Root and Kernel File Systems...
    Sep 18 11:50:21 octavia.localdomain systemd[1]: Started Remount Root and Kernel File Systems.
    Sep 18 11:50:21 octavia.localdomain systemd[1]: Started Various fixups to make systemd work better on Debian.
    


    Выделение ресурсов



    Основные особенности systemd-nspawn мы рассмотрели. Остался один важный момент: выделение контейнерам ресурсов. Как уже отмечалось выше, systemd-nspawn ресурсы не изолирует. Ограничить потребление ресурсов для контейнера можно с помощью systemctl, например:

    sudo systemctl set-property [имя контейнера] CPUShares=200 CPUQuota=30% MemoryLimit=500M
    


    Ограничения ресурсов для контейнера можно прописать и в юнит-файле, в секции [Slice].

    Заключение



    Systemd-nspawn — инструмент интересный и перспективный. В числе его несомненных плюсов стоит выделить:

    • тесную интеграцию с другими компонентами systemd;
    • возможность работы с образами в разных форматах;
    • отсутствие необходимости устанавливать какие-либо дополнительные пакеты или накладывать патчи на ядро.


    Конечно, говорить о полноценном использовании systemd-nspawn в продакшне пока что рано: инструмент пока что находится в «сыром» состоянии и подходит только для тестирования и экспериментов. Однако по мере дальнейшего распространения systemd стоит ждать и усовершенствования systemd-nspawn.

    Естественно, что в рамках обзорной статьи невозможно рассказать абсолютно обо всём. В комментариях приветствуются любые вопросы, замечания и дополнения.
    Если мы упустили какие-то детали или не рассказали о каких-то интересных возможностях systemd-nspawn — напишите, и мы обязательно дополним наш обзор.
    А если кто-то из вас пользуется systemd-nspawn, приглашаем поделиться опытом.

    Читателей, которые по тем или иным причинам не могут оставлять комментарии здесь, приглашаем в наш блог.
    • +22
    • 13,1k
    • 8

    Selectel

    116,76

    ИТ-инфраструктура для бизнеса

    Поделиться публикацией
    Комментарии 8
      +1
      Инструмент контейнеризации? В инит-системе? Осталась ли хоть одна вещь в мире, которую Поттеринг ещё не запихнул в этого монстра?
      +2
      Пользуюсь nspawn-ом на личном сервере (Virtuozzo 7, когда же, когда?). Всё работает, кроме квот на диск — их нет. Для них сделал subvolume-ы на btrfs, хотя и тут всплыл недостаток: если на диске закончилась квота, нельзя удалить файлы, чтобы освободить место: disk quota exceeded. Разработчики btrfs знают про этот баг, однако фиксить его не торопятся.
        0
        Virtuozzo 7, когда же, когда?

        Еще год наверное, а то и больше.
        github.com/Amet13/virtuozzo-tutorial#Планы
          0
          Ну правильно, VZ7 же ещё в стадии technical preview. Я его тестировал — вроде как работает, но с нетерпением жду стейбла. Одно непонятно — зачем там подключается репозиторий cloudlinux, из-за которого в систему тянутся их версии вроде бы стандартных пакетов?
        0
        Мне кажется, что использовать отдельный инструмент для контейнерной виртуализации LXC удобнее, особенно в связке с LVM.
        Но спасибо за расширение кругозора.
          0
          Мой комментарий не по теме, простите.

          Зачем вы сделали редизайн личных кабинетов? Получилось чудовищное дерьмо, просто омерзительно блевотное черти-что, не делайте, пожалуйста дизайн главнее функционала.
            +1
            Фидбек лучше направить через тикет, маловероятно, что тут вас услышат те, кто за это отвечает.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое