Хабрахабр

Сборка проектов с dapp. Часть 2: JavaScript (frontend)

Предыдущая статья была о сборке приложений на Java — теперь же поговорим о приложениях на JavaScript. Этот материал продолжает цикл о сборке Docker-образов для приложений на различных языках программирования с помощью утилиты dapp. Для начала это будет frontend-приложение, а в следующей части планируется рассказать о сборке backend'а и запуске всего в Kubernetes.

Да-да, подготовим к запуску в Kubernetes свой майнинг-пул с блокчейном и выплатами! В качестве иллюстрации будут использованы приложения nodejs-pool и poolui.

Пул раздаёт майнерам задания и собирает ответы от них. Пул для майнинга — это приложение для координации программ-майнеров. Nodejs-pool — это серверная часть пула, с которой общаются программы-майнеры. Если общими усилиями удалось найти блок, который сеть признаёт валидным, то вознаграждение за этот блок делится между участниками пула по той или иной стратегии. Poolui — frontend-приложение, с помощью которого участники взаимодействуют с пулом: регистрируются, видят общую и свою статистику по блокам, майнерам, выплатам.

Сборка приложения poolui «как есть»

Первое описание сборки может быть повторением готового Dockerfile (как в статье про Java), но если такого нет, то достаточно начать с запуска приложения в контейнере по рекомендациям разработчиков. В нашем случае в README написано, что для сборки и запуска достаточно выполнить команду npm start — вот с этого и начнём.

11-alpine. Возьмём официальный образ node, в котором уже есть npm, — например, версию 9. Исходники обычно добавляются в какую-нибудь директорию — например, /app, — поэтому нужна директива docker. В образ нужно добавить исходный код приложения, а контейнер будет запущен с командой npm start с помощью dapp dimg run. Получился такой простейший dappfile.yaml: WORKDIR, чтобы команда запустилась в нужной директории, а не в корне образа.

dimg: poolui
from: node:9.11-alpine
git: - add: / to: /app
docker: WORKDIR: /app

Команда сборки:

dapp dimg build

(Подробнее о некоторых удобствах при работе с этой командой сборки см. в статье от коллеги.)

Команда запуска приложения:

dapp dimg run poolui -p 8080:8080 -ti --rm -- npm start

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

Улучшенный dappfile.yaml

По виду страницы можно понять, что одной команды npm start не хватает для полноценного запуска приложения в виде контейнера.

Наличие в проекте Dockerfile упрощает работу по созданию dappfile.yaml, т.к. Подобный запуск «как есть» работает не для всех проектов, но его можно использовать, чтобы «пронаблюдать» за стартом незнакомого приложения в контейнере. сразу видно все команды для создания образа.

Инженеры нашей компании проводят такую работу либо на основе своих знаний утилит в разных языках (npm, gulp, maven, composer, и т.д.), либо в некоторых случаях совместно с разработчиками заказчика изменяют файлы описания (package.json, gulpfile.js, pom.xml, composer.json), чтобы сборка приложения описывала все нужные зависимости. Чтобы создать dappfile.yaml для проекта без Dockerfile, нужно определить из описания сборки приложения, какие команды запускать.

Затем добавляется стадия install, где уже доступны исходные тексты приложения и можно запускать инструменты сборки. Обычно всё начинается со стадии beforeInstall, где описывается установка системных пакетов, например, если каких-то инструментов не хватает в выбранном базовом образе. После успешной сборки образа с двумя стадиями можно пойти дальше и какие-то команды выделить в другие стадии (beforeSetup, setup), а также описать наборы директорий и файлов, изменения в которых приведут к пересборке.

Для выката приложения в production нужно провести работу по определению команд для каждой стадии сборки образа и по определению файлов-зависимостей для этих стадий. Подобный запуск «как есть» для проектов, в составе которых нет Dockerfile, обычно не применим в production-окружении.

Рассматриваемый проект имеет три файла описания:

  • package.json — описание зависимостей и действий для npm;
  • bower.json — описание зависимостей приложения;
  • gulpfile.js — описание задач.

Из package.json видно, что для сборки понадобятся gulp и bower — эти утилиты можно установить на стадии beforeInstall, т.к. их версия не будет часто изменяться. На этой же стадии добавится git, т.к. он нужен для скачивания зависимостей. В этом же файле видно команды, которых не хватило: npm install, bower install. Эти команды уйдут на стадию install, где происходит скачивание зависимостей. Отличие небольшое — для простоты bower install выполняется с ключом --allow-root. Пересборка стадии install зависит от изменений в файлах описаниях package.json и bower.json.

Эта задача последовательно запускает три других: build, connect, watch. npm start запускает команду gulp, которая выполнит задачу по умолчанию из gulpfile.js. задачи сборки и запуска объединены. Т.е. Это удобно для быстрого старта, но для сборки образа придётся на стадии setup явно вызвать gulp build и установить пересборку setup в зависимости от изменений в директории app и файла gulpfile.js.

Запускать gulp watch не нужно, т.к. Для запуска приложения теперь используется не npm start, а gulp connect. это команда для упрощения разработки.

Итоговый dappfile.yaml выглядит так:

dimg: poolui
from: node:9.11-alpine
git: - add: / to: /app stageDependencies: install: - package.json - bower.json beforeSetup: - app - gulpfile.js
shell: beforeInstall: - apk update - apk add git - npm install --global bower - npm install --global gulp install: - cd /app - npm install - bower install --allow-root beforeSetup: - cd /app - gulp build
docker: WORKDIR: "/app" CMD: ["gulp", "connect"]

Лог сборки приложения можно увидеть в этом asciicast'е:

Для проверки, если запустить сборку повторно, то всё соберётся из кэша:

Теперь можно запустить приложение командой dapp dimg run poolui -p 8080:8080 -ti --rm:

Нужно поправить gulpfile.js, чтобы сервер слушал на адресе 0. В выводе запуска заметна такая строка: Server started http://localhost:8080.
Это значит, что подключиться к серверу из браузера на хост-машине не получится. 0. 0. Изменения нужно закоммитить и запустить dapp dimg build, чтобы собрать новый образ. 0. изменится gulpfile.js, то должна пересобраться только стадия beforeSetup. Т.к. Результат можно увидеть в этом asciicast'е:

Повторный запуск с командой dapp dimg run poolui -p 8080:8080 -ti --rm:

Если подключиться к приложению браузером (зайти на http://localhost:8080), то можно увидеть подобную страницу:

Фронтенд пула запущен и выглядит как нужно. Готово! Таким вариантом может стать образ с nginx, куда будет скопировано содержимое директории /app/build. Однако gulp connect — это модуль, предназначенный для разработки, а для production хотелось бы запаковать приложение «правильно». В dapp есть артефакты и промежуточные или инструментальные образы — эта возможность и будет использована далее.

Упаковка в образ с nginx

Приложение собирается в директорию /app/build и достаточно превратить описанный dimg в artifact. Стоит отметить, что artifact не может содержать директивы Docker, поэтому их нужно удалить, а в остальном отличий от dimg нет. Теперь нужно добавить второй dimg на основе, например, nginx:stable-ansible. Готовый образ nginx настроен на отдачу статических файлов из /usr/share/nginx/html — в эту директорию нужно импортировать /app/build. Готовый dappfile.yml выглядит так:

artifact: poolui-builder
from: node:9.11-alpine
git: - add: / to: /app stageDependencies: install: - package.json - bower.json beforeSetup: - app - gulpfile.js
shell: beforeInstall: - apk update - apk add git - npm install --global bower - npm install --global gulp install: - cd /app - npm install - bower install --allow-root beforeSetup: - cd /app - gulp build
---
dimg: poolui
from: nginx:stable-ansible
import: - artifact: poolui-builder add: /app/build to: /usr/share/nginx/html after: install

Команда сборки не меняется:

dapp dimg build

А вот команду запуска надо поменять — nginx слушает на 80-м порту.

dapp dimg run poolui -p 8080:80 -ti --rm

При обращении к localhost:8080 результат такой же, как и с запуском gulp connect: страница показывается полностью.

В логе сборки можно подсмотреть id стадий и оценить размер промежуточного и итогового образов.

# Итоговый образ
dimgstage-poolui 0e27eaebff1f23312d18f83370ee30000a97139311fa141b86aa3f34b15e544d 6a1a7fc1aa98 8 minutes ago 25.1MB
# Промежуточный образ poolui-builder
dimgstage-poolui f000dbe70d25a5abb998997e6c0530db52f228fee4cdd0390046657bdb3a6d32 8f300d169e5e 17 minutes ago 241MB

Теперь frontend-часть точно готова! Далее нужно собрать и запустить backend, что несколько сложнее и будет описано в следующей статье.

Заключение

Приложение довольно простое, но даже на таком примере можно показать, что контейнеризация приложений, изначально написанных без оглядки на Docker, требует некоего вдумчивого анализа. Зато в результате может получиться dappfile.yaml, который будет пересобирать только нужные стадии, ускоряя инкрементальные сборки.

инструментов много и у каждого заказчика свой сформированный разработчиками набор. Специфика контейнеризации приложений на JavaScript именно в этом — в определении того, что нужно запускать на этапе сборки, т.к.

P.S.

Читайте также в нашем блоге:

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть