Оригинал: https://blog.rnds.pro/029-dev-containers-uncovering
В этой статье хотелось бы рассказать про разработку внутри docker-контейнера: зачем это нужно, что предоставляет для этого замечательная IDE VSCode, и как это работает.
Итак, docker - это не только отличная технология для контейнеризации и деплоя приложений, но и возможность развернуть специфическую среду разработки в одно касание.
Для тех, кто ещё (внезапно!) не знаком с Docker, очень рекомендую сразу пойти и ознакомиться с этой технологией (https://en.wikipedia.org/wiki/Docker_(software)).
Для чего же это нужно?
Давайте рассмотрим существующие проблемы, которые, как правило, возникают при работе над проектом.
Проблема 1
Вы - новый разработчик в компании , Вам дали свежеустановленный ПК, дали доступ в репозиторий проекта, с которым придется иметь дело. Предположим, что этот проект на Rails. Для запуска проекта необходимо:
- установить системные dev пакеты
- установить rvm
- установить правильную версию ruby, bundle
- установить nvm
- установить node
- установить и настроить БД, например, Postgres
- возможно, что-то ещё, что требует проект (Redis, Consul и т.д.)
В процессе установки могут возникнуть следующие проблемы:
- у вас Windows: это сразу +100 к сложности и боли
- у вас слишком новая версия операционки, а в проекте используются устаревшие библиотеки, и при установке ruby пакетов, либо scss (когда же его наконец перепишут на JS) могут возникнуть ошибки компиляции
- возможно, необходимы какие-то ещё дополнительные шаги, которые забыли описать в README, например, это может быть установка корневых сертификатов, прописывание каких-то переменных среды
В целом видно, что процесс первого запуска проекта непростой. Скорее всего, его придется повторить, когда захочется поработать с домашнего компьютера, а там как раз больше вероятность встретить Windows =)
Проблема 2
Вы - опытный разработчик и уже давно работаете в компании, у вас много проектов , на разных языках, фреймворках и приходится часто переключаться. Согласитесь, не очень хочется проводить существенное время на развертывание окружения, вспоминая, как это делать.
Проблема 3
Бывает так, что проект уже очень старый , порос мхом и обновлять его нерентабельно, но поддерживать надо. Там всё очень старое, и на своей современной операционке это просто не запустить.
Проблема 4
Ещё одна проблема - это замусоренность хостовой системы , когда мы долго уже работаем, много всего разного поставили себе в систему, у нас появляются странные глюки, а остальные разработчики говорят нам, что УМВР.
Решение
Итак, эти все проблемы решает контейнеризированное окружение разработки. Мы получаем:
- повторяемость среды разработки
- быстрое развертывание
- независимость от хостовой системы, её типа и версии
- возможность полностью очистить свою систему от ненужных рудиментов старых проектов
Конечно же есть и недостатки:
- Повышается сложность понимания что происходит. Надо не забывать, что мы находимся внутри контейнера, и некоторые внешние ресурсы могут быть недоступны, такие как файлы, либо сторонние сервисы, запущенные на localhost.
- Требуется больше системных ресурсов. В основном, это дополнительное пространство на диске под контейнеры и образы docker, а в случае с MacOS ещё и дополнительный расход оперативной памяти под виртуальную машину с докером.
- Необходимо учитывать, что ID пользователя внутри контейнера может быть другим , и может возникнуть проблема с доступом к файлам проекта. Забегая вперед, скажу, что эта проблема вполне решаемая.
Существует множество вариантов реализовать такое контейнеризированное окружение:
- написать Dockerfile с нужной версией ОС, установкой всего необходимого, зайти в контейнер и разрабатывать в VIM.
- можно смонтировать исходники в запущенный контейнер и разрабатывать в своей IDE, а запускать в контейнере. Правда, у IDE скорее всего будут проблемы с дополнением кода.
- можно установить IDE внутрь контейнера и пробросить X-ы с хостовой машины (работает только с Linux).
- можно поставить sshd в контейнер и заходить внутрь по ssh из VSCode, IDEA или любой другой IDE, которая поддерживает удалённую разработку.
- либо воспользоваться специализированным решением, которое нам предлагает VSCode. Предлагаю в этой статье подробно рассмотреть это решение как самое, на мой взгляд, продвинутое из того, что я видел.
VS Code Dev container
Полная документация находится здесь: https://code.visualstudio.com/docs/remote/containers
Вкратце, это работает следующим образом:
- в проект добавляется конфигурация в папке .devcontainer
- при открытии такого проекта VS Code предлагает переоткрыть его внутри контейнера
- если мы соглашаемся, то после непродолжительных магических действий со стороны VS Code проект открывается
- мы оказываемся внутри контейнера и получаем ровно то окружение, которое нам необходимо для разработки
Вот шаги, которые нужно выполнить для добавления к себе в проект конфигурации:
- Docker уже должен быть установлен
- устанавливаем плагин в VS Code https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
- добавляем поддержку dev container в наш проект
Для этого открываем палитру команд в VS Code, выбираем пункт “Remote-Containers: Add Development Configuration Files”.
Нам предоставляется выбор:
- воспользоваться готовыми конфигурациями (Node.js, Ruby on Rails, C++, Go, PHP и ещё много других)
- добавить существующий в проекте Dockerfile или docker-compose.yml
Если сильно спешим, то можно воспользоваться готовыми конфигурациями. Но, на мой взгляд, лучше написать свою конфигурацию с нуля, так мы получаем больше контроля над происходящим, и это же так интересно!
Разбираемся в магии
Отдельно хотелось бы рассмотреть, что же делает VS Code с нашим контейнером, прежде чем его открыть.
Существует ряд нюансов, на которые следует обратить внимание:
- при монтировании исходников в контейнер ID пользователя и ID группы внутри и снаружи должны совпадать, иначе мы получим в своих исходниках новые файлы, созданные от имени другого пользователя (возможно от рута)
- у Git есть глобальные конфигурационные файлы, в которых задается ряд параметров, таких как имя пользователя, email, тип переноса строк и т.д., желательно, чтобы git внутри контейнера использовал такие же настройки
- также необходимо скопировать некоторые пользовательские настройки для того, чтобы вы чувствовали себя как дома (.ssh/authorized_hosts, gpg конфигурацию)
Именно это делает VS Code при открытии devcontainer:
- он изучает версию операционной системы, которая используется в Dockerfile
- оборачивает ваш Dockerfile своим с дополнительными командами по пробросу UID и GID внутрь контейнера
- патчит /etc/passwd, синхронизируя UID и GID внутреннего пользователя с хостовым пользователем
- копирует в него все необходимые конфигурационные файлы из папки пользователя (git, ssh, gpg)
- устанавливает свой бэкенд на ноде (это порядка 450Мб) внутрь контейнера, который будет связываться с хостовым VSCode по рандомному TCP порту
- устанавливает внутрь контейнера все необходимые плагины для VS Code, прописанные в .devcontainer/devcontainer.json#extensions
- монтирует исходники проекта в папку /workspaces
Вуаля! Проект открыт, и можно кодить как обычно.
В итоге, чтобы открыть любой проект с поддержкой devcontainer и начать быстро кодить, Вам нужна лишь машина на Linux, Windows, MacOS с установленным Docker и VS Code.
Уже не терпится? Попробуем в деле!
Я заготовил пример проекта, который можно открыть в VSCode и посмотреть, как это работает.
Для этого я форкнул первый найденный проект “Блог” на Rails (https://github.com/navrocky/rails-blog-sample-devcontainers ).
Как нельзя кстати оказалось, что он уже немного “подзасох”, последний коммит 5 лет назад. Соответственно, в те годы люди сидели на Ruby 2.3, Debian 8 (Jessie). Вот и попробуем всё это завести в нашем 2К22.
Dev container поддерживает два варианта окружения:
- один Dockerfile. Этот вариант проще и подходит, когда нам не нужны дополнительные сервисы для работы, такие как БД.
- docker-compose.yml. Этот вариант позволяет нам запустить как само окружение, так и все необходимые дополнительные сервисы. В примере я использовал именно этот вариант, так как нам нужна ещё сконфигурированная база данных.
Так выглядит типичная конфигурация в проекте:
Всё находится внутри папки .devcontainer. Файл devcontainer.json является основным и описывает конфигурацию для плагина VSCode.
devcontainer.json
{
// Имя конфигурации
"name": "Ruby",
// указание файла docker-compose.yml и сервиса в нем,
// который будет использоваться для разработки
"dockerComposeFile": "./docker-compose.yml",
"service": "dev",
// папка внутри контейнера, в которую монтируются исходники проекта
"workspaceFolder": "/workspace",
// действие при завершении работы с проектом
"shutdownAction": "stopContainer",
// дополнительные расширения VSCode, которые необходимо установить
// внутрь контейнера перед началом работы
"extensions": [
"castwide.solargraph", "eamodio.gitlens"
],
// пользователь внутри контейнера, под которым будет происходить вход
// в контейнер
"remoteUser": "user"
}
Dockerfile
# берем нужную версию базового дистрибутива. Debian 8 из 2015 года, нам подходит.
FROM debian:8
# устанавливаем все необходимые утилиты
RUN apt-get update && apt-get install -y gnupg2 ca-certificates curl procps sudo git mc libpq-dev
# добавляем пользователя, под которым будем работать внутри контейнера, заодно даем ему возможность делать sudo
RUN useradd -m -d /home/user -s /bin/bash user && adduser user sudo && \
echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
# дальше все действия производим уже от пользователя
USER user
# устанавливаем rvm
RUN gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB && \
curl -ksSL https://get.rvm.io | bash -s stable
# устанавливаем nvm
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
# подгружаем все инициализационные скрипты и переменные среды в bash, чтобы заработал установленный rvm
SHELL ["/bin/bash", "-c", "-l"]
# устанавливаем нужную версию Ruby и Bundler
RUN rvm install ruby-2.4 && gem install bundler:1.17.3
# создаем пользовательский каталог .bundle, чтобы были правильные права на эту папку при монтировании volume
RUN mkdir -p /home/user/.bundle
# устанавливаем node v5.3.0 и делаем её по умолчанию
RUN source $HOME/.nvm/nvm.sh && nvm install v5.3.0 && nvm alias default v5.3.0
# просто висим в бесконечном ожидании из /dev/null, это нужно чтобы контейнер не закрылся после запуска
ENTRYPOINT ["tail", "-f", "/dev/null"]
Открываем проект, VSCode предлагает нам открыть его внутри контейнера - соглашаемся:
Ждем некоторое время, пока все образы будут загружены, и будет произведена сборка контейнера:
Пока ждем, можно нажать show log и посмотреть, что там происходит.
Всё - проект открыт, и можно приступать к работе:
Выполняем в терминале VSCode следующие команды:
rake db:setup
rails s -b 0.0.0.0
Открываем в браузере наш блог (http://localhost:3000/blog):
Можно зайти в административную панель (http://localhost:3000/admin) и добавить контент. Пользователь и пароль для входа: admin@example.com / 123456
Вот так просто и быстро можно открыть незнакомый проект и приступить к работе!
А что же IDEA и её производные, спросите вы?
Там не всё так радужно, но есть свет в конце туннеля.
Не так давно JetBrains добавила поддержку remote development в свои платные IDE. Community варианты её, к сожалению, не получили. И называется этот продукт JetBrains Gateway (https://www.jetbrains.com/remote-development/gateway/). Данная штука позволяет зайти на удалённую машину, в нашем случае в контейнер с поднятым ssh демоном, и загрузить туда выбранную вами IDE и запустить её в режиме сервера, а на вашем хосте будет запущен IDE Client, который будет по ssh туннелю общаться с серверной IDE. В целом всё выглядит примерно так же, как и в VS Code, но менее автоматизированно. При открытии проекта необходимо руками поднимать контейнер или docker-compose конфигурацию, настраивать соединение внутри контейнера. Серверная IDE, которая грузится в контейнер, ничем не отличается от десктопной, и в размерах тоже (это примерно 1,5 ГБ), что весьма печально. Интерфейс IDE клиента ощущается тормознее по сравнению с десктопной IDE и местами подглючивает. Но в целом, всё довольно работоспособно.
Стоит заметить, что эта система пока находится в бете, поэтому держим кулачки и внимательно наблюдаем за дальнейшим развитием событий.
Top comments (0)