LXC vs VM для докера и не только

Вышла версия Proxmox VE 9.1

Не зря я обратил внимание на новые опции в lxc

  1. В CT Templates скачиваем образ из OCI репы (аутентификация не поддерживается)
  2. Видим архив с образом
  3. При создании контейнера выбираем
  4. В опциях контейнера видим, что данные параметры были скопированы из контейнера
  5. В настройках сети видим галочку Host-Managed (она автоматически включится при создании контейнера если PVE пойдем, что это OCI образ)
    image
    Дело в том, что docker изначально не поддерживает настройку сети самим контейнером, поэтому, PVE назначает IP адрес самостоятельно и прокидывает в контейнер уже настроенный сетевой интерфейс

Я Обнаружил, что в версии PVE 9.1.1 IPv6 работает не совсем корректно, при попытке включить SLAAC ругается, а при Static и пустых полях должен отсутствовать IPv6 адрес, а он получен по SLAAC, в общем, ждем допиливаний.

  1. Запускаем LXC контейнер и видим
  2. Собственно, мы видим, что не зря нам ранее дали возможность просмотра IP адресов

Это все было в рамках подготовки к запуску Docker контейнеров в LXC

Смотрим на ресурсы, которые потребляет наша LXCшка


a man wearing a white shirt that says la riviera

Думаете все хорошо?

a man wearing a white shirt that says la riviera

В опциях консоль не через tty, а console, что логично

Думаете работает консоль?

На самом деле работает, но не как консоль, а как вывод stdout контейнера без интерактивного режима

Меняем консоль на shell и заводится

Давайте рассмотрим минусы данного решения

  1. Нет docker-compose, нет даже docker cli
  2. Только 1 процесс, нет ssh, нет нескольких контейнеров через docker compose, чтобы все это работало надо добавлять какой-то init процесс, который бы уже был родительским для остальных, т.е. по сути, собирать LXC контейнер
  3. Нет overlayfs, по сути, это подход микротика, когда все слои распаковываются в одно место, все конфиги правятся прямо на лету, т.к. смотрим следующий пункт
  4. Тут нет разделения на контейнер и о образ, если в докере мы делаем docker pull && docker stop && docker rm && docker run, то тут просто удалять LXC контейнер со всеми данными и создавать новый, либо же, написать баш скрипт, который скачивает docker образ куда-то, останавливает и монтирует rootfs контейнера, потом копирует файлы из одного места в другое, но с учетом волюмов (смотрим следующий пункт)
  5. Нет волюмов, по сути, это уже не stateless а stateful контейнер, если надо хранить пользовательские файлы, то пробрасываем каталог стандартной “матрешкой” mp0: /host/path,mp=/container/path
  6. Нет вменяемого API по работе с этим
  7. Ну и в целом, очень много ограничений данного решения, но с другой стороны, это еще один вариант запуска, он может пригодиться кому-то + можно же собирать свои кастомные докер образы, которые будут обновляемые и к какими-то своими фишками.

Есть еще вариант обновления контейнеров

  1. Создаем новый LXC контейнер с новой версией
  2. Удаляем старый LXC контейнер со старой версией

Тут мы понимаем, что все персистентные данные нам надо выносить в точки монтирования

Если мы обращаемся к контейнеру по сети, то надо как-то перенаправить клиентов на новый адрес, тут первое, что приходит в голову, это какой-то service-discovery, но с ними у нас большие проблемы

  1. Из коробки мы имеем только DHCP, в теории можно попробовать как-то его использовать
  2. Consul и прочие не будут работать т.к. нам нужен клиент, а тут не поды, а контейнеры, с подами было бы чуть легче
  3. Docker api у нас тоже нет, можно было бы натравить какой-нить traefik или типа того, реализовать куберовский оператор, в общем
  4. Остаются веб-хуки самого PVE, можно в конфиг добавить вызов скрипта при старте или остановке контейнера, этот скрипт может дергать serivce-discrovery для обновления
  5. Ну и мы же не будем руками создавать и удалять контейнеры? Скорее всего, у нас будет какой-нить terraform или ansible, который будет создавать нам контейнеры, в нем же тогда можно и дергать service-discovery провайдера
  6. Опционально, можно прикрутить скрипт, который будет получать список контейнеров и по тегам раскидывать контейнеры по сервисам
  7. Ну и можно попробовать поковырять SDN + IPAM, тут в рамках 1 проекта/неймспейса можно создать отдельную подсеть с IPAM
  8. Ну и мы должны понимать, что в данном случае у нас контейнеры все будут висеть в одном списке, если в кубере у нас есть несколько уровней организации, то тут только 1, максимум, что можем разные бриджи завести чере SDN

И и главный вопрос тогда: а оно вам надо? по сути, это будет попытка собрать кубер из :shit: и :crutch:

Тогда уже проще поднять кубер и получить все из коробки.

Уточнение

Самый главный момент
Это не запуск Docker напрямую в PVE
Это просто конвертация Docker образа в формат rootfs LXC + мелкие допилы типа кастомного entrypoint вместо /bin/init и передачи переменных окружения

Для себя вижу только 1 вариант: попробовать собрать минималистичную систему для запуска podman на основе libc т.к. пока с LXC шаблонами у меня не очень хорошо пошли дела и насколько я понял из общения с GPT, то там все равно шаблон надо собирать на основе docker образов

Еще вижу еще несколько вопросов:

  1. Нет аутентификации для OCI, тут либо ждать добавления данного функционала в PVE, либо идти по пути (на который намекнули сами Proxmox) подготовки архива своими силами и отправки его в хранилище. Тут я вижу добавление в CI/CD отдельного шага, который будет выполнять что-то типа skopeo copy docker-daemon:my-app:1.2.3 oci:my-app_1.2.3 && tar -czf my-app_1.2.3.tar.gz -C my-app_1.2.3 . && scp my-app_1.2.3.tar.gz proxmox:/var/lib/vz/templates/cache/
  2. В docker-compose (ну и docker) есть restart: unless-stopped/always, непонятно, как поведет себя PVE при вылете entrypoint, по идее просто выставит ошибку контейнеру и не будет пытаться загрузить его снова
  3. Docker менеджеры типа Dockge, Portainer, Komodo, Arcane, DockPort, Watchtower идут лесом, остается Pulse и еще парочка, которых сильно меньше
  4. Sidecar/agents, похоже идут лесом, пока не придумал как организовать
  5. Не совсем понятно, что делать с логами, как их вообще можно смотреть за претелами текущего noVNC буфера

Будем посмотреть