DEV Community

Samoilenko Yuri for RNDSOFT

Posted on • Originally published at blog.rnds.pro on

1

Dev containers: вскрытие

Оригинал: 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 проект открывается
  • мы оказываемся внутри контейнера и получаем ровно то окружение, которое нам необходимо для разработки

Вот шаги, которые нужно выполнить для добавления к себе в проект конфигурации:

Для этого открываем палитру команд в VS Code, выбираем пункт “Remote-Containers: Add Development Configuration Files”.

Нам предоставляется выбор:

  1. воспользоваться готовыми конфигурациями (Node.js, Ruby on Rails, C++, Go, PHP и ещё много других)
  2. добавить существующий в проекте 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"
}
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

Открываем проект, VSCode предлагает нам открыть его внутри контейнера - соглашаемся:

Ждем некоторое время, пока все образы будут загружены, и будет произведена сборка контейнера:

Пока ждем, можно нажать show log и посмотреть, что там происходит.

Всё - проект открыт, и можно приступать к работе:

Выполняем в терминале VSCode следующие команды:

rake db:setup
rails s -b 0.0.0.0
Enter fullscreen mode Exit fullscreen mode

Открываем в браузере наш блог (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 и местами подглючивает. Но в целом, всё довольно работоспособно.

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

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay