Lxd что это
LXD (Linux Container Daemon) — это система контейнерной виртуализации и управления виртуальными машинами на основе ОС Linux. LXD используется для запуска нескольких изолированных экземпляров ОС Linux на одном узле. LXD можно использовать в качестве альтернативы технологии OpenVZ.
Преимущества использования LXD:
- возможность изменения ресурсов контейнера без его остановки;
- высокий уровень безопасности узлов кластера;
- гибкая настройка узлов кластера;
- высокая скорость создания и работы контейнеров;
- высокая плотность виртуализации.
Особенности LXD-кластеров в VMmanager
В текущей версии VMmanager кластер LXD можно создать только с типом настройки сети «Коммутация» или IP-fabric и использованием ZFS-хранилища. Контейнеры и образы ВМ хранятся в пуле ZFS, резервные копии ВМ — на узле кластера. На узлах кластера должна быть установлена ОС Ubuntu 20.04.
В кластерах LXD недоступно:
- подключение ISO-образов пользователей к виртуальным машинам (ВМ);
- добавление узлов с двумя сетевыми интерфейсами;
- создание сетевых мостов;
- живая миграция ВМ;
- установка ОС Windows;
- подключение к ВМ через VNC и SPICE.
Для установки операционных систем в LXD-кластере VMmanager использует отдельные образы ОС. В текущей версии доступны образы ОС:
- AlmaLinux 8;
- СentOS 7, 8;
- Debian 9, 10, 11;
- Oracle Linux 8;
- Rocky Linux 8;
- Ubuntu 18.04, 20.04.
Для удалённого администрирования ВМ вы можете зайти в консоль LXD-контейнера. Окно с консолью откроется в отдельной вкладке браузера.
Вы можете перенести в LXD-кластер виртуальные машины, созданные с помощью виртуализации OVZ. Подробнее см. в статье Перенос OVZ-контейнера в LXD-кластер
Тонкие настройки ВМ
ВМ в кластере LXD имеют особенности в части тонких настроек:
- вес CPU и вес использования I/O изменяются в диапазоне от 0 до 10;
- скорость чтения и записи можно установить либо в IOPS, либо в Мбит/с;
- настройка режима эмуляции CPU недоступна;
- есть возможность настроить:
- вес сети — чем больше вес, тем больше времени выделяется на обработку запросов;
- максимальное количество активных процессов в контейнере;
- лимит использования CPU в процентах;
- создание контейнеров внутри контейнера с использованием Docker, Podman, LXC и т.д.
Подготовка узла кластера
Перед подключением сервера к кластеру настройте на сервере ZFS-пул:
- Перед установкой ОС оставьте на диске сервера неразмеченное пространство.
- Установите утилиту zfsutils-linux:
sudo apt install zfsutils-linuxБазовые возможности LXD — системы контейнеров в Linux

LXD — это системный менеджер контейнеров следующего поколения, так гласит источник. Он предлагает пользовательский интерфейс, похожий на виртуальные машины, но использующий вместо этого контейнеры Linux.
Ядро LXD — это привилегированный демон (сервис запущенный с правами root), который предоставляет REST API через локальный unix сокет, а также через сеть, если установлена соответствующая конфигурация. Клиенты, такие как инструмент командной строки поставляемый с LXD посылают запросы через этот REST API. Это означает, что независимо от того, обращаетесь ли вы к локальному хосту или к удаленному, все работает одинаково.
В этой статье мы не будем подробно останавливаться на концепциях LXD, не будем рассматривать все доступные возможности изложенные в документации в том числе реализацию в последних версиях LXD поддержки виртуальных машин QEMU параллельно с контейнерами. Вместо этого мы узнаем только базовые возможности управления контейнерами — настроим пулы хранилищ, сеть, запустим контейнер, применим лимиты на ресурсы, а также рассмотрим как использовать снепшоты, чтобы вы смогли получить базовое представление о LXD и использовать контейнеры в Linux.
Для получения полной информации следует обратиться к официальному источнику:
Навигация
- Инсталляция LXD
- Инсталляция LXD в дистрибутивах Ubuntu
- Инсталляция LXD в дистрибутивах Arch Linux
- Обзор хранилища LXD (Storage)
- Выбор файловой системы для Storage Pool
- Инициализация основных компонент LXD
- Создание дополнительного Storage Pool
- Увеличение размера Storage Pool
- Автовставка loopback-файла в слот loopback-устройства
- Редактирование профиля
- Создание новых профилей
- Удаленные репозитории образов
- Локальный репозиторий образов
- Установка статического IP адреса
- Доступ к контейнеру
- Управление ресурсами контейнера
- Ограничение ресурсов RAM (ОЗУ)
- Ограничение ресурсов CPU (ЦП)
- Ограничение дискового пространства
- Статистика потребления ресурсов
Инсталляция LXD ^
Прежде чем мы приступим к инсталляции пакета в системе, разберемся с именованием в проекте LXD, чтобы в дальнейшем у нас не было путаницы так как до проекта LXD была реализация проекта LXC одним и тем же автором-разработчиком.
Итак, проект LXD включает в себя два основных бинарных файла:
- LXD /usr/bin/lxd — демон (сервис REST API), где LX в аббревиатуре это сокращение от Linux, а D — демон. Также, это одноименный инсталляционный пакет lxd
- LXC /usr/bin/lxc — клиент командной строки, где C в аббревиатуре это command line client for LXD
Большинство команд представленных в статье, будут относится к клиенту командной строки lxc , например lxc init , но также в статье будет рассмотрена команда инициализации LXD — lxd init которую визуально можно спутать с lxc init .
Следующим шагом мы приступим к инсталляции пакета в системе и для этого предлагаю рассмотреть установку на основе двух популярных дистрибутивов и их производных — Ubuntu и Arch Linux. Инсталляция в Ubuntu немного отличается от классической, так как пакет устанавливается как snap-пакет и файловые пути к структуре проекта LXD будут отличаться от тех, что приведены в этой статье, но я думаю вас не затруднит разобраться с этим самостоятельно.
Инсталляция LXD в дистрибутивах Ubuntu ^
В дистрибутиве Ubuntu 19.10 пакет lxd имеет трансляцию на snap-пакет:
apt search lxd lxd/eoan 1:0.7 all Transitional package - lxd -> snap (lxd)Это значит, что будут установлены сразу два пакета, один системный, а другой как snap-пакет. Установка двух пакетов в системе может создать некоторую проблему, при которой системный пакет может стать сиротой, если удалить snap-пакет менеджером snap-пакетов.
Найти пакет lxd в snap-репозитории можно следующей командой:
snap find lxd Name Version Summary lxd 3.21 System container manager and API lxd-demo-server 0+git.6d54658 Online software demo sessions using LXD nova ocata OpenStack Compute Service (nova) nova-hypervisor ocata OpenStack Compute Service - KVM Hypervisor (nova) distrobuilder 1.0 Image builder for LXC and LXD fabrica 0.1 Build snaps by simply pointing a web form to. satellite 0.1.2 Advanced scalable Open source intelligence platformЗапустив команду list можно убедится, что пакет lxd еще не установлен:
snap list Name Version Rev Tracking Publisher Notes core 16-2.43.3 8689 stable canonical✓ coreНе смотря на то, что LXD является snap-пакетом, устанавливать его нужно через системный пакет lxd , который создаст в системе соответствующую группу, необходимые утилиты в /usr/bin и т.д.
sudo apt update sudo apt install lxdУбедимся, что пакет установлен как snap-пакет:
snap list Name Version Rev Tracking Publisher Notes core 16-2.43.3 8689 stable canonical✓ core lxd 3.21 13474 stable/… canonical✓ -Инсталляция LXD в дистрибутивах Arch Linux ^
Для установки пакета LXD в системе необходимо запустить следующие команды, первая — актуализирует список пакетов в системе доступных в репозитории, вторая — непосредственно установит пакет:
sudo pacman -Syyu && sudo pacman -S lxdПосле установки пакета, для управления LXD обычным пользователем, его необходимо добавить в системную группу lxd :
sudo usermod -a -G lxd user1Убедимся, что пользователь user1 добавлен в группу lxd :
id -Gn user1 user1 adm dialout cdrom floppy sudo audio dip video plugdev netdev lxdЕсли группа lxd не видна в списке, тогда нужно активировать сессию пользователя заново. Для этого нужно выйти и зайти в систему под этим же пользователем.
Активируем в systemd загрузку сервиса LXD при старте системы:
sudo systemctl enable lxdsudo systemctl start lxdПроверяем статус сервиса:
sudo systemctl status lxdИнициализация LXD ^
Прежде чем использовать контейнеры необходимо выполнить инициализацию основных компонент LXD — виртуальную сеть и хранилище в котором будут хранится файлы контейнера, образов и другие файлы. В этом нам поможет мастер инициализации, который инициализирует компоненты после того как мы ответим на его вопросы.
Обзор хранилища LXD (Storage) ^
В этом разделе мы только ознакомимся с хранилищем в LXD, а инициализировать его мы будем немного позже с помощью мастера инициализации.
Хранилище (Storage) состоит из одного или нескольких Storage Pool который использует одну из поддерживаемых файловых систем такие как ZFS, BTRFS, LVM или обычные директории. Каждый Storage Pool разделяется на тома (Storage Volume) которые содержат образы, контейнеры или данные для других целей.

- Образы — это специально собранные дистрибутивы без ядра Linux и доступные из внешних источников
- Контейнеры — это развернутые дистрибутивы из образов, готовые к эксплуатации
- Снепшоты — это снимки состояния контейнеров к которым можно возвращаться
Для управления хранилищем в LXD служит команда lxc storage справку по которой можно получить указав ключ — lxc storage —help
Следующая команда выводит на экран список всех Storage Pool в LXD хранилище:
lxc storage list +---------+-------------+--------+--------------------------------+---------+ | NAME | DESCRIPTION | DRIVER | SOURCE | USED BY | +---------+-------------+--------+--------------------------------+---------+ | hddpool | | btrfs | /dev/loop1 | 2 | +---------+-------------+--------+--------------------------------+---------+ | ssdpool | | btrfs | /var/lib/lxd/disks/ssdpool.img | 4 | +---------+-------------+--------+--------------------------------+---------+Для просмотра списка всех Storage Volume в выбранном Storage Pool служит команда lxc storage volume list :
lxc storage volume list hddpool +-------+----------------------------------+-------------+---------+ | TYPE | NAME | DESCRIPTION | USED BY | +-------+----------------------------------+-------------+---------+ | image | ebd565585223487526ddb3607f515. | | 1 | +-------+----------------------------------+-------------+---------+lxc storage volume list ssdpool +-----------+----------------------------------+-------------+---------+ | TYPE | NAME | DESCRIPTION | USED BY | +-----------+----------------------------------+-------------+---------+ | container | alp3 | | 1 | +-----------+----------------------------------+-------------+---------+ | container | jupyter | | 1 | +-----------+----------------------------------+-------------+---------+ | image | ebd565585223487526ddb3607f515. | | 1 | +-----------+----------------------------------+-------------+---------+Также, если для Storage Pool при создании была выбрана файловая система BTRFS, то получить список Storage Volume или subvolumes в интерпретации BTRFS можно с помощью инструментария этой файловой системы:
sudo btrfs subvolume list -p /var/lib/lxd/storage-pools/hddpool ID 257 gen 818 parent 5 top level 5 path images/ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3sudo btrfs subvolume list -p /var/lib/lxd/storage-pools/ssdpool ID 257 gen 1820 parent 5 top level 5 path images/ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3 ID 260 gen 1819 parent 5 top level 5 path containers/jupyter ID 263 gen 1820 parent 5 top level 5 path containers/alp3Выбор файловой системы для Storage Pool ^
Во время инициализации LXD задаёт несколько вопросов, среди которых будет определение типа файловой системы для дефолтного Storage Pool. По умолчанию для него выбирается файловая система BTRFS. Поменять на другую ФС после создания будет невозможно. Для выбора ФС предлагается таблица сравнения возможностей:
Feature Directory Btrfs LVM ZFS CEPH Optimized image storage no yes yes yes yes Optimized instance creation no yes yes yes yes Optimized snapshot creation no yes yes yes yes Optimized image transfer no yes no yes yes Optimized instance transfer no yes no yes yes Copy on write no yes yes yes yes Block based no no yes no yes Instant cloning no yes yes yes yes Storage driver usable inside a container yes yes no no no Restore from older snapshots (not latest) yes yes yes no yes Storage quotas yes(*) yes yes yes no Инициализация основных компонент LXD ^
Итак, у нас всё готово для инициализации LXD. Запустите команду вызова мастера инициализации lxd init и введите ответы на вопросы после знака двоеточия так как показано в примере ниже или измените их согласно вашим условиям:
lxd init Would you like to use LXD clustering? (yes/no) [default=no]: Do you want to configure a new storage pool? (yes/no) [default=yes]: Name of the new storage pool [default=default]: ssdpool Name of the storage backend to use (lvm, btrfs, dir) [default=btrfs]: Create a new BTRFS pool? (yes/no) [default=yes]: Would you like to use an existing block device? (yes/no) [default=no]: Size in GB of the new loop device (1GB minimum) [default=15GB]: 10GB Would you like to connect to a MAAS server? (yes/no) [default=no]: Would you like to create a new local network bridge? (yes/no) [default=yes]: What should the new bridge be called? [default=lxdbr0]: What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 10.0.5.1/24 Would you like LXD to NAT IPv4 traffic on your bridge? [default=yes]: What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: none Would you like LXD to be available over the network? (yes/no) [default=no]: Would you like stale cached images to be updated automatically? (yes/no) [default=yes] no Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:Создание дополнительного Storage Pool ^
В предыдущем шаге мы создали Storage Pool которому дали название ssdpool и файл которого расположился в моей системе по адресу /var/lib/lxd/disks/ssdpool.img . Этот адрес файловой системы соответствует физическому SSD диску в моём ПК.
Следующими действиями, для расширения понимания того, какую роль играет Storage Pool в хранилище, мы создадим второй Storage Pool который будет физически располагаться на другом типе диске, на HDD. Проблема заключается в том, что LXD не позволяет создавать Storage Pool вне адреса /var/lib/lxd/disks/ и даже символические ссылки не будут работать, смотрите ответ разработчика. Обойти это ограничение мы можем при инициализации/форматировании Storage Pool указав значение как блочное устройство вместо пути к loopback-файлу указав это в ключе source .
Итак, до создания Storage Pool необходимо определить loopback-файл или существующий раздел в вашей файловой системе который он будет использовать. Для этого, мы создадим и будем использовать файл который ограничим размером в 10GB:
dd if=/dev/zero of=/mnt/work/lxd/hddpool.img bs=1MB count=10000 10000+0 records in 10000+0 records out 10000000000 bytes (10 GB, 9,3 GiB) copied, 38,4414 s, 260 MB/sПодключим loopback-файл в свободное loopback-устройство:
sudo losetup --find --show /mnt/work/lxd/hddpool.img /dev/loop1Благодаря ключу —show выполнение команды возвращает на экран имя устройства в которое подключился наш loopback-файл. При необходимости, мы можем вывести на экран список всех занятых устройств этого типа, чтобы убедится в корректности наших действий:
losetup -l NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE DIO LOG-SEC /dev/loop1 0 0 0 0 /mnt/work/lxd/hddpool.img 0 512 /dev/loop0 0 0 1 0 /var/lib/lxd/disks/ssdpool.img 0 512Из списка можно обнаружить, что в устройстве /dev/loop1 подключен loopback-файл /mnt/work/lxd/hddpool.img , а в устройстве /dev/loop0 подключен loopback-файл /var/lib/lxd/disks/ssdpool.img который соответствует дефолтному Storage Pool.
Следующая команда создает новый Storage Pool в LXD на основе только что подготовленного loopback-файла. LXD отформатирует loopback-файл /mnt/work/lxd/hddpool.img в устройстве /dev/loop1 под файловую систему BTRFS:
lxc storage create hddpool btrfs size=10GB source=/dev/loop1Выведем список всех Storage Pool на экран:
lxc storage list +---------+-------------+--------+--------------------------------+---------+ | NAME | DESCRIPTION | DRIVER | SOURCE | USED BY | +---------+-------------+--------+--------------------------------+---------+ | hddpool | | btrfs | /dev/loop1 | 0 | +---------+-------------+--------+--------------------------------+---------+ | ssdpool | | btrfs | /var/lib/lxd/disks/ssdpool.img | 0 | +---------+-------------+--------+--------------------------------+---------+Увеличение размера Storage Pool ^
После создания Storage Pool, при необходимости, его можно расширить. Для Storage Pool основанном на файловой системе BTRFS выполните следующие команды:
sudo truncate -s +5G /mnt/work/lxd/hddpool.img sudo losetup -c /dev/loop1 sudo btrfs filesystem resize max /var/lib/lxd/storage-pools/hddpoolАвтовставка loopback-файла в слот loopback-устройства ^
У нас есть одна небольшая проблема, при перезагруке системы хоста, файл /mnt/work/lxd/hddpool.img «вылетит» из устройства /dev/loop1 и сервис LXD упадет при загрузке так как не увидит его в этом устройстве. Для решения этой проблемы нужно создать системный сервис который будет вставлять этот файл в устройство /dev/loop1 при загрузке системы хоста.
Создадим unit файл типа service в /etc/systemd/system/ для системы инициализации SystemD:
sudo systemctl enable lxd-hddpool Created symlink /etc/systemd/system/local-fs.target.wants/lxd-hddpool.service → /etc/systemd/system/lxd-hddpool.service.После рестарта хостовой системы проверяем статус сервиса:
systemctl status lxd-hddpool.service ● lxd-hddpool.service - Losetup LXD Storage Pool (hddpool) Loaded: loaded (/etc/systemd/system/lxd-hddpool.service; enabled; vendor preset: disabled) Active: active (exited) since Wed 2020-04-08 03:43:53 MSK; 1min 37s ago Process: 711 ExecStart=/sbin/losetup /dev/loop1 /mnt/work/lxd/hddpool.img (code=exited, status=0/SUCCESS) Main PID: 711 (code=exited, status=0/SUCCESS) апр 08 03:43:52 manjaro systemd[1]: Starting Losetup LXD Storage Pool (hddpool). апр 08 03:43:53 manjaro systemd[1]: Finished Losetup LXD Storage Pool (hddpool).Из вывод мы можем убедиться, что состояние сервиса равно active, несмотря на то, что выполнение нашего скрипта из одной команды завершилось, это позволила нам сделать опция RemainAfterExit=true .
Безопасность. Привилегии контейнеров ^
Так как все процессы контейнера фактически исполняются в изоляции на хостовой системе используя его ядро, то для дополнительной защиты доступа процессов контейнера к системе хоста LXD предлагает привилегированность процессов, где:
- Привилегированные контейнеры — это контейнеры в которых процессы с UID и GID соответствуют тому же владельцу, что и на хостовой системе. Например, процесс запущенный в контейнере с UID равным 0 имеет все те же права доступа, что и процесс хостовой системы с UID равным 0. Другими словами, root пользователь в контейнере обладает всеми правами не только в контейнере, но и на хостовой системе если он сможет выйти за пределы изолированного пространства имен контейнера.
- Непривилегированные контейнеры — это контейнеры в которых процессы принадлежат владельцу UID и GID с номером от 0 до 65535, но для хостовой системы владелец маскируется с помощью добавляемого бита SubUID и SubGID соответственно. Например, пользователь с UID=0 в контейнере будет замечен в хостовой системе как SubUID + UID . Это защищает хост-систему, поскольку, если какой-либо процесс в контейнере сможет выйти из своего изолированного пространства имен, он может взаимодействовать с хост-системой только как процесс с неизвестным, очень высоким UID/GID.
По умолчанию, вновь создаваемые контейнеры имеют статус непривилегированных и поэтому мы должны определить SubUID и SubGID.
Создадим два конфигурационных файла в которых зададим маску для SubUID и SubGID соответственно:
sudo touch /etc sudo usermod --add-subuids 1000000-1065535 root sudo usermod --add-subgids 1000000-1065535 rootДля применения изменений, сервис LXD должен быть рестартован:
sudo systemctl restart lxdСоздание виртуального коммутатора сети ^
Так как мы ранее инициализировали сеть с помощью мастера инициализации lxd init и создали сетевое устройство lxdbr0 , то в этом разделе мы просто ознакомимся с сетью в LXD и с тем, как создавать виртуальный коммутатор (сетевой мост, bridge) с помощью команды клиента.
Следующая схема демонстрирует как коммутатор (сетевой мост, bridge) объединяет хост и контейнеры в сеть:

Контейнеры могут взаимодействовать посредством сети с другими контейнерами или хостом на котором эти контейнеры обслуживаются. Для этого необходимо слинковать виртуальные сетевые карты контейнеров с виртуальным коммутатором. В начале создадим коммутатор, а сетевые интерфейсы контейнера будут слинкованы в последующих главах, после того как будет создан сам контейнер.
Следующая команда создаёт коммутатор с подсетью 10.0.5.0/24 и IPv4 адресом 10.0.5.1/24 , а также включает ipv4.nat чтобы контейнеры смогли получать интернет через хост с помощью службы NAT:
lxc network create lxdbr0 ipv4.address=10.0.5.1/24 ipv4.nat=true ipv6.address=noneПроверяем список сетевых устройств доступных LXD:
lxc network list +--------+----------+---------+-------------+---------+ | NAME | TYPE | MANAGED | DESCRIPTION | USED BY | +--------+----------+---------+-------------+---------+ | eno1 | physical | NO | | 0 | +--------+----------+---------+-------------+---------+ | lxdbr0 | bridge | YES | | 0 | +--------+----------+---------+-------------+---------+Также, убедится в создании сетевого устройства можно с помощью штатного стредства Linux-дистрибутива — ip link или ip addr :
ip addr 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eno1: mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether bc:ee:7b:5a:6b:44 brd ff:ff:ff:ff:ff:ff altname enp0s25 inet6 fe80::9571:11f3:6e0c:c07b/64 scope link noprefixroute valid_lft forever preferred_lft forever 3: lxdbr0: mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether c2:38:90:df:cb:59 brd ff:ff:ff:ff:ff:ff inet 10.0.5.1/24 scope global lxdbr0 valid_lft forever preferred_lft forever inet6 fe80::c038:90ff:fedf:cb59/64 scope link valid_lft forever preferred_lft forever 5: veth3ddab174@if4: mtu 1500 qdisc noqueue master lxdbr0 state UP group default qlen 1000 link/ether ca:c3:5c:1d:22:26 brd ff:ff:ff:ff:ff:ff link-netnsid 0Профиль конфигурации ^
Каждый контейнер в LXD имеет свою собственную конфигурацию и может расширять её с помощью глобально декларируемых конфигураций которые называются профилями конфигурации. Применение профилей конфигурации к контейнеру имеет каскадную модель, следующий пример демонстрирует это:

В этом примере, в системе LXD созданы три профиля: default , hddpool и hostfs . Все три профиля применены к контейнеру у которого имеется локальная конфигурация (серая зона). Профиль default имеет устройство root у которого параметр pool равен ssdpool , но благодаря каскадной модели применения конфигурации мы можем применить для контейнера профиль hddpool у которого параметр pool перекроет этот же параметр из профиля default и контейнер получит конфигурацию устройства root с параметром pool равным hddpool , а профиль hostfs просто добавляет новое устройство в контейнер.
Выведем на экран список всех доступных профилей конфигурации:
lxc profile list +---------+---------+ | NAME | USED BY | +---------+---------+ | default | 1 | +---------+---------+ | hddroot | 0 | +---------+---------+ | ssdroot | 1 | +---------+---------+Полный список доступных команд для управления профилями можно получить добавив ключ —help :
lxc profile --help Description: Manage profiles Usage: lxc profile [command] Available Commands: add Add profiles to instances assign Assign sets of profiles to instances copy Copy profiles create Create profiles delete Delete profiles device Manage instance devices edit Edit profile configurations as YAML get Get values for profile configuration keys list List profiles remove Remove profiles from instances rename Rename profiles set Set profile configuration keys show Show profile configurations unset Unset profile configuration keysРедактирование профиля ^
Профиль конфигурации по умолчанию default не имеет конфигурации сетевого интерфейса и все вновь создаваемые контейнеры не получают сеть. Для них необходимо создавать отдельными командами локальные сетевые интерфейсы, но мы можем создать в профиле конфигурации глобальный сетевой интерфейс который будет разделяться между всеми контейнерами использующими этот профиль. Таким образом, сразу после команды создания нового контейнера он получит сеть с доступом в интернет. При этом, нет ограничений, мы всегда можем позже создать локальный сетевой интерфейс для контейнера если будет в этом необходимость и/или удалить интерфейс из профиля.
Следующая команда добавит в профиль конфигурации устройство eth0 типа nic присоединяемого к сети lxdbr0 :
lxc profile device add default eth0 nic network=lxdbr0 name=eth0Важно отметить, что так как мы фактически добавили устройство в профиль конфигурации, то если бы мы указали в устройстве статический IP адрес, то все контейнеры которые будут применять этот профиль разделят один и тот же IP адрес. Если есть необходимость создать контейнер с выделенным для контейнера статическим IP адресом, тогда следует создать конфигурацию сетевого устройства на уровне контейнера (локальная конфигурация) с параметром IP адреса, а не на уровне профиля.
lxc profile show default config: <> description: Default LXD profile devices: eth0: name: eth0 network: lxdbr0 type: nic root: path: / pool: ssdpool type: disk name: default used_by: []В этом профиле мы можем увидеть, что для всех вновь создаваемых контейнеров будут созданы два устройства (devices):
- eth0 — Устройство типа nic слинкованное с коммутатором (сетевым мостом) lxdbr0
- root — Устройство типа disk которое использует пул хранилища ssdpool
Создание новых профилей ^
Для использования ранее созданных Storage Pool контейнерами, создадим профиль конфигурации ssdroot в котором добавим устройство типа disk с точкой монтирования / (root) использующее ранее созданное Storage Pool — ssdpool :
lxc profile create ssdroot lxc profile device add ssdroot root disk path=/ pool=ssdpoolАналогично, создаем устройство типа disk , но в этом случае использующее Storage Pool — hddpool :
lxc profile create hddroot lxc profile device add hddroot root disk path=/ pool=hddpoolПроверяем профили конфигурации:
lxc profile show ssdroot config: <> description: "" devices: root: path: / pool: ssdpool type: disk name: ssdroot used_by: []lxc profile show hddroot config: <> description: "" devices: root: path: / pool: hddpool type: disk name: hddroot used_by: []Репозиторий образов ^
Контейнеры создаются из образов которые являются специально собранными дистрибутивами не имеющие ядра Linux. Поэтому, прежде чем запустить контейнер, он должен быть развернут из этого образа. Источником образов служит локальный репозиторий в который образы загружаются из внешних репозиториев.
Удаленные репозитории образов ^
По умолчанию LXD настроен на получение образов из трёх удаленных источников:
- ubuntu: (for stable Ubuntu images)
- ubuntu-daily: (for daily Ubuntu images)
- images: (for a bunch of other distros)
lxc remote list +-----------------+------------------------------------------+--------+--------+ | NAME | URL | PUBLIC | STATIC | +-----------------+------------------------------------------+--------+--------+ | images | https://images.linuxcontainers.org | YES | NO | +-----------------+------------------------------------------+--------+--------+ | local (default) | unix:// | NO | YES | +-----------------+------------------------------------------+--------+--------+ | ubuntu | https://cloud-images.ubuntu.com/releases | YES | YES | +-----------------+------------------------------------------+--------+--------+ | ubuntu-daily | https://cloud-images.ubuntu.com/daily | YES | YES | +-----------------+------------------------------------------+--------+--------+Например, репозиторий ubuntu: имеет следующие образы:
lxc image -c dasut list ubuntu: | head -n 11 +----------------------------------------------+--------------+----------+------------+ | DESCRIPTION | ARCHITECTURE | SIZE | TYPE | +----------------------------------------------+--------------+----------+------------+ | ubuntu 12.04 LTS amd64 (release) (20150728) | x86_64 | 153.72MB | CONTAINER | +----------------------------------------------+--------------+----------+------------+ | ubuntu 12.04 LTS amd64 (release) (20150819) | x86_64 | 152.91MB | CONTAINER | +----------------------------------------------+--------------+----------+------------+ | ubuntu 12.04 LTS amd64 (release) (20150906) | x86_64 | 154.69MB | CONTAINER | +----------------------------------------------+--------------+----------+------------+ | ubuntu 12.04 LTS amd64 (release) (20150930) | x86_64 | 153.86MB | CONTAINER | +----------------------------------------------+--------------+----------+------------+Чтобы вывести ограниченное количество колонок мы использовали опцию -c с параметрами dasut , а также ограничили длину списка командой head .
Для вывода списка образов доступна фильтрация. Следующая команда выведет список всех доступных архитектур дистрибутива AlpineLinux:
lxc image -c ldast list images:alpine/3.11 +------------------------------+--------------------------------------+--------------+ | ALIAS | DESCRIPTION | ARCHITECTURE | +------------------------------+--------------------------------------+--------------+ | alpine/3.11 (3 more) | Alpine 3.11 amd64 (20200220_13:00) | x86_64 | +------------------------------+--------------------------------------+--------------+ | alpine/3.11/arm64 (1 more) | Alpine 3.11 arm64 (20200220_13:00) | aarch64 | +------------------------------+--------------------------------------+--------------+ | alpine/3.11/armhf (1 more) | Alpine 3.11 armhf (20200220_13:00) | armv7l | +------------------------------+--------------------------------------+--------------+ | alpine/3.11/i386 (1 more) | Alpine 3.11 i386 (20200220_13:01) | i686 | +------------------------------+--------------------------------------+--------------+ | alpine/3.11/ppc64el (1 more) | Alpine 3.11 ppc64el (20200220_13:00) | ppc64le | +------------------------------+--------------------------------------+--------------+ | alpine/3.11/s390x (1 more) | Alpine 3.11 s390x (20200220_13:00) | s390x | +------------------------------+--------------------------------------+--------------+Локальный репозиторий образов ^
Для начала эксплуатации контейнера необходимо добавить образ из глобального репозитория в локальный local: . Сейчас локальный репозиторий пуст, убедится в этом нам даст команда lxc image list . Если методу list не указать репозиторий, то по умолчанию будет использоваться локальный репозиторий — local:
lxc image list local: +-------+-------------+--------+-------------+--------------+------+------+ | ALIAS | FINGERPRINT | PUBLIC | DESCRIPTION | ARCHITECTURE | TYPE | SIZE | +-------+-------------+--------+-------------+--------------+------+------+Управление образами в репозитории производится следующими методами:
Команда Описание lxc image alias Manage image aliases lxc image copy Copy images between servers lxc image delete Delete images lxc image edit Edit image properties lxc image export Export and download images lxc image import Import images into the image store lxc image info Show useful information about images lxc image list List images lxc image refresh Refresh images lxc image show Show image properties Копируем образ в локальный репозиторий из глобального images: :
lxc image copy images:alpine/3.11/amd64 local: --alias=alpine3 Image copied successfully!Выведем список всех образов доступных сейчас в локальном репозитории local: :
lxc image -c lfdatsu list local: +---------+--------------+------------------------------------+--------------+ | ALIAS | FINGERPRINT | DESCRIPTION | ARCHITECTURE | +---------+--------------+------------------------------------+--------------+ | alpine3 | 73a3093d4a5c | Alpine 3.11 amd64 (20200220_13:00) | x86_64 | +---------+--------------+------------------------------------+--------------+Конфигурация LXD ^
Кроме интерактивного режима, LXD поддерживает также неинтерактивный режим установки конфигурации, это когда конфигурация задается в виде YAML-файла, специального формата, который позволяет установить всю конфигурацию за один раз, минуя выполнения множества интерактивных команд которые были рассмотрены выше в этой статье, в том числе конфигурацию сети, создание профилей конфигурации и т.д. Здесь мы не будем рассматривать эту область, вы можете самостоятельно ознакомится с этим в документации.
Следующая интерактивная команда lxc config которую мы рассмотрим, позволяет устанавливать конфигурацию. Например, для того, чтобы загруженные образы в локальный репозиторий не обновлялись автоматически из глобальных репозиториев, мы можем включить это поведение следующей командой:
lxc config set images.auto_update_cached=falseСоздание и управление контейнером ^
Для создания контейнера служит команда lxc init которой передаются значения репозиторий:образ и затем желаемый идентификатор для контейнера. Репозиторий может быть указан как локальный local: так и любой глобальный. Если репозиторий не указан, то по умолчанию, для поиска образа используется локальный репозиторий. Если образ указан из глобального репозитория, то в начале образ будет загружен в локальный репозиторий, а затем использован для создания контейнера.
Выполним следующую команду чтобы создать наш первый контейнер:
lxc init alpine3 alp --storage=hddpool --profile=default --profile=hddrootРазберем по порядку ключи команды которые мы здесь используем:
- alpine3 — Указывается альяс (псевдоним) для образа который ранее был загружен в локальный репозиторий. Если бы альяс был не создан для этого образа, то всегда можно сослаться на образ по его Fingerprint который выводится в таблице.
- alp — Задаётся идентификатор для контейнера
- —storage — Этот ключ указывает в каком Storage Pool будет создан контейнер, однако в нашем случае, этот ключ не обязательно указывать, так как профиль конфигурации hddroot который мы создали ранее, уже имеет конфигурацию которая использует hddpool , в этом можно убедится посмотрев информацию из команды lxc profile show hddroot
- —profile — Эти ключи каскадно применяют к контейнеру конфигурацию из ранее созданных профилей конфигурации
Запускаем контейнер, который начинает запускать init-систему дистрибутива:
lxc start alpТакже, можно воспользоваться командой lxc launch которая позволяет объединить команды lxc init и lxc start в одну операцию.
Проверяем состояние контейнера:
lxc list -c ns46tb +------+---------+------------------+------+-----------+--------------+ | NAME | STATE | IPV4 | IPV6 | TYPE | STORAGE POOL | +------+---------+------------------+------+-----------+--------------+ | alp | RUNNING | 10.0.5.46 (eth0) | | CONTAINER | hddpool | +------+---------+------------------+------+-----------+--------------+Проверяем конфигурацию контейнера:
lxc config show alp architecture: x86_64 config: image.architecture: amd64 image.description: Alpine 3.11 amd64 (20200326_13:39) image.os: Alpine image.release: "3.11" image.serial: "20200326_13:39" image.type: squashfs volatile.base_image: ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3 volatile.eth0.host_name: vethb1fe71d8 volatile.eth0.hwaddr: 00:16:3e:5f:73:3e volatile.idmap.base: "0" volatile.idmap.current: '[,]' volatile.idmap.next: '[,]' volatile.last_state.idmap: '[,]' volatile.last_state.power: RUNNING devices: root: path: / pool: hddpool type: disk ephemeral: false profiles: - default - hddroot stateful: false description: ""В секции profiles мы можем убедиться, что этот контейнер использует два профиля конфигурации — default и hddroot . В секции devices мы можем обнаружить только одно устройство, так как сетевое устройство было создано на уровне профиля default . Для того, чтобы увидеть все устройства используемые контейнером необходимо добавить ключ —expanded :
lxc config show alp --expanded architecture: x86_64 config: image.architecture: amd64 image.description: Alpine 3.11 amd64 (20200326_13:39) image.os: Alpine image.release: "3.11" image.serial: "20200326_13:39" image.type: squashfs volatile.base_image: ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3 volatile.eth0.host_name: vethb1fe71d8 volatile.eth0.hwaddr: 00:16:3e:5f:73:3e volatile.idmap.base: "0" volatile.idmap.current: '[,]' volatile.idmap.next: '[,]' volatile.last_state.idmap: '[,]' volatile.last_state.power: RUNNING devices: eth0: name: eth0 network: lxdbr0 type: nic root: path: / pool: hddpool type: disk ephemeral: false profiles: - default - hddroot stateful: false description: ""Установка статического IP адреса ^
Если мы попытаемся установить IP адрес для сетевого устройства eth0 командой lxc config device set alp предназначенной для конфигурации контейнера, то мы получим ошибку которая сообщит, что устройство не существует потому что устройство eth0 которое используется контейнером принадлежит профилю default :
lxc config device set alp eth0 ipv4.address 10.0.5.5 Error: The device doesn't existМы можем конечно установить статический IP адрес для eth0 устройства в профиле, но он будет един для всех контейнеров которые этот профиль будут использовать. Поэтому, добавим выделенное для контейнера устройство:
lxc config device add alp eth0 nic name=eth0 nictype=bridged parent=lxdbr0 ipv4.address=10.0.5.5В новых версиях LXD 3.21 и выше доступна улучшенная команда создания интерфейса для сетевого моста (bridge network), сейчас можно просто указать значение параметра network , исключив указание значений для nictype и parent :
lxc config device add alp eth0 nic name=eth0 network=lxdbr0 ipv4.address=10.0.5.5Затем следует рестартовать контейнер:
lxc restart alpЕсли мы сейчас посмотрим на конфигурацию контейнера, то нам не нужно применять опцию —expanded чтобы увидеть сетевое устройство eth0 , так как мы создали его на уровне контейнера и оно каскадно перекрыло это же устройство из профиля default :
lxc config show alp architecture: x86_64 config: image.architecture: amd64 image.description: Alpine 3.11 amd64 (20200326_13:39) image.os: Alpine image.release: "3.11" image.serial: "20200326_13:39" image.type: squashfs volatile.base_image: ebd565585223487526ddb3607f5156e875c15a89e21b61ef004132196da6a0a3 volatile.eth0.host_name: veth2a1dc59d volatile.eth0.hwaddr: 00:16:3e:0e:e2:71 volatile.idmap.base: "0" volatile.idmap.current: '[,]' volatile.idmap.next: '[,]' volatile.last_state.idmap: '[,]' volatile.last_state.power: RUNNING devices: eth0: ipv4.address: 10.0.5.5 name: eth0 nictype: bridged parent: lxdbr0 type: nic root: path: / pool: hddpool type: disk ephemeral: false profiles: - default - hddroot stateful: false description: ""Доступ к контейнеру ^
Для выполнения команд в контейнере, напрямую, минуя сетевые соединения, служит команда lxc exec которая выполняет команды в контейнере без запуска системной оболочки. Если вам нужно выполнить команду в оболочке, используя shell паттерны, такие как переменные, файловые перенаправления (pipe) и т.д., то необходимо явно запускать оболочку и передавать команду в качестве ключа, например:
lxc exec alp -- /bin/sh -c "echo \$HOME"В команде был задействован спецсимвол экранирования \ для спецсимвола $ чтобы переменная $HOME не интерпретировалась на хостовой машине, а была интерпретирована только внутри контейнера.
Также, возможно запустить интерактивный режим оболочки, а после завершить сеанс выполнив hotkey CTRL+D :
lxc exec alp -- /bin/shУправление ресурсами контейнера ^
В LXD можно управлять ресурсами контейнера при помощи специального набора конфигурации. Полный список конфигурационных параметров контейнера можно найти в документации.
Ограничение ресурсов RAM (ОЗУ) ^
Параметр limits.memory ограничивает объём RAM доступный для контейнера. В качестве значения указывается число и один из доступных суффиксов.
Зададим контейнеру ограничение на объём RAM равный 256 MB:
lxc config set alp limits.memory 256MBТакже, существуют другие параметры для ограничения памяти:
- limits.memory.enforce
- limits.memory.hugepages
- limits.memory.swap
- limits.memory.swap.priority
Команда lxc config show позволяет вывести на экран всю конфигурацию контейнера, в том числе примененное ограничение ресурсов которое было установлено:
lxc config show alp architecture: x86_64 config: image.architecture: amd64 image.description: Alpine 3.11 amd64 (20200220_13:00) image.os: Alpine image.release: "3.11" image.serial: "20200220_13:00" image.type: squashfs limits.memory: 256MB volatile.base_image: 73a3093d4a5ce0148fd84b95369b3fbecd19a537ddfd2e2d20caa2eef0e8fd60 volatile.eth0.host_name: veth75b6df07 volatile.eth0.hwaddr: 00:16:3e:a1:e7:46 volatile.idmap.base: "0" volatile.idmap.current: '[]' volatile.idmap.next: '[]' volatile.last_state.idmap: '[]' volatile.last_state.power: RUNNING devices: <> ephemeral: false profiles: - default stateful: false description: ""Ограничение ресурсов CPU (ЦП) ^
Для ограничения ресурсов ЦП существует несколько типов ограничений:
- limit.cpu — привязывает контейнер к одному или нескольким ядрам ЦП
- limits.cpu.allowance — управляет либо квотами планировщика CFS, когда прошло ограничение по времени, либо универсальным механизмом совместного использования ресурсов CPU, когда прошло процентное значение
- limits.cpu.priority — приоритет планировщика, когда для нескольких экземпляров, совместно использующих набор процессоров, назначен одинаковый процент процессоров
lxc config set alp limits.cpu.allowance 40%lxc config show alp architecture: x86_64 config: image.architecture: amd64 image.description: Alpine 3.11 amd64 (20200220_13:00) image.os: Alpine image.release: "3.11" image.serial: "20200220_13:00" image.type: squashfs limits.cpu.allowance: 40% limits.memory: 256MB volatile.base_image: 73a3093d4a5ce0148fd84b95369b3fbecd19a537ddfd2e2d20caa2eef0e8fd60 volatile.eth0.host_name: veth75b6df07 volatile.eth0.hwaddr: 00:16:3e:a1:e7:46 volatile.idmap.base: "0" volatile.idmap.current: '[]' volatile.idmap.next: '[]' volatile.last_state.idmap: '[]' volatile.last_state.power: RUNNING devices: <> ephemeral: false profiles: - default stateful: false description: ""Ограничение дискового пространства ^
Кроме ограничений таких как limits.read , limits.write мы также можем ограничить объём потребления контейнером дискового пространства (работает только с ZFS или BTRFS):
lxc config device set alp root size=2GBПосле установки, в параметре devices.root.size мы можем убедится в установленном ограничении:
lxc config show alp . devices: root: path: / pool: hddpool size: 2GB type: disk ephemeral: false profiles: - default - hddroot stateful: false description: ""Для просмотра используемых квот на диск мы можем получить из команды lxc info :
lxc info alp . Resources: Processes: 5 Disk usage: root: 1.05GB CPU usage: CPU usage (in seconds): 1 Memory usage: Memory (current): 5.46MB Network usage: eth0: Bytes received: 802B Bytes sent: 1.59kB Packets received: 4 Packets sent: 14 lo: Bytes received: 0B Bytes sent: 0B Packets received: 0 Packets sent: 0Не смотря на то, что мы установили ограничение для корневого устройства контейнера в 2GB, системные утилиты такие как df не будут видеть это ограничение. Для этого мы проведем небольшой тест и выясним как это работает.
Создадим 2 новых одинаковых контейнера в одном и том же Storage Pool (hddpool):
lxc init alpine3 alp1 --storage=hddpool --profile=default --profile=hddroot lxc init alpine3 alp2 --storage=hddpool --profile=default --profile=hddrootlxc list +------+---------+------------------+------+-----------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+---------+------------------+------+-----------+-----------+ | alp1 | RUNNING | 10.0.5.46 (eth0) | | CONTAINER | 0 | +------+---------+------------------+------+-----------+-----------+ | alp2 | RUNNING | 10.0.5.30 (eth0) | | CONTAINER | 0 | +------+---------+------------------+------+-----------+-----------+В одном из контейнеров создадим файл размером 1GB:
lxc exec alp1 -- dd if=/dev/urandom of=file.img bs=1M count=1000Убедимся, что файл создан:
lxc exec alp1 -- ls -lh total 1000M -rw-r--r-- 1 root root 1000.0M Mar 27 10:16 file.imgЕсли мы посмотрим во втором контейнере, проверим существование файла в том же самом месте, то этого файла не будет, что ожидаемо, так как контейнеры создаются в своих собственных Storage Volume в этом же Storage Pool:
lxc exec alp2 -- ls -lh total 0Но давайте сравним значения которые выдает df на одном и другом контейнерах:
lxc exec alp1 -- df -hT Filesystem Type Size Used Available Use% Mounted on /dev/loop1 btrfs 9.3G 1016.4M 7.8G 11% / .lxc exec alp2 -- df -hT Filesystem Type Size Used Available Use% Mounted on /dev/loop1 btrfs 9.3G 1016.4M 7.8G 11% / .Устройство /dev/loop1 смонтированное как корневой раздел является Storage Pool которое эти контейнеры используют, поэтому они разделяют его объём на двоих.
Статистика потребления ресурсов ^
Просмотреть статистику потребления ресурсов для контейнера можно с помощью команды:
lxc info alp Name: alp Location: none Remote: unix:// Architecture: x86_64 Created: 2020/04/08 18:05 UTC Status: Running Type: container Profiles: default, hddroot Pid: 19219 Ips: eth0: inet 10.0.5.5 veth2a1dc59d eth0: inet6 fe80::216:3eff:fe0e:e271 veth2a1dc59d lo: inet 127.0.0.1 lo: inet6 ::1 Resources: Processes: 5 Disk usage: root: 495.62kB CPU usage: CPU usage (in seconds): 1 Memory usage: Memory (current): 4.79MB Network usage: eth0: Bytes received: 730B Bytes sent: 1.59kB Packets received: 3 Packets sent: 14 lo: Bytes received: 0B Bytes sent: 0B Packets received: 0 Packets sent: 0Работа со снепшотами ^
В LXD имеется возможность создания снепшотов и восстановления из них состояния контейнера.
Чтобы создать снепшот, выполните следующую команду:
lxc snapshot alp snapshot1У команды lxc snapshot не имеется ключа list , поэтому, чтобы просмотреть список снепшотов нужно воспользоваться командой выводящей общую информацию о контейнере:
lxc info alp . . Snapshots: snapshot1 (taken at 2020/04/08 18:18 UTC) (stateless)Восстановить контейнер из снепшота можно командой lxc restore указав контейнер для которого будет произведено восстановление и псевдоним снепшота:
lxc restore alp snapshot1Следующая команда служит для удаления снепшота. Обратите внимание, что синтаксис команды не похож на все остальные, здесь необходимо указать прямой слеш после имени контейнера. Если слеш опустить, то команда удаления снепшота интерпретируется как команда удаления контейнера!
lxc delete alp/snapshot1В приведённом выше примере мы рассмотрели так называемые stateless-снепшоты. В LXD есть и другой тип снепшотов — stateful, в которых сохраняется текущее состояние всех процессов в контейнере. Со stateful-снепшотами связаны ряд интересных и полезных функций.
Удаление контейнера ^
Для удаления контейнера служит команда lxc delete , но прежде чем удалить контейнер, он должен быть остановлен с помощью команды lxc stop :
lxc stop alplxc list +------+---------+-------------------+------+-----------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+---------+-------------------+------+-----------+-----------+ | alp | STOPPED | 10.0.5.10 (eth0) | | CONTAINER | 0 | +------+---------+-------------------+------+-----------+-----------+После того как мы убедились, что состояние контейнера стало STOPPED, его можно удалить из Storage Pool:
lxc delete alpЭкспорт контейнеров ^
Чтобы вы не утратили плоды своих трудов в контейнерах, в LXD предусмотрена команда экспорта контейнера:
lxc export alp /backups/alp.tar.gz --instance-onlyЧто ещё? ^
- Вы можете подняться на следующий уровень запустив Jupyter на орбиту LXD
- Для Python разработчиков доступен модуль PyLXD который предоставляет API к LXD
UPDATE 10.04.2020 15:00: Добавил навигацию
UPDATE 11.04.2020 06:00: Исправил ошибки в тексте благодаря ребятам отписавшимся в личку. Спасибо огромное!
UPDATE 11.04.2020 07:30: Добавил информацию в раздел «Инсталляция LXD»
UPDATE 11.04.2020 08:40: Немного реорганизовал разделы, подправил и дополнил текст
UPDATE 14.04.2020 16:10: Добавил информацию о экспорте контейнеровУправление контейнерами с LXD: краткое введение
Продолжаем наш цикл статей о контейнеризации. Если предыдущие статьи были посвящены теории, то сегодня мы поговорим о вполне конкретном инструменте и об особенностях её практического использования. Предметом нашего рассмотрения будет LXD (Linux Container Daemon). LXD представляет собой надстройку над LXC, которая существенно упрощает работу с контейнерами и добавляет новые возможности.

Продолжаем наш цикл статей о контейнеризации. Если первые две статьи (1 и 2) были посвящены теории, то сегодня мы поговорим о вполне конкретном инструменте и об особенностях его практического использования. Предметом нашего рассмотрения будет LXD (сокращение от Linux Container Daemon), созданный канадцем Стефаном Грабе из компании Canonical.
Имя создателя LXD хорошо известно в профессиональном сообществе: он также является одним из авторв другого популярного контейнерного решения — LXC. Собственно, LXD представляет собой надстройку над LXC, которая упрощает работу с контейнерами и добавляет широкий спектр новых возможностей.
В рамках этой статьи мы ограничимся лишь кратким введением в LXD: сравним его с Docker, приведём инструкцию по установке и настройке, а также продемонстрируем базовые возможности управления контейнерами.
LXD и Docker
LXD — инструмент относительно новый: первая версия вышла в свет в 2014 году, когда Docker уже получил широкое распространение и хорошо зарекомендовал себя на практике.
Как и Docker, LXD функционирует на базе LXC.При этом cфера применения у двух инструментов совершенно разная: если Docker предназначен для запуска в контейнерах приложений, то LXD — для запуска полноценных операционных систем.
С помощью LXD можно создавать даже не контейнеры в буквальном смысле этого слова, а легковесные виртуальные машины. Чтобы подчеркнуть этот момент и одновременно указать на отличие от других инструментов контейнеризации, авторы многих публикаций называют LXD словом lightvisor (на русский язык его уже переводят как «легковизор»).
В публикациях Canonical отмечается, что LXD-контейнеры могут работать в 10 раз быстрее, чем традиционные виртуальные машины на базе KVM.
В LXD предпринята попытка решить целый ряд проблем, с которыми приходится сталкиваться при работе с другими инструментами контейнеризации: продуман механизм динамического управления ресурсами, расширены возможности миграции контейнеров (в том числе и в режиме реального времени), устранены проблемы безопасности. По сравнению с Docker у LXD гораздо шире возможности переконфигурации контейнеров.
LXD оснащён открытым API; имеются клиенты для различных языков программирования. Создан плагин для OpenStack, позволяющий управлять контейнерами с помощью клиента Nova.
Установка и настройка
Здесь и далее мы будем описывать особенности работы c LXD на материале Ubuntu 16.04. В этой ОС LXD включён в официальные репозитории и устанавливается стандартным способом:
apt-get install lxdСтефан Грабе в своей статье рекомендует в качестве бэкенда для хранения контейнеров использовать файловую систему ZFS. Чтобы работать с ZFS, нужно установить соответствующие пакеты:
apt-get install zfsutils-linuxЕсли ZFS вам по тем или иным причинам не подходит, вы можете воспользоваться BTRFS или LVM (подробнее об этом см. здесь ).
По завершении установки выполним команду:lxd initПрограмма настройки задаст несколько простых вопросов, после чего всё будет сконфигурировано автоматически. Подробнее об особенностях настройки LXD можно прочитать в этой статье .
Создание контейнера
Все контейнеры в LXD создаются на базе образов. Образы можно получить как из локального, так и из удалённого репозитория. Просмотрим список доступных репозиториев:
lxc remote list +-----------------+------------------------------------------+---------------+--------+--------+ | NAME | URL | PROTOCOL | PUBLIC | STATIC | +-----------------+------------------------------------------+---------------+--------+--------+ | images | https://images.linuxcontainers.org | lxd | YES | NO | +-----------------+------------------------------------------+---------------+--------+--------+ | local (default) | unix:// | lxd | NO | YES | +-----------------+------------------------------------------+---------------+--------+--------+ | ubuntu | https://cloud-images.ubuntu.com/releases | simplestreams | YES | YES | +-----------------+------------------------------------------+---------------+--------+--------+ | ubuntu-daily | https://cloud-images.ubuntu.com/daily | simplestreams | YES | YES | +-----------------+------------------------------------------+---------------+--------+--------+Для первого знакомства с LXD вполне подойдёт локальный репозиторий (local). Запустим в контейнере ОС Ubuntu 16.04:
lxc launch ubuntu:16.04 container1В результате выполнения этой команды LXD создаст на базе указанного образа контейнер и запустит его.
Запустить в этом контейнере командную оболочку можно с помощью команды:
lxc exec container1 /bin/bashЕсли нужно просто создать контейнер, но не запускать его, достаточно выполнить команду:
lxc init ubuntu:16.04 container1Для последующего запуска и остановки контейнера используются команды lxc start и lxc stop.
LXC предоставляет хорошие возможности для управления контейнерами «на лету». Вот так, например, можно поместить созданный на основном хосте файл внутрь контейнера:
lxc file push [путь к файлу на основном хосте] [контейнер]/[путь]Можно совершить и обратную операцию — загрузить файл из контейнера на основной хост
$ lxc file pull [контейнер]/[путь]Можно и редактировать файлы в контейнере напрямую:
lxc edit [контейнер]/[путь]Основные команды для создания и запуска контейнеров мы уже рассмотрели; желающих узнать больше отсылаем к подробной статье Стефана Грабе.
Управление ресурсами
Управление изолированными окружениями немыслимо без контроля ресурсов: мы должны предоставить контейнеру достаточное количество ресурсов для работы и в то же время быть уверенными в том, что контейнер не будет потреблять лишних ресурсов, нарушая тем самым работу остальной системы.
В LXD можно выделять контейнерам ресурсы при помощи специального набора команд:
# устанавливаем лимит памяти lxc config set container1 limits.memory 512M # привязываем контейнер к ядрам CPU lxc config set container1 limits.cpu 1,3 # ограничиваем потребление ресурсов CPU lxc config set container1 cpu.allowance 10% # ограничиваем объём используемого контейнером дискового пространства(работает только с ZFS или btrfs) lxc config set container1 root size 10GBБолее подробно почитать об управлении ресурсами можно в этой статье .
Просмотреть статистику потребления ресурсов для контейнера можно с помощью простой команды:
lxc info container1 Name: container1 Architecture: x86_64 Created: 2016/08/16 07:55 UTC Status: Running Type: persistent Profiles: default Pid: 4110 Ips: lo: inet 127.0.0.1 lo: inet6 ::1 eth0: inet6 fe80::216:3eff:fe18:faa9 vethA2SCMX Resources: Processes: 24 Memory usage: Memory (current): 48.88MB Memory (peak): 163.26MB Network usage: eth0: Bytes received: 648 bytes Bytes sent: 648 bytes Packets received: 8 Packets sent: 8 lo: Bytes received: 264 bytes Bytes sent: 264 bytes Packets received: 4 Packets sent: 4Работа со снапшотами
В LXD имеется возможность создания снапшотов и восстановления контейнеров из снапшотов. Посмотрим, как это работает на практике (пример взят из интерактивного туториала LXD ).
Внесём некоторые изменения в уже созданный нами контейнер container1:
lxc exec container1 -- apt-get update lxc exec container1 -- apt-get dist-upgrade -y lxc exec container1 -- apt-get autoremove —purge -yСделаем снапшот этого контейнера и назовём его, например, new:
lxc snapshot container1 newПопробуем что-нибудь «поломать» в нашем первом контейнере:
lxc exec container1 -- rm -Rf /etc /usrПоcле этого запустим в нём в нём командную оболочку:
lxc exec container1 -- bash I have no name!@container1:~#Выполним команду exit и вернёмся на основной хост. Восстановим работу контейнера container1 из снапшота:
lxc restore container1 newЗапустим командную оболочку в восстановленном контейнере:
lxc exec container1 -- bash root@container1:#Всё работает так же, как раньше!
В приведённом выше примере мы рассмотрели так называемые stateless-снапшоты В LXD есть и другой тип снапшотов — stateful, в которых сохраняется текущее состояние всех процессов в контейнере. Со stateful-снапшотами связаны ряд интересных и полезных функций.
Чтобы создавать stateful-снапшоты, нам понадобится установить программу CRIU (CheckPoint/Restore in Userspace). C её помощью можно сохранить текущее состояние всех процессов, а затем восстановить их хоть на текущей, хоть на другой машине.
В Ubuntu 16.04 утилита CRIU устанавливается при помощи стандартного менеджера пакетов:apt-get install criuПосле этого можно переходить к созданию снапшотов:
lxc snapshot container1 snapshot1 --statefulВ некоторых ситуациях такие снапшоты могут оказаться очень полезными. Представим себе, например, что нам нужно перезагрузить сервер, на котором запущены один или несколько контейнеров. Чтобы после перезагрузки не запускать всё заново, а продолжить с прерванного места, достаточно выполнить:
# перед перезагрузкой lxc stop container1 --stateful #после перезагрузки lxc start container1На базе stateful-снапшотов реализован механизм «живой» миграции контейнеров, который пока что находится в несколько «сыром» состоянии.
Заключение
LXD представляет собой удобную систему управления контейнерами, обладающую целым рядом полезных функций. Надеемся, что проект LXD будет успешно развиваться и займёт достойное место в ряду современных инструментов контейнеризации.
Если у вас есть практический опыт использования LXD — добро пожаловать в комментарии.Естественно, в рамках одной статьи рассказать обо всех функциях LXD вряд ли возможно. Для желающих узнать больше приводим несколько полезных ссылок:
- https://www.stgraber.org/2016/03/11/lxd-2-0-blog-post-series-012/ — цикл статей об LXD в блоге Стефана Грабе;
- http://vasilisc.com/lxd-2-0-series — перевод всех статей по предыдущей ссылке на русский язык;
- https://insights.ubuntu.com/2016/04/19/directly-interacting-with-the-lxd-api/ — статья-введение в LXD API;
- https://www.openstack.org/summit/vancouver-2015/summit-videos/presentation/lxd-vs-kvm — видеозапись доклада о перспективах использования LXD в OpenStack.
Что такое LXC/LXD

Опубликовано: 15.12.2022
платформа контейнеризации, использующая общее ядро хостовой операционной системы и позволяющая запускать изолированные операционные системы. LXC разработана в 2008 году Даниэлем Лескано, Сержем Айюном и Стефаном Грабе. Позже в 2014 году появилась более усовершенствованный вариант LXD.
LXC/LXD больше похожа на OpenVZ. В сравнении с другими популярными системами контейнеризации:
LXC/LXD Docker и Podman Позволяет использовать один контейнер для настройки многокомпонентного сервиса. Идейно, применяются по принципу один контейнер — один процесс. Перманентно хранит информацию. Данные удаляются после пересоздания контейнера. Контейнер больше похож на изолированную виртуальную машину. Имеет особый подход к управлению — часть возможностей может отсутствовать для оптимизации контейнера. LXC/LXD входит в репозиторий большинства популярных систем Linux и может быть установлен с помощью пакетного менеджера, таких как apt (Debian, Ubuntu) или yum/dnf (Rocky Linux, CentOS).
Еще немного о LXC на Википедии.