null

Основы LXD

LXD является следующей итерацией LXC, которая предоставляет новый CLI.
При этом, LXD -- это не переписанный LXC. Де-факто, он использует liblxc
для управления linux контейнерами. Наряду с контейнерами, LXD позволяет создавать и
QEMU KVM виртуальные машины, что может быть полезно, например, при необходимости
изменять параметры ядра в контейнере.

Основные преимущества LXD:

  • Интуитивно понятный интерфейс
  • Частообновляемые образы ОС
  • Гибкий контроль потребления ресурсов
  • Возможность пробросить устройство в ВМ (USB, GPU, NIC, и другие)
  • Гибкое управление сетью и хранилищами

Установка LXD

Установить LXD очень просто:

snap install lxd

И после этого, нам необходимо провести базовую конфигурацию.
Выполним команду:

lxd init

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

Would you like to use LXD clustering? (yes/no) [default=no]: no

Отвечаем нет, поскольку мы конфигурируем LXD в standalone режиме.
LXD clustering позволяет конфигурировать высокодоступные кластеры, требуется минимум 3 LXD сервера.

Далее, создаем новый zfs pool где будут храниться данные наших контейнеров и ВМ.

Do you want to configure a new storage pool? (yes/no) [default=yes]: yes
Name of the new storage pool [default=default]: default
Name of the storage backend to use (btrfs, dir, lvm, zfs) [default=zfs]: zfs
Create a new ZFS pool? (yes/no) [default=yes]: yes
Would you like to use an existing block device? (yes/no) [default=no]: no
Size in GB of the new loop device (1GB minimum): 128

На вопрос о MAAS (Metal As A Server) отвечаем no, поскольку конфигурируем LXD в standalone режиме:

Would you like to connect to a MAAS server? (yes/no) [default=no]: no

Далее последуют вопросы о конфигурации сетевого моста для контейнеров.
Используя его все контейнеры получают свой приватный IP адрес, они могут обмениваться данными
друг с другом внутри этой сети и обращаться в интернет.

Would you like to create a new local network bridge? (yes/no) [default=yes]: yes
What should the new bridge be called? [default=lxdbr0]: lxdbr0
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: 10.30.0.1/24
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]: none

Здесь мы задали подсеть IP из которой будут назначаться нашим контейнерам и отключили IPv6.

Мы не будем пользоваться LXD демоном по сети:

Would you like LXD to be available over the network? (yes/no) [default=no]: no

Разрешаем автоматически обновлять устаревшие образы ОС:

Would you like stale cached images to be updated automatically? (yes/no) [default=yes] yes

И, наконец, имеется возможность сохранить получившуюся кофигурацию LXD в YAML формате, которой мы пользоваться не будем:

Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]: no

Теперь LXD полностью сконфигурирован и можно создавать свой первый контейнер!

Первый LXD контейнер

Для начала нужно определиться с образом контейнера который мы хотим развернуть.
Список доступных образом можно получить так:

lxc image list images:

Предположим, мы выбрали debian/bullseue, в таком случае контейнер можно запустить так:

lxc launch images:debian/bullseye NAME

После завершения этой команды, можем посмотреть список всех контейнеров/ВМ:

# lxc list
+------+---------+--------------------+------+-----------------+-----------+
| NAME |  STATE  |        IPV4        | IPV6 |      TYPE       | SNAPSHOTS |
+------+---------+--------------------+------+-----------------+-----------+
| NAME | RUNNING | 10.30.0.11 (eth0)  |      | VIRTUAL-MACHINE | 0         |
+------+---------+--------------------+------+-----------------+-----------+

Наконец, запустим shell в контейнере:

lxc exec NAME -- /bin/bash

Первая LXD VM

Немногим сложнее создать первую ВМ с LXD. Для этого нам понадобится создать свой
LXD профиль:

lxc profile create vm

Далее создаем текстовый файл lxd-vm.yaml со следующим содержимым:

config:
  user.user-data: |
    #cloud-config
    ssh_pwauth: no
    ssh_authorized_keys:
      - "ssh-rsa AAAAB..."

    growpart:
      mode: auto
      devices: ['/']
      ignore_growroot_disabled: false
description: LXD profile for virtual machines
devices:
  eth0:
    nictype: bridged
    parent: lxdbr0
    type: nic
  config:
    source: cloud-init:config
    type: disk
  root:
    path: /
    pool: default
    type: disk
name: vm
used_by: []

Здесь Вам понадобится поменять 6ю строку на свой публичный ключ. Их может быть
несколько, просто добавьте для каждого новый элемент в массив ssh_authorized_keys.
Это необходимо, чтобы у нас была возможность залогиниться в нашу новую ВМ, поскольку команда
lxc exec работает только для контейнеров. 

Загружаем получившуюся конфигурацию в созданный профиль:

lxc profile edit vm < lxd-vm.yaml

И создаем виртуальную машину(разумеется, вместо ubuntu:20.04 можете выбрать любой другой образ):

lxc init --vm ubuntu:20.04 NAME -p vm

Static IP for VM/container

Если Вам не нравится назначенный автоматически IP, его можно задать вручную:

lxc stop NAME
lxc network attach lxdbr0 NAME eth0 eth0
lxc config device set NAME eth0 ipv4.address IP_ADDRESS
lxc start NAME

Контейнер/VM можно и не перезапускать, но для этого понадобится внутри
контейнера/VM вручную вызвать dhclient.

Ограничение ресурсов для контейнера/ВМ

Размер корневого раздела можно ограничить так:

lxc config device override NAME root size=64GB

Количество ядер CPU:

lxc config set NAME limits.cpu 4

Объем оперативной памяти:

lxc config set NAME limits.memory 16GB

CPU allowance. Позволяет ограничить выделяемое процессорное время на контейнер:

lxc config set NAME limits.cpu.allowance 80%

Снапшоты

Снапшоты позволяют быстро и практически "бесплатно" заморозить состояние VM/контейнера,
чтобы потом можно было к нему откатиться.

Сделать снапшот очень просто:

lxc snapshot CONTAINER_NAME SNAPSHOT_NAME

Если мы что-то сломали в нашем контейнере, можно откатиться к нужному состоянию:

lxc restore CONTAINER_NAME SNAPSHOT_NAME

Удалить снапшот:

lxc delete CONTAINER_NAME/SNAPSHOT_NAME

Посмотреть список снапшотов, как и всю более детальную информацию о контейнере/ВМ:

lxc info CONTAINER_NAME

Удаление контейнера/ВМ

Будьте осторожны! Эта операция необратима!

lxc delete CONTAINER_NAME

Поздравляю! Мы установили LXD, научились управлять контейнерами и даже виртуальными машинами.

Бонус

Еще в качестве бонуса несколько полезных команд, которыми я часто пользуюсь.

Иногда возникает необходимость создать общий каталог для нескольких контейнеров.
В таком случае, вместо NFS можно просто примонтировать директорию с хостовой ОС
в контейнеры. Это можно сделать следующим образом:

lxc config device add CONTAINER_NAME sharedtmp disk \
                  path=/tmp/share_on_guest source=/tmp/share_on_host

где sharedtmp -- имя устройства типа disk которое будет создано и примонтировано.

Здесь следует знать, что в целях безопасности в LXD контейнерах используется UID И GID
смещение в 1000000. Таким образом, у пользователя root в контейнере будет UID 0, а
у того же пользователя на хостовой ОС -- 1000000.
Поэтому после создания устройства, нам может понадобиться изменить владельца каталога на
хостовой ОС:

chown -R 1000000:1000000 /tmp/share_on_host

Еще пара полезных команд позволяющих загрузить/выгрузить из контейнера файл.
Из контейнера на хостовую ОС:

lxc file pull CONTAINER_NAME/path-in-container path-on-host

С хостовой ОС в контейнер:

lxc file push path-on-host CONTAINER_NAME/path-in-container

Добавьте ключ -r если нужно рекурсивной загрузки (для каталогов).