Назад в блог

Как развернуть приложение Node.js (Express.js) с помощью Docker на Ubuntu 20.04

Как развернуть приложение Node.js (Express.js) с помощью Docker на Ubuntu 20.04

Введение

Docker — это контейнерная платформа, представляющая собой легкую, виртуализированную, портативную, программно-определяемую стандартизированную среду. Она позволяет программному обеспечению работать изолированно от другого ПО, запущенного на физическом хосте. Docker является определяющим компонентом непрерывной разработки и интеграции (CI/CD) в разработке программного обеспечения. Он предлагает легковесную альтернативу виртуальным машинам и позволяет разработчикам использовать преимущества распределенных архитектур приложений. Для подробного обзора экосистемы Docker ознакомьтесь с этой статьей.

Процесс создания приложения с помощью Docker начинается с того, что разработчик создает образ для своего приложения. Затем этот образ развертывается внутри контейнера. Образ содержит определяющие компоненты приложения, такие как код приложения, библиотеки, файлы конфигурации, переменные окружения и среду выполнения. Образ стандартизирует среду внутри контейнера, обеспечивая контейнеризации свойство портативности. Node.js — это кроссплатформенная среда выполнения JavaScript с открытым исходным кодом для бэкенда, которая может выполнять код JavaScript вне веб-браузера. Она построена на базе Chrome V8 JavaScript Engine. Express.js — это минималистичный бэкенд-фреймворк JavaScript, который работает поверх Node.js.

В этом руководстве мы создадим образ для веб-сайта, работающего на фреймворке Express. Мы будем использовать Bootstrap, библиотеку для фронтенда, чтобы улучшить внешний вид интерфейса. После создания образа мы соберем контейнер и отправим его в Docker Hub. Docker Hub позволяет разработчикам размещать контейнеризированные приложения для простого развертывания в любой среде Docker. Как только ваш контейнер будет размещен на Docker Hub, мы скачаем его и создадим еще один образ, который непосредственно будет обслуживать наш веб-сайт.

Предварительные требования

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

Шаг 1. Настройка зависимостей приложения

Перед созданием образа вам необходимо подготовить исходный код приложения. Исходный код включает в себя сам код, статический контент и зависимости, которые будут скопированы в контейнер. Начните с создания каталога для вашего проекта в домашней директории пользователя без прав root. Мы назовем его node_express, но вы можете использовать любое другое имя каталога по вашему выбору:

Затем перейдите в этот каталог:

Это будет корневой каталог вашего приложения. Приложение node.js ожидает наличия файла package.json в корневой папке. Npm использует этот файл для определения зависимостей, необходимых вашему приложению. Введите следующую команду, чтобы создать этот файл:

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

Как видите, этот файл определяет имя проекта, версию, автора и лицензию, под которой будет распространяться код приложения. Рекомендуется использовать короткое и описательное имя для вашего проекта, чтобы избежать дубликатов в npm registry. Мы указали лицензию ISC для проекта, которая разрешает свободное копирование, изменение или распространение кода приложения.

Самое главное, вам следует обратить внимание на следующие директивы в файле:

  • main»: эта директива указывает точку входа приложения, которую мы установили как index.js. Мы создадим этот файл в ближайшее время.
  • dependencies»: эта директива указывает зависимости приложения, которые будут загружены из реестра npm при запуске команды npm, в нашем случае нам нужна Express версии 4.17.1 и выше.

Теперь вы можете сохранить файл, нажав Ctrl + O. Затем закройте файл, нажав Ctrl + X. Далее мы установим зависимости, выполнив следующую команду:

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

Шаг 2. Добавление файлов кода приложения

Мы создадим простой сайт с рецептами, предоставленными allrecipes. Основной точкой входа для приложения является файл index.js. Мы добавим директорию views, в которой будут храниться различные страницы и статические ресурсы проекта. У сайта будет целевая страница, содержащая вводную информацию и ссылки на некоторые рецепты.

Код нашей целевой страницы будет помещен в файл home.html. Сначала создайте файл index.js, введя следующую команду:

Добавьте следующий код, который импортирует и создает приложение Express. Он также указывает объект Router, базовую директорию и порт, на котором будет работать это приложение:

require — это функция JavaScript, которая загружает модуль. В данном случае мы загружаем модуль express. Затем мы будем использовать импортированный модуль для создания объектов express и router. Объект router выполняет функции маршрутизации приложения, отвечая на вызовы методов HTTP, которые мы будем добавлять к этому объекту по ходу руководства.

Мы также установили path и port. Константа path определяет базовую директорию для кода. В нашем случае это поддиректория views внутри корневой директории проекта. port указывает порт, который должно прослушивать приложение express, в нашем примере мы установили его в значение 8090.

После определения констант мы можем указать некоторые маршруты для приложения с помощью объекта router. Добавьте следующий код в файл index.js, чтобы указать маршруты:

Вы можете добавить промежуточное ПО к маршрутам с помощью функции router.use. В этом случае мы добавляем функцию, которая логирует запросы маршрутизатора перед их передачей маршрутам приложения. Запрос GET к корню приложения вернет файл home.html страницу. Затем мы добавили страницы для трех рецептов, которые также будут запрашиваться с помощью GET-запроса к конкретной странице рецепта.

Наконец, добавьте следующий код для подключения router промежуточного ПО и статических ресурсов приложения. Кроме того, укажите приложению express прослушивать порт 8090:

Ваш готовый файл index.js должен выглядеть следующим образом:

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

Введите следующую команду, чтобы открыть файл home.html целевой страницы:

Добавьте следующий код в файл. Этот код импортирует Bootstrap и предоставляет посетителям сайта информацию о том, чему посвящен сайт:

Помимо импорта Bootstrap, страница также добавляет базовое навигационное меню, которое поможет нам перемещаться по страницам и возвращаться на целевую страницу. Мы также добавили строку для импорта нашего собственного CSS-файла:

Позже мы будем использовать этот файл для добавления пользовательских стилей в приложение. Теперь давайте создадим три страницы для рецептов. Сначала мы начнем с создания страницы лазаньи. Откройте файл в редакторе nano с помощью следующей команды:

В открытом файле добавьте следующий код. Этот файл импортирует Bootstrap, файл custom.css, определит навигационное меню и предоставит некоторую информацию о рецепте лазаньи:

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

Затем добавьте этот код в файл:

Наконец, давайте создадим файл banana_bread.html, введя команду:

Затем добавьте в файл следующий HTML-код:

Итак, мы создали все страницы. Если вы помните, нам нужно добавить css/custom.css файл. Введите следующую команду, чтобы создать директорию:

Затем создайте и откройте файл в редакторе nano с помощью команды:

Вы можете добавить больше CSS-кода для стилизации вашего сайта по своему усмотрению. Для краткости давайте добавим в файл следующий фрагмент кода:

После завершения сохраните и закройте файл.

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

Мы настроили приложение на прослушивание порта 8090, выполните следующую команду, чтобы указать брандмауэру разрешить трафик через этот порт. Если вы указали другой порт, замените номер порта в команде:

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

Запустите приложение с помощью команды node index.js. Если вы указали другую точку входа, замените ее на свою:

Если вы перейдете в браузере по адресу http://your_public_server_ip:8090, вы увидите целевую страницу рецептов, как и было настроено:

Recipes

 

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

Node.js app install on Ubuntu 1

А здесь у нас страница рецепта Гуакамоле:

Guacamole

К этому моменту вы создали свое приложение и проверили, что оно работает должным образом. Вы можете остановить сервер, нажав Ctrl + C, и перейти к созданию Dockerfile. Файлы Dockerfile помогают в масштабировании, позволяя воссоздать экземпляр приложения при необходимости.

Шаг 3. Создание Dockerfile

Docker считывает инструкции, указанные в Dockerfile, при сборке образов. Он определяет среду выполнения приложения. Таким образом, он помогает разработчикам избежать несоответствий в зависимостях или изменения версий среды выполнения. Введите следующую команду, чтобы создать Dockerfile:

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

Поскольку приложение должно работать в среде node.js, мы начнем с добавления образа node:10-alpine image для node.js. На момент написания этого руководства это recommended LTS version of Node.js. Мы выбрали именно этот образ, потому что он основан на проекте Alpine Linux project. Таким образом, это поможет свести размер нашего образа к минимуму. На странице Docker Hub Node images page доступно несколько вариантов образов, которые вы можете выбрать в зависимости от ваших потребностей.

Добавьте следующий код, чтобы задать базовый образ приложения с помощью директивы FROM:

Этот образ включает Node.js и npm. Каждый Dockerfile должен начинаться с директивы FROM. Образ Docker node по умолчанию поставляется с пользователем node без прав root, которого вы можете использовать для запуска контейнера приложения вместо root. Docker security recommends не запускать контейнеры от имени root и ограничивать привилегии только теми, которые необходимы для работы его ресурсов.

В таком случае мы будем использовать домашний каталог пользователя node в качестве рабочей директории для приложения, а также самого пользователя внутри контейнера. Вы можете обратиться к этому руководству по Docker Node image best practices для получения дополнительной информации.

Мы создадим подкаталог node_modules внутри /home/node вместе с директорией app, чтобы упростить настройку прав доступа для кода приложения. Создание этих директорий гарантирует, что они будут иметь правильные права доступа, когда мы запустим команду npm install локально внутри контейнеров. После создания директорий вы должны передать права владения ими пользователю node. Мы сделаем это внутри Dockerfile, добавив следующую строку:

Затем вы установите рабочую директорию, добавив следующую строку:

Рекомендуется всегда устанавливать WORKDIR, чтобы Docker не приходилось создавать ее по умолчанию.

Добавьте следующую строку, чтобы скопировать файлы package.json и package-lock.json:

Рекомендуется добавлять инструкцию COPY перед запуском npm install или копированием исходного кода приложения. Это позволяет использовать механизм кэширования Docker. В процессе сборки Docker проверяет, есть ли у него кэшированный слой для каждой инструкции. Это означает, что если вы не меняли файл package.json, Docker будет использовать существующий слой образа и избежит повторной установки node modules, что ускорит процесс сборки.

Перед запуском npm install, добавьте следующую строку, чтобы переключить пользователя на node, чтобы гарантировать, что все файлы приложения и директория node_modules принадлежат пользователю node без прав root:

Теперь наш контейнер готов к запуску команды npm install. Добавьте следующую строку в Dockerfile:

После установки node_modules добавьте следующую строку, которая укажет Docker скопировать код приложения в директорию приложения на контейнере с правильными правами доступа и владельцем, то есть пользователем node без прав root:

Последний шаг — открыть порт 8090 на контейнере, как мы определили в нашем входном файле index.js:

EXPOSE определяет, какие порты на контейнере будут открыты во время выполнения. CMD запускает команду для запуска приложения, в данном случае node index.js.

В Dockerfile должна быть только одна инструкция CMD, так как действует только последняя. Пожалуйста, ознакомьтесь с справочной документацией по Dockerfile, чтобы узнать, что еще можно делать с помощью Dockerfile.

Ваш готовый Dockerfile должен выглядеть следующим образом:

Теперь вы можете сохранить и закрыть файл.

Следующий шаг — добавление файла .dockerignore. Как и файл .gitignore, .dockerignore указывает, какие файлы и директории в каталоге проекта не следует копировать в контейнер.

Откройте файл в редакторе nano:

Добавьте в файл следующие строки:

Если вы работаете с репозиторием git, вам также следует добавить директорию .git и файл .gitignore. Сохраните и закройте файл.

Если все прошло успешно, пришло время собрать образ приложения с помощью команды docker build. Вы можете добавить флаг –t к команде docker build, чтобы присвоить образу понятное имя вместо случайной строки, которую Docker устанавливает по умолчанию. Мы также будем отправлять образ на Docker Hub, поэтому лучше всего включить ваше имя пользователя Docker Hub в тег.

Мы будем использовать nodejs-express-image в качестве имени тега. Вы можете выбрать любое имя тега, которое вам нравится. Вот команда для сборки образа:

Не забудьте заменить your_dockerhub_username на ваше настоящее имя пользователя Docker Hub. Точка (.) в конце указывает, что контекстом сборки является текущий каталог.

Процесс сборки занимает минуту или две. Как только он завершится, введите команду для проверки ваших образов:

Вы должны увидеть что-то подобное:

sudo docker images

Помните, что мы заменили your_dockerhub_username на реальное имя пользователя.

Убедившись, что ваш образ собран, вы можете создать контейнер на его основе с помощью docker run. Будут включены следующие флаги:

  • -p: публикует порт контейнера и сопоставляет его с портом на хост-системе. В демонстрационных целях мы будем использовать порт 80 на хост-системе. Однако, если на этом порту у вас запущен другой процесс, вы можете изменить его по своему усмотрению. Узнайте больше о привязке портов в документации Docker.
  • -d: для фонового режима (detached mode). Позволяет контейнеру продолжать работу в фоновом режиме.
  • --name: вы можете использовать этот флаг, чтобы задать понятное имя вместо того, чтобы позволить Docker назначить случайную строку.

Команда для создания контейнера выглядит следующим образом. Замените имя пользователя Docker Hub соответствующим образом:

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

Вы должны увидеть вывод, похожий на следующий:

Node.js app install on Ubuntu 3

Как видно из вывода, контейнер запущен. Вы можете просмотреть его в браузере, перейдя по публичному IP-адресу вашего сервера без указания порта. Загрузится ваша домашняя страница:

awesome recipe

 

Вы успешно развернули статический веб-сайт Node Express с помощью Docker. Давайте посмотрим, как мы можем отправить этот образ на Docker Hub для дальнейшего использования и масштабирования.

Шаг 4. Работа с репозиториями образов Docker

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

Используйте следующую команду для входа в свою учетную запись Docker Hub. Замените ее на ваше фактическое имя пользователя Docker Hub:

Введите пароль по запросу. После входа в систему файл ~/.docker/config.json создается в домашнем каталоге вашего пользователя и содержит ваши учетные данные Docker Hub.

После этого введите следующую команду, чтобы отправить образ в Docker Hub, указав тег, который вы задали при сборке образа ранее:

Эта команда отправляет docker-образ в вашу учетную запись Docker Hub. Если вы перейдете в свою учетную запись, вы увидите недавно отправленный образ:

Docker Hub

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

Выведите список текущих контейнеров, введя команду:

Вы должны увидеть вывод, похожий на следующий:

Docker Hub

Обратите внимание на CONTAINER ID, указанный в выводе, скопируйте его и используйте для остановки контейнера с помощью команды, заменив ID на ваш:

Введите следующую команду, чтобы вывести список всех docker-образов, доступных в вашей системе:

В выводе будет показано имя вашего образа, образ node.js и другие образы, созданные в процессе сборки.

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

Введите y для подтверждения. Это удалит остановленные контейнеры и образы. Если вы выведете их список, вы увидите пустой список в выводе:

output

Теперь вы удалили как контейнер, в котором работало приложение, так и сам образ. Узнайте больше об удалении контейнеров, образов и томов Docker, следуя нашему руководству.

Теперь мы можем воссоздать весь процесс, сначала загрузив образ из Docker Hub с помощью следующей команды. Замените имя пользователя Docker Hub соответствующим образом:

Снова выведите список ваших образов Docker с помощью команды:

Вы должны увидеть образ в выводе:

sudo docker

Теперь вы можете перестроить свой контейнер, используя команду из Шага 3. Конечно, замените имя пользователя Docker Hub там, где это необходимо:

Выведите список ваших контейнеров, чтобы подтвердить, что он был перестроен:

Вы должны увидеть похожий вывод:

В браузере перейдите по публичному IP-адресу вашего сервера, и вы увидите, что ваше приложение работает.

Заключение

Если вы следовали руководству до этого момента, теперь у вас есть статический веб-сайт, созданный с помощью Express и Bootstrap и развернутый с помощью Docker. Вы использовали файлы статического веб-сайта для сборки Docker-образа и использовали этот образ для создания контейнера. Затем вы отправили образ в реестр Docker-образов, Docker Hub, сделав его доступным для будущего использования или масштабирования. Чтобы протестировать использование реестра образов, вы удалили образы и контейнеры, загрузили образы из реестра и заново создали контейнеры.

В этом руководстве объяснялось, как развернуть приложение Node.js. Если вы хотите узнать, как использовать другой стек веб-разработки, у нас есть руководство по Развертыванию приложения Laravel с помощью Docker Compose на Nginx.

Дополнительные ресурсы по использованию Docker см. в следующих руководствах:

Приятной работы!

author

Hark Labs

Автор · CloudSigma

Preslav Dobrev — креативный дизайнер в CloudSigma, сосредоточенный на формировании последовательного корпоративного образа с помощью традиционных и инновационных маркетинговых каналов. Он умело сочетает художественное видение со стратегическим маркетингом, создавая убедительные истории бренда.

Комментарии

Комментариев пока нет. Будьте первым.