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


  • для разных языков нужны разные IDE и тулчейны;
  • в разных проектах могут использоваться разные версии тулчейнов и библиотек.

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


Конфигурация на примере Ubuntu 20.04.


Размышления о вариантах и причинах приведены в конце статьи.


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


В Ubuntu 20.04 LXD больше не доступен для установки как deb пакет, только через snap:


$ snap install lxd

После установки нужно выполнить инициализацию:


$ lxd init

Единственный параметр который я меняю, это storage bakend — я использую dir как самый простой. Так как снимки и копии я не использую, то предупреждения в документации меня не пугают:


Similarly, the directory backend is to be considered as a last resort option.
It does support all main LXD features, but is terribly slow and inefficient as it can't perform
instant copies or snapshots and so needs to copy the entirety of the instance's storage every time.

2. Настройка профиля LXD


Профили в LXD — это наборы параметров применяемых к нескольким контейнерам. Для моих нужд мне достаточно единственного созданного по умолчанию профиля default со следующими изменениями:


  • $ lxc profile device add default X0 disk source=/tmp/.X11-unix/X0 path=/tmp/.X11-unix/X0 — чтобы приложения в контейнерах могли взаимодействовать с хостовым X11 сервером;
  • $ lxc profile set default environment.DISPLAY :0 — чтобы переменная окружающей среды DISPLAY в контейнерах была установлена корректно;
  • $ lxc profile set default raw.idmap "both 1000 1000" — для правильного маппинга идентификаторов.

3. Создание и настройка контейнера


Создание контейнера на базе образа images:ubuntu/20.04:


$ lxc launch images:ubuntu/20.04 dev1

Я предпочитаю образы из репозитория https://images.linuxcontainers.org, так как в них меньше предустановленного софта. По этой причине я добавил префикс images: к имени образа. Создание контейнера на базе образа из репозитория Ubuntu можно выполнить следующим образом: $ lxc launch ubuntu/20.04 dev1.


Доступ к рутовому шелу контейнера:


$ lxc exec dev1 -- bash

Установлю Firefox и VS Code (из репозитория по инструкции):


$ apt update
$ apt install curl gpg firefox

$ curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > packages.microsoft.gpg
$ install -o root -g root -m 644 packages.microsoft.gpg /usr/share/keyrings/
$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list

$ apt update
$ apt install code

Включу контейнер для наглядности


poweroff

Бонус! Довольно просто пробросить GPU в контейнер для того, чтобы запускаемые в нем приложения могли пользоваться графической картой. Для этого нужно:


  • добавить устройство $ lxc config device add dev1 mygpu gpu;
  • установить в контейнере драйверы видеокарты — те же самые, что установлен на хосте.

4. Использование контейнера


В том случае, если контейнер еще не запущен, нужно его запустить:


lxc start dev1

Запуск VS Code от имени не привилегированного пользователя ubuntu:


lxc exec dev1 -- sudo --login --user ubuntu code

Запуск Firefox:


lxc exec dev1 -- sudo --login --user ubuntu firefox

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


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


5. Заключение


Я предпочитаю не использовать хостовую ОС для разработки, так как это потребовало бы установки инструментов разработки, отладочных версий библиотек, настройки компонентов системы специфическим образом и других манипуляций. Все это может приводить к неожиданному поведению остального, не связанного с разработкой, программного обеспечения, а то и всей ОС. К примеру изменения в конфигурации OpenSSL могут привести к тому, что ОС перестанет корректно запускаться.


Я пробовал разные средства для изоляции сред разработки:


  • виртуальные машины (KVM, VirtualBox и т.п.) — самый очевидный вариант, но потребляет значительно больше ресурсов, хотя для разработки под Windows (в том случае, если хост Linux) других вариантов нет;
  • инструменты облачной разработки запущенные на локальной машине (Cloud9 в контейнере или виртуальной машине, Eclipse Che и т.п.) — их разрабатывают не для такого режима работы, они требуют дополнительной настройки и сопровождения, лучше всего использовать их по назначению — в облаке;
  • контейнеры Docker — опять же предназначены для другого, на мой взгляд в них не очень удобно быстро прототипировать с применением того ПО, которое еще не упаковано в отдельные контейнеры.

Выбранный подход импонирует мне простотой и низким порогом вхождения. В самих контейнерах можно применять специфичные для проектов подходы: устанавливать и настраивать все вручную, либо применять автоматизацию (Puppet, Ansible и т.п.), даже разворачивать инфраструктуру на базе Docker. Я использую контейнеры LXD так же для запуска специфического ПО которое либо требует установки большого количества зависимостей, либо другой версии ОС — в этом случае можно создать контейнер с нужной версией ОС к примеру $ lxc launch images:ubuntu/16.04 dev16.


Важно помнить о том, что в разрезе изоляции контейнеризация имеет большую поверхность атаки по сравнению с виртуализацией — хост и контейнер делят одно ядро, уязвимость в котором может позволить вредоносному программному обеспечению сбежать из контейнера. Для экспериментов с сомнительным ПО лучше использовать более подходящие механизмы изоляции.


Полезные ссылки