Всем привет! Наша небольшая команда из компании Tourmaline Core работала над проектом, тесно связанным с Embedded‑разработкой. Нам нужно было написать библиотеку, которая запускается на устройствах с процессорами на ARM платформе. И тут в наш офис зашел большой слон по имени «А как», потому что было не очевидно, как нам лучше вести разработку на используемой нами платформе (x86) под целевую платформу (ARM).

Какие есть решения:

  1. Самое очевидное — начать устанавливать кросс‑компиляторы и другие инструменты для разработки локально. Нам нужно разрабатывать на C++, так что установим Cygwin, на него устанавливаем все нужные нам библиотеки и компиляторы, устанавливаем MSYS2, настраиваем его так, чтобы он использовал инструменты из Cygwin. А теперь повторяем это на компьютере всех разработчиков в команде! Так дело не пойдет: слишком много действий и велик процент ошибиться и установить что‑то не то.

  2. Можно настраивать все это на одном компьютере, к которому через SSH будут подключаться разработчики. Подобная машина называется Build Server. Звучит уже лучше, но требует отдельный сервер и хорошее интернет соединение.

  3. Наша финальная идея — контейнерная разработка на компьютере каждого разработчика с помощью Docker. Мы пытались реализовать это различными способами, но наиболее оптимальным из них нам показался dev контейнер: вся команда использовала один и тот же конфигурационный файл для запуска контейнера, и, впоследствии, каждый разработчик имел готовую среду разработки со всеми необходимыми тулчейнами и зависимостями у себя на компьютере.

В данной статье мы поговорим про третье решение и расскажем, что такое dev контейнер, опишем процесс его настройки и приведем несколько практических примеров использования dev контейнеров. 

Что такое dev контейнер?

Терминология dev контейнер введена разработчиками среды VS Code. По сути, это просто название расширения, той же терминологии поддерживается и Visual Studio. Оба тулчейна основаны на единой спецификации, которая, по нашему мнению, в ближайшем времени будет использоваться и другими средами разработки. Например, сейчас dev контейнер есть также в Visual Stidio и в Clion.

Ну, а если более конкретно, то dev контейнер — это Docker контейнер, настроенный так, чтобы вести в этом контейнере полноценную разработку. Dev контейнеры настраивают:

  • Операционную систему

  • Компиляторы

  • Инструменты разработки и расширения

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

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

Dev контейнеры полезны и при разработке под платформы, архитектура которых отлична от используемой разработчиком. Тут есть два варианта:

  1. Настроить dev контейнер в качестве эмулятора под таргетную платформу и работать в ней напрямую.

  2. Разрабатывать в dev контейнере на целевой платформе (в нашем случае, x86), а тестирование проводить на других платформах (ARM).

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

Архитектура

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

Архитектура dev контейнера
Архитектура dev контейнера

Итак, мы видим две части: слева — локальная машина, справа — docker контейнер.

Что у нас находится на локальной машине? В первую очередь это, конечно же, исходный код проекта, над которым мы хотим работать внутри контейнера. Также там лежат все необходимые для разработки улучшения и кастомизации среды разработки и, в общем‑то, всё, что душа желает. Можете даже белую тему поставить, никто не осудит, так как это останется только между вами и вашей локальной машиной ?. Ну а в качестве UI для общения со средой разработки выступает всеми (не)любимый (на ваше усмотрение) VSCode. Расширение Dev Containers уже само прокидывает необходимые порты для общения IDE с контейнером, а также любезно делится исходными файлами проекта, чтобы вам вручную не приходилось прописывать копирование файлов в Dockerfile.

Контейнер выступает сердцем разработки, он — и жнец и на дуде игрец, ну вы знаете. Имеется доступ к файловой системе, доступ к консоли, также если вы устанавливали в контейнер компиляторы/интерпретаторы, то к ним тоже есть возможность обратиться, чтобы собирать/запускать ваше приложение. Дебажить код тоже можно (но не без проблем). Все эти команды он выполняет благодаря установленной серверной части VSCode внутри контейнера, которая принимает запросы с UI, т. е. с VSCode на локальной машине.

Преимущества dev контейнеров

Итак, подытожим преимущества использования dev контейнеров:

  • Работа в изолированной среде

  • Возможность вести разработку на целевой платформе

  • Возможность делиться настройками среды разработки между командой

  • Синхронизация контейнера и операционной системы платформы, в которой ведется разработка

Недостатки dev контейнера

Но без недостатков не обошлось:

  • Dev контейнер, взаимодействуя с локальной системой, совершает множество движений, нагружающих систему: синхронизация локальных файлов и файлов в контейнере и связанные с этим накладные расходы при преобразовании файловой системы (если внутри контейнера запущен Linux, а разработка идет на Windows).

  • Компьютер, на котором запускается dev контейнер, должен быть мощным. Чем он мощнее, тем комфортнее работать в dev контейнере.

  • Сборка проекта в dev контейнере происходит несколько медленнее, чем локально. В особенности это наблюдается в Windows. Почему так происходит? Мы не разобрались, но будем рады почитать ваши идеи в комментариях.  

Производительность

Мы подготовили абстрактные приложения, призванные проверить эффективность и целесообразность использования dev контейнеров (также доступны в нашем репозитории). 

Вот время сборки проекта с использованием dev контейнера:

ОС

Время сборки

Windows

4 min

Linux

20 sec

MacOS

1 min 5 sec

А вот что у нас получилось локально:

ОС

Время сборки

Windows

40 sec

Linux

17 sec

MacOS

50 sec

Тут видно невооруженным глазом, что dev контейнеры хоть и немного, но уступают в производительности стандартным подходам. Все эти проблемы с производительностью связаны с недостатками описанными выше.

P. S. все действия проводились со следующими характеристиками системы:

  • Windows — AMD Ryzen 5 2400G with Radeon Vega Graphics 4-core, 32Gb RAM

  • Linux — AMD Ryzen 7 3700x 8-core, 16 Gb RAM

  • MacOS — Intel Core i7 4-core, 2.6ghz, 16 Gb RAM

Настройка dev контейнера

Создание dev контейнера почти не отличается от создания обычного docker контейнера, для начала работы также нужно создать Dockerfile с описанием среды, в которой будет проводиться разработка. Этот файл понадобится для запуска dev контейнера. По мере работы над проектом можно изменять Dockerfile (в VS Code можно также изменять файл настроек devcontainer.json). Написанным Dockerfile»ом можно делиться с командой, и после запуска dev контейнера на его основе, изменения отобразятся и в их средах. Если вы не хотите писать конфиг контейнера самостоятельно, его можно выбрать из предложенных вариантов при запуске контейнера, главное выбрать базовый образ, на основе которого вы хотите работать.

На этом настройка Docker образа для dev контейнера окончена.

Для демонстрации работы dev контейнеров, мы написали простое C++ приложение, выводящее в консоль «Hello, Docker!», репозиторий вы можете найти тут.

Подключение к dev контейнеру

Для настройки dev контейнера в VS Code необходимо иметь:

  • плагин для работы с dev контейнерами — Dev Containers.

  • Dockerfile (опционально, можно выбрать уже существующую конфигурацию)

Как запуститься? Довольно просто! После установки расширения в левом нижнем углу появится зеленая кнопка «Open a Remote Window».

Нажимаем на кнопку в левом углу
Нажимаем на кнопку в левом углу

После нажатия на нее, открывается меню расширения. Выберем опцию «Reopen in Container» в выпадающем сверху списке. Далее появится выбор способов добавления конфигурации. Выберем опцию «From Dockerfile», если он у вас есть, ну а если нет, то выбираем из предустановленных конфигураций. VS Code предложит установить дополнительные расширения, нажимаем ОК.

Выбираем способ открытия контейнера
Выбираем способ открытия контейнера

Теперь проект готов к сборке! Сборка dev контейнера может занять некоторое время. Убедиться в том, что проект запущен в dev контейнере, можно по зеленой иконке в левом нижнем углу.

Мы в контейнере!
Мы в контейнере!

В VS Code можно дополнительно настроить dev контейнер через файл devcontainter.json. Он позволяет кастомизировать вашу рабочую среду, например, устанавливать расширения, прокидывать порты, менять конфигурацию и так далее. 

В нашем проекте используется стандартный автоматически генерируемый при запуске контейнера файл, вот как он выглядит:

{
	"name": "Existing Dockerfile",

	// Sets the run context to one level up instead of the .devcontainer folder.
	"context": "..",

	// Update the 'dockerFile' property if you aren't using the standard 'Dockerfile' filename.
	"dockerFile": "../Dockerfile",
	"customizations": {
		"vscode": {
			"extensions": [
				"ms-vscode.cpptools",
				"ms-vscode.cmake-tools",
				"twxs.cmake"
			]
		}
	}
}

Расширения можно вручную добавлять в dev контейнер, прописав название расширения в список extensions или найти нужное расширение в поисковике расширений VSCode и выбрать пункт «Добавить в devcontainter.json».

Добавляем что хотим в контейнер одним кликом
Добавляем что хотим в контейнер одним кликом

Запуск Github репозитория в dev контейнере

Готовый проект с настроенным dev контейнером на Github, можно открыть в dev контейнере в VS Code, даже без клонирования его в локальную систему. Это может пригодиться во многих ситуациях: когда проекту нужно ревью; когда при разработке необходимо исследовать другую ветку проекта, при этом на нее не переключаясь. При этом пользователю, открывающему проект в dev контейнере, не нужно волноваться о клонировании репозитория, настройке тулчейнов и расширений.

Чтобы запустить Github репозиторий в dev контейнере, откройте меню расширения Dev Containers (зеленая кнопка в левом нижнем углу) и выберете пункт «Clone Repository in Container Volume», после чего введите ссылку на репозиторий.

Клонируем репозиторий в dev контейнер
Клонируем репозиторий в dev контейнер

Для открытия проекта в локальной системе (например, чтобы было удобнее работы с git), нужно сначала склонировать репозиторий. После чего можно открывать проект как в контейнере, так и на локальной системе.

Запуск dev контейнера в браузере

Возможно, вы уже слышали про GitHub Codespaces — облачную среду разработки. Так вот, она также основана на dev контейнерах!

Codespace
Codespace

Dev контейнеры в Clion

Dev контейнер доступен также и в Clion начиная с версии 2022.2.3. В версиях ниже можно использовать подключение контейнера по SSH. Мы приведем инструкции для работы в Clion версии 2022.2.3.

docker build -t "dev-container-application" .

Теперь перейдем к настройке Clion — настроим Toolchain.

  1. Переходим в настройки Clion (File → Settings или Clion → Preferences для MacOS).

  2. Вкладка «Build, Execution, Deployment».

  3. Вкладка «Toolchains».

  4. Добавляем новый toolchain, нажав на иконку +. В выпадающем списке выбираем «Docker».

  5. Указываем в поле Image имя созданного ранее Docker образа (в нашем случае, dev‑container‑application).

  6. Переносим созданный toolchain наверх списка.

Настраиваем dev контейнеры в Clion
Настраиваем dev контейнеры в Clion

Далее необходимо убедиться, что профили во вкладке Cmake указывают на дефолтный toolchain. Переключая дефолтный toolchain, мы переключаемся между работой в dev контейнере (Docker как дефолтный toolchain) и работой на целевой платформе (другой toolchain как дефолтный. Мы используем MinGW).

Настраиваем тулчейны в Clion
Настраиваем тулчейны в Clion

Настройка Dev контейнера для CMake закончена.

Чтобы обновить конфигурацию проекта, щелкните на CMakeLists.txt и выберите «Load Cmake Project».

Собрать и запустить приложение в Clion можно через графический интерфейс. При запуске кроссплатформенного приложения, эмулятор вызывается автоматически и приложение запускается.

$ cmake-build-debug/DevContainerApplication-temp
Hello, Docker!

Проверить, под какую платформу было собрано приложение в Clion можно через  дистрибутив WSL.

$ file cmake-build-debug/DevContainerApplication-temp
cmake-build-debug/DevContainerApplication-temp: ELF 64-bit LSB executable,
ARM aarch64, version 1 (SYSV), statically linked, for GNU/Linux 3.7.0,
BuildID[sha1]=c31a9fb6ecb7324088002d85cadf2013d583ad83, with debug_info,
not stripped

Интересный факт: если Вы используете Windows, улучшить производительность работы dev контейнеров можно с помощью интеграции с WSL.

Вывод

Мы рассказали, как настроить и использовать dev контейнеры в средах разработки VS Code и Clion. Данная технология поддерживается также многими другими средами (пример, Visual Studio).

Dev контейнер — удобный инструмент, который упрощает процесс разработки и предоставляет такие возможности как:

  • изолированные разработка, сборка и дебаг;

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

  • легкое обновление окружения сборки проекта;

  • синхронизация настроек среды разработки между командой (в том числе на разных платформах);

  • разработка и тестирование на отличных от используемой платформах.

Поэтому dev контейнеры — это удобно, модно, молодёжно!

Dev контейнеры, fellow kids!
Dev контейнеры, fellow kids!

Авторы: Кузьмичева Ольга и Стародубцев Дмитрий
Вычитка и фидбек: Черных Виктор, Магденко Юлия, Кирпичников Антон, Колесникова Анна
Оформление статьи: Ковыляева Анастасия

Комментарии (11)


  1. kulaginds
    15.05.2024 08:45

    Подскажите, чем старый docker compose хуже dev containers?


    1. Akuma
      15.05.2024 08:45
      +1

      Тем что не надо ничего делать руками


    1. TourmalineCore Автор
      15.05.2024 08:45

      Это немного разные технологии с разным фокусом: docker compose – средство для запуска и управления контейнерами, dev containers – средство для контейнерной разработки. Да, можно настроить контейнер через docker compose и использовать его для контейнерной разработки, но это будет сложнее. Dev контейнеры уже интегрированы в среду разработки, их использовать проще.


      1. kulaginds
        15.05.2024 08:45

        А в чем сложность с docker-compose? Там нельзя прокинуть volume с хоста?


        1. TourmalineCore Автор
          15.05.2024 08:45

          Конечно, можно. Но зачем, если в dev контейнерах это уже автоматизировано?
          Что нужно делать с docker-compose: прокидывать volume с хоста, устанавливать расширения, настраивать IDE в контейнере.
          Что нужно сделать с dev контейнером: кликнуть на кнопку.


          1. kulaginds
            15.05.2024 08:45

            А какие расширения нужно устанавливать?

            Зачем настраивать ide в контейнере?


            1. TourmalineCore Автор
              15.05.2024 08:45

              Зависит от того, что вам нужно. Мы, например, используем расширения VS Code для поддержки синтаксиса языка, для удобного взаимодействия с Cmake, для написания документации и поддержки Mermaid и многие другие. Удобно, когда нужное расширение одним кликом можно добавить в контейнер.


              1. kulaginds
                15.05.2024 08:45

                А в рамках контейнера, какие вы плагины ставите, которые нельзя поставить в связке ide+docker-compose?


                1. TourmalineCore Автор
                  15.05.2024 08:45

                  Можно поставить любые расширения в связке ide+docker-compose, но тогда их либо придется ставить внутрь контейнера + vs code туда же, либо, если использовать docker-compose чисто для сборки и билда, расширения придется ставить локально. Dev контейнеры же легко позволяют устанавливать расширения именно в контейнер.


  1. say_TT_plz
    15.05.2024 08:45
    +1

    на windows используется в лучшем случае WSL под капотом которого старый добрый Hyper-v. Используете вы скорее всего docker desktop, который в свою очередь требует лицензионного соглашения. Да и в целом он всегда был тормозным и весьма глючным. У себя использую rancher desktop, при прочих равных куда меньше проблем с ним.

    https://learn.microsoft.com/en-us/windows/wsl/wsl-config - Стоит почитать по кастомной настройке WSL.

    У меня стройкое предубеждение, что докер на windows использует не все ядра с хоста при запуске.

    Но в любом случае, существуют накладные расходы на виртуализацию. А еще при долгой работе появляется куча мусора, старые контейнеры, слои, кеши. Виртуальный диск WSL разрастается и с удивлением видим забитый диск C.

    Этот плагин же поддерживает работу в удаленной среде, проще завести на вашем гипервизоре виртуалку на Linux с докером. Не нужно будет мощное железо, да регламентную очистку будет проще делать. А то и вообще в кубере запускать.


    1. TourmalineCore Автор
      15.05.2024 08:45

      Да, действительно используем docker desktop. Посмотрим в сторону rancher desktop, спасибо :)