Руководство по LXC и LXD: контейнеры без Docker

Docker совершил революцию в мире контейнеризации, но он не единственный игрок. LXC (Linux Containers) и его надстройка LXD предлагают другой подход: они позволяют запускать полноценные системы (как виртуальные машины), но без накладных расходов гипервизора. Если вам нужен «VPS внутри сервера» с полноценным init, системными службами и возможностью ставить любые пакеты — LXC/LXD может быть идеальным решением.

В этой статье мы подробно разберём:

  • Что такое LXC и LXD, чем они отличаются от Docker и виртуальных машин.
  • Архитектуру LXC/LXD.
  • Установку и первоначальную настройку.
  • Основные команды LXD: создание, управление, доступ к контейнерам.
  • Настройку сети, хранилищ и профилей.
  • Примеры: запуск веб-сервера, базы данных, снапшоты, миграцию.
  • LXD в production: кластеризация, отказоустойчивость.
  • Сравнение LXC/LXD с Docker и виртуальными машинами.
  • Частые ошибки и лучшие практики.

1. Что такое LXC и LXD

1.1 LXC (Linux Containers)

LXC — это технология контейнеризации на уровне операционной системы, которая использует возможности ядра Linux: cgroups (ограничение ресурсов) и namespaces (изоляция). LXC позволяет запускать несколько изолированных Linux-систем на одном хосте, используя общее ядро.

Ключевые особенности LXC:

  • Контейнер выглядит как полноценная Linux-система: свой init (systemd, sysvinit), свои пользователи, свои сетевые интерфейсы.
  • Можно установить любое ПО, которое работает в данной ОС.
  • Не требует гипервизора, как виртуальные машины.
  • Использует общее ядро хоста, но изолирует процессы, сеть, файловую систему.

LXC существует с 2008 года и изначально управлялся через набор утилит командной строки (lxc-create, lxc-start, lxc-attach и т.д.). Эти утилиты работают, но не очень удобны для массового управления.

1.2 LXD

LXD — это надстройка над LXC, которая предоставляет удобный API, клиент командной строки и инструменты для управления контейнерами. Важное дополнение: Начиная с 2024–2025 годов Canonical ужесточила лицензионную политику LXD, из-за чего большинство независимых Linux-дистрибутивов полностью исключили LXD из своих официальных репозиториев, заменив его на полностью открытый форк Incus. Хотя базовый синтаксис команд управления (lxc ...) у них совпадает, для долгосрочных open-source проектов сегодня рекомендуется выбирать именно Incus.

Что даёт LXD:

  • Простой и мощный CLI (lxc).
  • REST API для автоматизации.
  • Поддержка образов (Ubuntu, Debian, CentOS, Alpine и др.).
  • Снапшоты, бэкапы, миграция.
  • Кластеризация (несколько серверов LXD объединяются в кластер).
  • Профили для быстрой настройки контейнеров.
  • Хранилища (ZFS, Btrfs, LVM, директории).
  • Сетевые возможности (мосты, VLAN, маршрутизация).

Важно: LXD — это не замена Docker. Это другой инструмент для других задач. Docker упаковывает одно приложение, LXD запускает целую систему.

1.3 Отличия от Docker и виртуальных машин

КритерийLXC/LXDDockerВиртуальные машины
Что запускаетПолноценную ОСОдно приложениеПолноценную ОС
ЯдроОбщее с хостомОбщее с хостомСобственное
Initsystemd, sysvinitНет (один процесс)systemd, sysvinit
ИзоляцияВысокая (namespaces, cgroups)Высокая (namespaces, cgroups)Полная (гипервизор)
ЗапускСекундыМиллисекундыМинуты
Потребление ресурсовНизкоеОчень низкоеВысокое
ИспользованиеVPS, тестовые среды, CIМикросервисы, приложенияРазные ОС, полная изоляция
УправлениеLXD CLI/APIDocker CLI/APIlibvirt, VMware, Hyper-V

Когда выбирать LXC/LXD:

  • Нужен «VPS внутри сервера» с полноценной ОС.
  • Требуется запустить несколько изолированных сред для тестирования.
  • Нужна миграция контейнеров между серверами.
  • Хочется использовать привычные инструменты (apt, systemd) внутри контейнера.
  • Не нужна полная виртуализация (экономия ресурсов).

Когда выбирать Docker:

  • Нужно упаковать одно приложение.
  • Требуется микросервисная архитектура.
  • Важна скорость запуска и минимальный размер образа.
  • Нужна экосистема (Docker Hub, Compose, Swarm, Kubernetes).

ВАЖНО! По умолчанию LXD создаёт непривилегированные контейнеры — это безопасно, так как контейнер не имеет прав root на хосте. Если вам нужно запустить Docker внутри LXD или выполнить привилегированную операцию, включите: lxc config set mycontainer security.privileged true. Но делайте это только если понимаете риски.

2. Архитектура LXC/LXD

LXD состоит из нескольких компонентов:

  • LXD daemon — фоновый процесс, который управляет контейнерами. Слушает Unix-сокет и (опционально) сетевой порт.
  • LXC — низкоуровневая библиотека и утилиты для работы с контейнерами.
  • Клиент lxc — командная строка для взаимодействия с LXD daemon.
  • Образы — шаблоны систем (Ubuntu, Debian, CentOS, Alpine и др.), которые можно скачать и использовать.
  • Профили — наборы настроек (CPU, память, сеть, диски), применяемые к контейнерам.
  • Хранилища — места, где хранятся контейнеры (ZFS, Btrfs, LVM, directory).
  • Сети — мосты, VLAN, маршрутизация.

Как это работает:

  1. Вы запускаете lxc launch ubuntu:22.04 mycontainer.
  2. LXD скачивает образ, создаёт контейнер, применяет профиль по умолчанию.
  3. Контейнер запускается как изолированный процесс с собственным init.
  4. Вы можете подключаться к нему (lxc exec mycontainer bash), управлять пакетами, настраивать сеть.

3. Установка LXD

3.1 Установка на Ubuntu/Debian

В Ubuntu LXD доступен как snap-пакет (рекомендуется) или через apt.

Через snap (рекомендуется):

Bash
sudo snap install lxd

Через apt (для Debian):

Bash
sudo apt update
sudo apt install lxd

3.2 Установка на CentOS/RHEL/Rocky Linux

Bash
sudo dnf install epel-release
sudo dnf install lxd

3.3 Первоначальная настройка

После установки выполните:

Bash
sudo lxd init

Вас проведут через несколько вопросов:

  • Хранилище: выберите zfs (если доступно), btrfs, lvm или dir. Для тестов подойдёт dir.
  • Размер хранилища: по умолчанию.
  • Сеть: создайте новый мост lxdbr0 (рекомендуется).
  • IPv4/IPv6: можно оставить автоматически.
  • LXD в кластере: нет (для одного сервера).
  • Порт API: можно не включать, если не нужен удалённый доступ.

ВАЖНО! Обратите внимание, что lxd init можно запустить с флагом --auto и параметрами, чтобы не отвечать на вопросы интерактивно — это полезно для автоматизации (например, в cloud-init).

После завершения LXD готов к работе.

3.4 Добавление пользователя в группу lxd

Чтобы управлять LXD без sudo:

Bash
sudo usermod -aG lxd $USER
newgrp lxd

4. Основные команды LXD

4.1 Управление образами

Bash
# Список доступных образов
lxc image list images:

# Список локальных образов
lxc image list

# Копирование образа
lxc image copy images:ubuntu/22.04 local: --alias ubuntu22

4.2 Создание и запуск контейнеров

Bash
# Создать контейнер из образа
lxc launch ubuntu:22.04 mycontainer

# Создать, но не запускать
lxc init ubuntu:22.04 mycontainer

# Запустить остановленный контейнер
lxc start mycontainer

# Остановить
lxc stop mycontainer

# Перезапустить
lxc restart mycontainer

# Удалить
lxc delete mycontainer

4.3 Просмотр информации

Bash
# Список всех контейнеров
lxc list

# Подробная информация о контейнере
lxc info mycontainer

# Логи
lxc info mycontainer --show-log

4.4 Доступ к контейнеру

Bash
# Выполнить команду внутри контейнера
lxc exec mycontainer -- bash

# Или просто
lxc exec mycontainer bash

# Выполнить одну команду
lxc exec mycontainer -- apt update

# Скопировать файл из хоста в контейнер
lxc file push /path/on/host/file.txt mycontainer/path/in/container/

# Скопировать файл из контейнера на хост
lxc file pull mycontainer/path/in/container/file.txt /path/on/host/

4.5 Управление ресурсами

Bash
# Ограничить CPU (2 ядра)
lxc config set mycontainer limits.cpu 2

# Ограничить память (512 МБ)
lxc config set mycontainer limits.memory 512MB

# Посмотреть конфигурацию
lxc config show mycontainer

# Изменить конфигурацию
lxc config edit mycontainer

4.6 Снапшоты

Bash
# Создать снапшот
lxc snapshot mycontainer snap1

# Список снапшотов
lxc info mycontainer

# Восстановить из снапшота
lxc restore mycontainer snap1

# Удалить снапшот
lxc delete mycontainer/snap1

4.7 Клонирование

Bash
# Клонировать контейнер
lxc copy mycontainer mycontainer-clone

# Клонировать из снапшота
lxc copy mycontainer/snap1 mycontainer-clone

5. Настройка сети

5.1 Мост (bridge) — по умолчанию

При lxd init создаётся мост lxdbr0. Контейнеры получают IP из этого моста и имеют доступ в интернет через NAT.

Просмотр сети:

Bash
lxc network list
lxc network show lxdbr0

Настройка DHCP:

Bash
lxc network set lxdbr0 ipv4.dhcp.ranges 10.0.0.100-10.0.0.200

5.2 Проброс портов

Чтобы открыть порт контейнера наружу:

Bash
# Строгий синтаксис проброса портов в LXD (протокол tcp указывается явно)
lxc config device add mycontainer http proxy \
    listen=tcp:0.0.0.0:80 \
    connect=tcp:127.0.0.1:80

# Альтернативный, более современный и производительный способ через NAT (LXD 4.0+, требует OVN или статического IP)
lxc network forward create lxdbr0 192.0.2.1 target_address=10.0.0.50

ВАЖНО! Connect указывает адрес внутри контейнера. Если сервис слушает только на 127.0.0.1 внутри контейнера — это сработает. Если на конкретном IP — укажите его.

Теперь порт 80 на хосте будет перенаправляться на порт 80 в контейнере.

5.3 Использование macvlan

Если нужно, чтобы контейнер получил IP из вашей локальной сети (как отдельное устройство):

Bash
lxc config device add mycontainer eth0 nic nictype=macvlan parent=eth0

5.4 Статический IP

Bash
lxc config device override mycontainer eth0 ipv4.address=10.0.0.50

6. Хранилища

LXD поддерживает несколько типов хранилищ:

  • dir — обычная директория (просто, но медленно).
  • ZFS — продвинутая файловая система с снапшотами и дедупликацией.
  • Btrfs — похожа на ZFS, но проще.
  • LVM — логические тома.

Просмотр пулов:

Bash
lxc storage list
lxc storage show default

Создание нового пула:

Bash
lxc storage create mypool zfs

Использование пула для контейнера:

Bash
lxc launch ubuntu:22.04 mycontainer -s mypool

7. Профили

Профили позволяют задать общие настройки для группы контейнеров.

Создание профиля:

Bash
lxc profile create web
lxc profile edit web

Пример профиля для веб-сервера:

YAML
# Исправленный синтаксис профиля LXD (все значения конфигурации пишем строго в кавычках)
config:
  limits.cpu: "2"
  limits.memory: "1GB"
  boot.autostart: "true"
devices:
  eth0:
    name: eth0
    nictype: bridged
    parent: lxdbr0
    type: nic
  root:
    path: /
    pool: default
    type: disk

Применение профиля:

Bash
lxc launch ubuntu:22.04 webserver -p default -p web

8. Практические примеры

8.1 Запуск веб-сервера в контейнере

Bash
# Создание контейнера
lxc launch ubuntu:22.04 web1

# Вход в контейнер
lxc exec web1 bash

# Внутри контейнера:
apt update
apt install nginx
systemctl start nginx
systemctl enable nginx

# Выход
exit

# Проброс порта 80
lxc config device add web1 http proxy listen=tcp:0.0.0.0:80 connect=tcp:127.0.0.1:80

Теперь http://ваш_сервер откроет Nginx из контейнера.

8.2 Запуск базы данных

Bash
lxc launch ubuntu:22.04 db1
lxc exec db1 bash
apt update
apt install mysql-server
mysql_secure_installation
exit

# Проброс порта 3306 (только для локального доступа)
lxc config device add db1 mysql proxy listen=tcp:127.0.0.1:3306 connect=tcp:127.0.0.1:3306

ВАЖНО! Обратите внимание, что listen — это адрес на хосте, а connect — внутри контейнера.

8.3 Снапшот и восстановление

Bash
# Создание снапшота
lxc snapshot web1 before-update

# Обновление (что-то сломалось)
lxc exec web1 bash
apt upgrade -y
# ... всё сломалось ...
exit

# Восстановление
lxc restore web1 before-update

8.4 Миграция контейнера на другой сервер

Bash
# На сервере-источнике
lxc remote add backup-server 192.168.1.100

# Копирование контейнера
lxc copy web1 backup-server:web1

# На сервере-приёмнике
lxc start web1

ВАЖНО! На сервере-приёмнике выполните lxc config set core.https_address :8443 и задайте пароль доверия: lxc config set core.trust_password secret. При lxc remote add вам будет предложено ввести этот пароль.

9. LXD в production

9.1 Кластеризация

Рассмотрим кластер из двух узлов: node1 (192.168.1.10) и node2 (192.168.1.11). Для простоты используем локальные хранилища (без Ceph), что подойдёт для знакомства и тестирования.

Шаг 1. Настройка первого узла (node1)

На первом узле запускаем инициализацию с параметрами кластера:

Bash
# ПРАВИЛЬНО: Строгая структура YAML preseed для автоматической инициализации кластера LXD
lxd init --preseed <<EOF
config:
  core.https_address: 192.168.1.10:8443
  core.trust_password: "secret-cluster-pass"
cluster:
  server_name: node1
  enabled: true
  member_config: []
networks: []
storage_pools: []
profiles: []
EOF

Здесь:

  • core.https_address — адрес, на котором LXD принимает подключения от других узлов.
  • core.trust_password — пароль для присоединения новых узлов к кластеру.
  • server_name — имя узла в кластере.

Шаг 2. Получение токена для второго узла

На первом узле генерируем токен присоединения:

Bash
lxc cluster add node2

Вывод будет примерно таким:

Этот токен нужен на втором узле.

Шаг 3. Настройка второго узла (node2)

На втором узле запускаем инициализацию и выбираем присоединение к кластеру:

Bash
lxd init

На вопросы отвечаем так:

LXD свяжется с первым узлом, проверит токен и добавит node2 в кластер.

Шаг 4. Проверка кластера

На любом узле:

Bash
lxc cluster list

Шаг 5. Создание контейнера на конкретном узле

Bash
# Создать контейнер на node1
lxc launch ubuntu:22.04 web1 --target node1

# Создать контейнер на node2
lxc launch ubuntu:22.04 web2 --target node2

# Посмотреть, где работают контейнеры
lxc list

Шаг 6. Перемещение контейнера между узлами

Для живой миграции нужно, чтобы оба узла использовали общее хранилище (Ceph, или NFS). С локальными хранилищами миграция работает только в остановленном состоянии:

Bash
# Остановить контейнер
lxc stop web1

# Переместить на node2
lxc move web1 --target node2

# Запустить на новом узле
lxc start web1

Для живой миграции (без остановки контейнера) требуется распределённое хранилище — Ceph или общий блочный накопитель. С локальными хранилищами (ZFS, Btrfs, dir) миграция возможна только в остановленном состоянии: контейнер переносится копированием.

Кворум: кластер LXD использует базу данных Raft. Для отказоустойчивости нужно минимум 3 узла с ролью database, иначе при потере одного узла кластер перестанет принимать изменения (split-brain). Два узла достаточно для знакомства, но не для production.

ВАЖНО! Полная настройка кластера выходит за рамки этой статьи. См. официальную документацию LXD Clustering.

9.2 Отказоустойчивость

LXD может автоматически перезапускать контейнеры на других узлах при отказе сервера (с использованием Ceph или распределённого хранилища).

9.3 Мониторинг

LXD предоставляет метрики через API. Можно использовать Prometheus и Grafana для мониторинга контейнеров.

9.4 Резервное копирование

Bash
# Экспорт контейнера в файл
lxc export web1 web1-backup.tar.gz

# Импорт
lxc import web1-backup.tar.gz

10. Сравнение LXC/LXD с Docker и VM

КритерийLXC/LXDDockerВиртуальные машины
Запуск ОСПолноценная ОСОдно приложениеПолноценная ОС
ЯдроОбщееОбщееСобственное
InitsystemdНетsystemd
Скорость запускаСекундыМиллисекундыМинуты
Потребление RAMНизкоеОчень низкоеВысокое
ИзоляцияВысокаяВысокаяПолная
МиграцияДаОграниченноДа
КластеризацияДаSwarm/K8sДа
ИспользованиеVPS, тесты, CIМикросервисыРазные ОС
СложностьСредняяНизкаяВысокая

11. Частые ошибки и лучшие практики

ОшибкаПоследствияРешение
Недостаточно правОшибка доступа к LXDДобавьте пользователя в группу lxd.
Сеть не настроенаКонтейнер без интернетаПроверьте lxc network list, настройте lxdbr0.
Нет проброса портовСервис недоступен извнеИспользуйте lxc config device add ... proxy.
Хранилище dir для productionМедленно, нет снапшотовИспользуйте ZFS или Btrfs.
Нет лимитовКонтейнер съедает все ресурсыУстановите limits.cpu, limits.memory.
Нет бэкаповПотеря данныхНастройте lxc export по cron.
Игнорирование обновленийУязвимостиРегулярно обновляйте LXD и контейнеры.
Запуск Docker внутри LXD*Конфликты, сложностиНе рекомендуется, если не уверены.

* Если вам действительно необходимо запустить Docker внутри непривилегированного контейнера LXD (оркестрация в контейнере), не делайте контейнер привилегированным. Вместо этого включите поддержку вложенности и виртуализации одной безопасной командой: lxc config set mycontainer security.nesting true.

Лучшие практики:

  • Используйте ZFS или Btrfs для production.
  • Настраивайте профили для типовых контейнеров.
  • Делайте снапшоты перед обновлениями.
  • Ограничивайте ресурсы.
  • Мониторьте состояние контейнеров.
  • Регулярно обновляйте LXD и образы.
  • Документируйте конфигурацию.

Docker и LXD не конкурируют, а дополняют друг друга. Docker — для приложений, LXD — для систем. Освоив оба инструмента, вы сможете выбирать подходящий для каждой задачи.

👤 Зарегистрируйтесь, чтобы добавить материал в закладки.