Поиск по сайту:

Как докеризировать веб-приложение Node.js


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

Node.js — ведущая среда выполнения JavaScript для серверной разработки. Для успешного запуска веб-службы Node.js требуется среда с установленной средой выполнения, доступный код приложения и механизм, который обрабатывает автоматические перезапуски в случае сбоя.

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

Создание вашего проекта узла

Мы пропустим детали реализации вашего приложения. Создайте каталог для своего проекта и добавьте в него код сервера. Вот простой app.js, который прослушивает порт 8080 и отвечает на каждый запрос жестко заданным ответом:

const express = require("express");
 
const app = express();
app.get("*", (req, res) => res.send("<p>It works!</p>"));
app.listen(8080, () => console.log("Listening on 8080"));

Добавьте Express в свой проект с помощью npm:

npm init
npm install --save express

Запустите приложение, чтобы проверить его работу:

node app.js

Вы должны иметь возможность посетить localhost:8080 в своем браузере, чтобы увидеть образец ответа.

Написание Dockerfile

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

Вот файл Dockerfile, который работает для примера приложения:

FROM node:16
WORKDIR /app

COPY package.json .
COPY package-lock.json .
RUN npm ci

COPY app.js .
CMD ["app.js"]

Этот Dockerfile выбирает официальный образ Node.js Docker в качестве основы с помощью оператора FROM. Образ наследует все в базе, а затем добавляет дополнительный контент с помощью следующих инструкций.

Рабочий каталог устанавливается в /app строкой WORKDIR. Следующие операторы COPY помещают файлы в каталог /app внутри образа контейнера.

Установка зависимостей

Следующим этапом является добавление package.json npm и запуск npm ci. Это установит зависимости npm вашего проекта — в данном случае Express — в файловой системе контейнера.

Не используйте COPY node_modules/ . для копирования существующей папки node_modules в каталог вашего проекта — это помешает вам повторно использовать Dockerfile в других средах сборки. Файлы Docker должны позволить вам создавать согласованные сборки только с содержимым вашего репозитория системы управления версиями. Если файл или папка находятся в вашем .gitignore, на них не следует ссылаться в инструкции Dockerfile COPY.

Копирование кода приложения

После запуска npm ci код вашего приложения копируется в образ. Размещение этой инструкции COPY после RUN, отделяющей ее от предыдущих копий, является преднамеренным. Каждая инструкция создает новый слой в вашем изображении; Процесс сборки Docker кэширует каждый уровень для ускорения последующих сборок. Как только содержимое одного слоя изменится, кэш всех последующих слоев станет недействительным.

Вот почему код приложения следует копировать после выполнения npm ci. Код обычно меняется гораздо чаще, чем содержимое вашего файла блокировки npm. Перестроение образа, которое включает только изменения кода, эффективно пропускает этап RUN npm ci (и все более ранние этапы), значительно ускоряя процесс, когда у вас много зависимостей.

Установка команды изображения

На последнем этапе Dockerfile используется инструкция CMD для автоматического запуска вашего приложения при запуске контейнера. Это работает, потому что базовый образ Node.js настроен на использование процесса node в качестве точки входа. CMD добавляется к унаследованной точке входа, в результате чего node app.js запускается как процесс переднего плана для вашего нового изображения.

Создание вашего имиджа

Далее вам нужно создать свой образ:

docker build -t node-app:latest .

Docker возьмет Dockerfile в вашем рабочем каталоге, выполнит в нем инструкции и пометит получившееся изображение как node-app:latest. Последний . (точка) указывает ваш рабочий каталог в качестве контекста сборки образа. Это определяет пути, на которые могут ссылаться инструкции COPY в вашем Dockerfile.

Оптимизация сборки

Один из способов повысить производительность сборки — добавить файл .dockerignore в корень проекта. Дайте файлу следующее содержимое:

node_modules/

Этот файл определяет пути в вашем рабочем каталоге, которые не будут включены в контекст сборки. Вы не сможете ссылаться на них внутри своего Dockerfile. В случае node_modules содержимое этого каталога не имеет отношения к сборке, поскольку мы устанавливаем зависимости заново с помощью инструкции RUN npm ci. В частности, исключение node_modules, уже присутствующих в вашем рабочем каталоге, избавляет от необходимости копировать все эти файлы во временное местоположение контекста сборки Docker. Это повышает эффективность и сокращает время, затрачиваемое на подготовку сборки.

Запуск контейнера

На данный момент вы готовы запустить свое приложение с помощью Docker:

docker run -d 
    -p 8080:8080 
    --name my-app 
    --restart on-failure 
    node-app:latest

Команда docker run используется для запуска нового экземпляра контейнера из указанного образа. Добавлено несколько дополнительных флагов для правильной настройки контейнера для предполагаемого варианта использования:

  • -d — отсоединяет вашу оболочку от процесса переднего плана контейнера, эффективно запуская его в качестве фонового сервера.
  • -p — привязывает порт 8080 на вашем хосте к порту 8080 внутри контейнера (который наш пример приложения Express был настроен для прослушивания). Это означает, что трафик на localhost:8080 будет проходить через соответствующий порт контейнера. Вы можете изменить значение поста узла, изменив первую часть определения привязки, например 8100:8080, чтобы получить доступ к вашему контейнеру на localhost:8100.
  • --name — присваивает контейнеру понятное имя, которое вы можете использовать для ссылки на него в других командах Docker CLI.
  • --restart — выбирает политику перезапуска для применения к контейнеру. Параметр on-failure означает, что Docker автоматически перезапустит контейнер, если он выйдет с кодом ошибки из-за сбоя вашего приложения.

Образ, созданный на предыдущем шаге, используется как последний аргумент команды docker run. Идентификатор контейнера будет отправлен в окно вашего терминала; вы сможете получить доступ к своему приложению Node.js, повторно посетив localhost:8080. На этот раз сервер работает внутри контейнера Docker, а не использует процесс node, установленный на вашем хосте.

Краткое содержание

Docker помогает развертывать веб-службы Node.js, помещая в контейнер всю среду приложения. Вы можете запустить контейнер из своего образа с помощью одной команды docker run на любом хосте с установленным Docker. Это устраняет сложность поддержки версий Node.js, установки модулей npm и мониторинга ситуаций, когда процесс вашего приложения необходимо перезапустить.

Когда вы внесли изменения в код и хотите запустить обновление, перестройте образ Docker и удалите старый контейнер с помощью docker rm . Затем вы можете запустить замещающий экземпляр, использующий исправленное изображение.

Возможно, вам понадобится немного другая процедура в производстве. Хотя вы можете использовать обычную установку Docker с помощью docker run, это, как правило, громоздко для всех приложений, кроме самых простых. Чаще всего используется такой инструмент, как Docker Compose или Kubernetes, для определения конфигурации контейнера в файле, который может быть версионирован внутри вашего репозитория.

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

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




Все права защищены. © Linux-Console.net • 2019-2024