Контейнеризируйте свои настройки разработки с помощью Docker и VSCode

В этой статье вы узнаете о важности хорошего процесса разработки и его влиянии на вашу производительность.

К тому времени, как вы закончите читать эту статью, вы будете знать, как настроить среду разработки бэкенда и внешнего интерфейса с помощью VSCode и Docker.

Немного контекста

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

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

Я должен найти способ держаться подальше от такого рода проблем, с моей точки зрения, есть два решения.

  • Глобальные зависимости
  • Контейнерная разработка

Проанализируем каждый из них.

Глобальные зависимости

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

Такие инструменты, как nvmдля NodeJS или virtualenvдля Python, позволяют переключаться между версиями на хост-компьютере.

Узнайте больше о nvm здесь или virtualenv здесь.

В случае nvm вы можете установить разные версии NodeJS на свой локальный компьютер, и каждый раз, когда вы хотите использовать одну из них, просто переключайтесь на нужную версию:

$ nvm use 14.15.0

а затем вы можете использовать выбранную вами версию везде.

Но этого недостаточно

Я не могу перечислить все случаи, когда я переключался на другой проект, и выполнить:

$ npm run test

запустить все мои наборы тестов и удивить!

Потому что я использую неправильную версию NodeJS для проекта.

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

Контейнерная разработка

Итак, я начал исследовать, есть ли что-нибудь еще для решения этой проблемы, и я нашел так называемую «контейнерную разработку», которая позволяет вам изолировать вашу среду разработки от вашего хост-компьютера, не смешивая зависимости , больше никаких подверженных ошибкам исполнений, все, что вам нужно, это все, что у вас есть в вашем 'контейнере'.

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

Во время моего исследования и использования этого типа процесса разработки я смог собрать преимущества и недостатки:

Преимущества:

  • Одним из ключевых моментов в разработке программного обеспечения является возможность выполнять итерации снова и снова более быстрым и надежным способом.
  • Возможность поделиться конфигурацией настройки разработки проекта, передав только образ Docker.
  • Забудьте о «глобальных» элементах внутри локального компьютера хоста, только то, что имеет значение для проекта, находится внутри образа Docker.
  • Если у каждого товарища по команде будет одинаковый образ докера, такие вещи, как «это сработало на моей машине», исчезнут.

Недостатки:

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

Итак, все, что нам нужно сделать, это создать нашу среду с нашим образом Docker и настроить все в зависимости от характера проекта.

Звучит сложно! Надеюсь, VSCode (с подключаемым модулем) позволит нам наиболее легко использовать такой процесс разработки.

Давайте рассмотрим пример того, как я могу настроить простой проект Frontend + Backend и работать в «замкнутом режиме» с Docker и VSCode.

Контейнерная разработка на практике

Если вы зашли так далеко, возможно, вас интересует, как мы собираемся смешивать все ингредиенты для создания простого веб-приложения.

Предположим, мы хотим создать простое приложение React, которое подключается к серверной части ExpressJS.

Шаги, которые мы собираемся выполнить, следующие:

  • Требования
  • Конфигурация VSCode + Docker
  • Пример приложения

Итак, начнем!

Требования

На этом этапе мы устанавливаем все необходимые инструменты.

Установить VSCode

Прежде всего, установите VSCode (если вы еще этого не сделали) и следуйте системным требованиям для удаленной разработки в контейнере.

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

Установите плагин VSCode Remote — Containers.

Затем откройте VSCode и установите плагин «Remote Containers». Этот плагин упрощает нам разработку внутри контейнера.

Подробнее о плагине Remote — Containers для VSCode здесь.

Конфигурация VSCode + Docker

На этом этапе мы настроим VSCode для удаленной контейнерной разработки.

Обнаружение .devcontainer

После установки подключаемого модуля нажмитеF1 и введите"Добавить файлы конфигурации разработки",выберите предпочтительную настройку, в моем случае я выбираю NodeJS.

На этом этапе создается файл .devcontainer.json внутри папки .devcontainer, этот файл вместе с Dockerfile (вы также можете используйте сгенерированный файл docker-compose.yml), где мы можем настроить нашу установку для разработки.

Dockerfile:

ARG VARIANT="14-buster"
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}

Как видите, мы получаем образ изMicrosoft Container Registry (MCR), там много Dockerобразов, готовых для разработки контейнера, зайдите и посмотрите здесь .

.devcontainer.json:

{
    "name": "Node.js",
    "build": {
        "dockerfile": "Dockerfile",
        "args": { "VARIANT": "14" }
    },
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "extensions": ["dbaeumer.vscode-eslint"],
    "forwardPorts": [],
    "remoteUser": "node"
}

В .decontainer.json можно настроить много чего для контейнера, одно из них — свойство build, где мы прописываем путь к Dockerfile мы хотим использовать и переменную среды, которую мы передаем. В нашем случае мы передаем переменную 'VARIANT'.

Помимо сборки, вы также можете настроить подключаемые модули VSCode, которые вы хотели бы использовать внутри контейнера, в примере dbaeumer.vscode-eslint, устанавливается после создания контейнера разработки. .

Вы можете проверить все параметры конфигурации файла .devcontainer.json здесь.

Но мы все еще работаем на нашей локальной хост-машине, прежде чем начать, нам нужно собрать и запустить образ, также нам нужно создать том и привязать его к нашему рабочему пространству… слишком много работы, верно?

Не волнуйтесь! Пусть VSCode сделает это за нас.

Запустите контейнер разработки с VSCode

Сначала нажмите F1 и введите "Повторно открыть в контейнере" и подождите, пока контейнер разработки не будет готов.

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

Следующий шаг, откройте новый терминал, и вы заметите, что он открыт внутри контейнера, в папке вашей рабочей области.

Перед началом разработки проверьте, какая версия NodeJS работает.

$ node -v
v14.16.0

Как мы настраиваем его в нашем файле .devcontainer.json, милая!

Пример приложения

На этом этапе мы начнем разработку примера приложения с помощью React и ExpressJS.

Создать React-приложение

Как только у нас будет настроена среда, давайте начнем разработку нашего приложения, сначала с нашей внешней стороны (эта команда создаст папку 'frontend'):

$ npx create-react-app frontend

И дождитесь окончания установки.

Если вы пережили установку npm, вы можете продолжить работу на стороне Backend.

Создать приложение ExpressJS

Мы будем использовать ExpressJS, и express-generator отлично подойдет сюда, давайте установим его глобально внутри контейнера:

$ npm install express-generator -g

Но что произойдет, если мы закроем контейнер и снова откроем его? express-generator не будет установлен, верно? нам нужно будет устанавливать express-generator каждый раз, когда мы открываем контейнер, это неправильно!

Не беспокойтесь, .devcontainer.json спешит на помощь!

{
    "name": "Node.js",
    "build": {
        "dockerfile": "Dockerfile",
        "args": { "VARIANT": "14" }
    },
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "postCreateCommand": ["npm install express-generator -g"],
    "extensions": ["dbaeumer.vscode-eslint"],
    "forwardPorts": [],
    "remoteUser": "node"
}

С помощью postCreateCommand мы сможем выполнять переданные нами команды при создании контейнера, круто, верно?

После того, как мы установили express-generator, создайте экспресс-приложение с помощью (это создаст папку «backend»):

$ express --no-view backend

Мы хотим использовать ExpressJSв качестве Rest API для нашего Reactприложения, поэтому нам не нужно указывать какой-либо механизм представления.

Подготовьтесь к разработке

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

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

Приложение React использует chokidar для отслеживания изменений и не включено по умолчанию. Чтобы включить, нам нужно установить специальную переменную среды для нашего контейнера разработки.

Подробнее о чокидаре здесь.

Создайте файл .env в папке .devcontainer и добавьте следующее:

CHOKIDAR_USEPOLLING=true

Добавим в наш файл .devcontainer.json:

{
    "name": "Node.js",
    "build": {
        "dockerfile": "Dockerfile",
        "args": { "VARIANT": "14" }
    },
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "postCreateCommand": ["npm install express-generator -g"],
    "extensions": ["dbaeumer.vscode-eslint"],
    "runArgs": ["--env-file", ".devcontainer/.env"],
    "forwardPorts": [],
    "remoteUser": "node"
}

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

Включить взаимодействие между интерфейсом и сервером

Чтобы Frontend мог получить доступ к Backend, нам нужно установить BACKEND_URL в нашем Frontendприложении, как мы это делали раньше. , для этого мы будем использовать тот же файл .env.

Измените файл .env, добавив следующее:

CHOKIDAR_USEPOLLING=true
BACKEND_PORT=3001
FRONTEND_PORT=3000
REACT_APP_BACKEND_URL=http://localhost:3001

Затем примените эти новые переменные среды в коде.

Сначала замените PORT на BACKEND_PORT в backend/bin/www.

var port = normalizePort(process.env.BACKEND_PORT || '3000');

Затем заставьте react-scripts использовать FRONTEND_PORT в качестве PORT по умолчанию, изменив package.json файла Модуль Внешний интерфейс.

"scripts": {
    "start": "PORT=$FRONTEND_PORT && react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
}

Наконец, REACT_APP_BACKEND_URL будет доступен внутри приложения React, поэтому вы можете использовать его как process.env.REACT_APP_BACKEND_URL,но для упрощения статьи, Я пока пропущу это.

В качестве резюме:

  • Бэкенд будет прослушивать порт 3001
  • Внешний интерфейс будет прослушивать порт 3000
  • Внешняя часть будет использовать REACT_APP_BACKEND_URL для доступа к внутренней частиконечным точкам.

Структура проекта

Наконец, структура папок нашего проекта, которую мы только что сгенерировали.

.devcontainer
|__.devcontainer.json
|_.env
|__Dockerfile
frontend
|__node_modules
|__src
   |__App.js
   |__App.css
   |__App.test.js
   |__index.js
   |__index.css
|__public
   |__index.html
|__package.json
|__README.md
|__yarn.lock
backend
|__bin
   |__www
|__public
   |__images
   |__javascripts
   |__stylesheets
      |__styles.css
   |__index.html
|__routes
   |__index.js
   |__users.js
|__app.js
|__package.json

Со всей этой настройкой мы готовы запустить наше приложение.

Настроить порты переадресации

Перед запуском нашего проекта нам нужно открыть порты как из Frontend, так и из Backend, чтобы мы могли получить к ним доступ с нашего хост-компьютера.

Давайте посмотрим, как это сделать с помощью .devcontainer.json.

{
    "name": "Node.js",
    "build": {
        "dockerfile": "Dockerfile",
        "args": { "VARIANT": "14" }
    },
    "settings": {
        "terminal.integrated.shell.linux": "/bin/bash"
    },
    "postCreateCommand": ["npm install express-generator -g"],
    "extensions": ["dbaeumer.vscode-eslint"],
    "runArgs": ["--env-file", ".devcontainer/.env"],
    "forwardPorts": [3000, 3001],
    "remoteUser": "node"
}

С помощью forwardPorts вы можете настроить, какие порты будут перенаправляться на наш хост-компьютер, порт 3000 для нашего интерфейса и 3001для нашего бэкенда.

Хорошо! как только мы поработаем над нашим приложением, давайте воплотим его в жизнь!

Запуск примера приложения

Сначала запустите Backend следующим образом:

$ cd /backend
$ npm run start

Затем запустите интерфейс следующим образом:

$ cd /frontend
$ npm run start

Пример приложения для тестирования

Чтобы протестировать Внешний интерфейс, откройте браузер и перейдите по ссылке http://localhost:3000.

Приложение React всплывает, круто!

Теперь давайте проверим Backend,откроем другую вкладку браузера и перейдем по адресу http://localhost:3001.

Бэкенд тоже отвечает, здорово!

Поздравляем с запуском вашего первого контейнерного приложения!

Поделитесь примером приложения

Последнее, что нужно сделать, — это использовать предпочтительную версию системы управления версиями, например Git, для хранения конфигурации .devcontainer. Таким образом, любой, кто захочет использовать этот проект, должен будет только клонировать проект, открыть .devcontainer и начать программировать!

Вы даже можете использовать разные версии одновременно!

Забудьте о типичной ошибке запуска тестов на локальном компьютере.

Вывод

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

Я надеюсь, что вы узнаете столько же, сколько и я, из такого потока разработки.

Удачного кодирования!