Как использовать Node.js с Docker – CodesCode

Узнайте о преимуществах запуска приложений Node.js в контейнерах Docker и создание практического рабочего процесса для разработки.

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

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

Рассмотрим следующие сценарии:

  • Возможно, вы используете macOS, когда другие используют Windows, а сервер работает на Linux.
  • У вас установлена версия Node.js 20, но другие используют другие версии выполнения времени.
  • Вы используете зависимости, такие как базы данных, которые имеют различия или могут быть недоступны на других платформах.
  • Вы уверены, что ваш новый код не может нанести вред на другой операционной системе (ОС)?

Docker поставляет

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

Docker

Настоящая виртуальная машина эмулирует аппаратное обеспечение ПК, чтобы вы могли установить ОС. Docker эмулирует ОС, чтобы вы могли устанавливать приложения. Обычно устанавливается одно приложение на контейнере на основе Linux и они соединяются через виртуальную сеть для общения по порту HTTP.

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

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

С Docker вам не нужно устанавливать Node.js на свой компьютер или использовать такую ​​возможность управления временем выполнения, как nvm.

Ваш первый скрипт

Установите Docker Desktop на Windows, macOS или Linux, а затем создайте небольшой скрипт с именем version.js с следующим кодом:

console.log(`Версия Node.js: ${ process.version }`);

Если у вас установлен Node.js локально, попробуйте выполнить этот скрипт. Вы увидите следующий вывод, если у вас установлена версия 18:

$ node version.jsВерсия Node.js: v18.18.2

Теперь вы можете запустить тот же скрипт внутри контейнера Docker. Ниже приведена команда, которая использует самую свежую версию долгосрочной поддержки (LTS) Node.js. Перейдите в каталог со скриптом и выполните его в macOS или Linux:

$ docker run --rm --name version \  -v $PWD:/home/node/app \  -w /home/node/app \  node:lts-alpine version.jsВерсия Node.js: v20.9.0

Пользователи Windows Powershell могут использовать аналогичную команду с фигурными скобками вокруг PWD:

> docker run --rm --name version -v ${PWD}:/home/node/app -w /home/node/app node:lts-alpine version.jsВерсия Node.js: v20.9.0

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

Давайте попробуем другую версию Node, например, последнюю версию 21. На macOS или Linux:

$ docker run --rm --name version \  -v $PWD:/home/node/app \  -w /home/node/app \  node:21-alpine version.jsNode.js version: v21.1.0

В Windows Powershell:

> docker run --rm --name version -v ${PWD}:/home/node/app -w /home/node/app node:21-alpine version.jsNode.js version: v21.1.0

Помните, что скрипт выполняется внутри контейнера Linux, в котором установлена определенная версия Node.js.

Объяснение аргументов

Для любопытных, аргументы команды:

  • docker run запускает новый контейнер из образа – об этом позже.

  • --rm удаляет контейнер при завершении. Нет необходимости сохранять контейнеры, если у вас нет оснований перезапустить их снова.

  • --name version присваивает имя контейнеру для более простого управления.

  • -v $PWD:/home/node/app (или -v ${PWD}:/home/node/app) связывает том. В данном случае, текущий каталог на хост-компьютере смонтирован внутри контейнера в пути /home/node/app.

  • -w /home/node/app устанавливает рабочий каталог Node.js.

  • node:lts-alpine – это образ, в данном случае, LTS-версия Node.js, работающая на Alpine Linux. Образ содержит ОС и файлы, необходимые для выполнения приложения. Представьте его как снимок диска. Вы можете запустить любое количество контейнеров из одного и того же образа: все они ссылаются на один и тот же набор файлов, поэтому каждый контейнер требует минимальных ресурсов.

  • version.js – это команда для выполнения (из рабочего каталога).

Образы Docker доступны на Docker Hub и они доступны для приложений и сред выполнения, включая Node.js. Обычно образы доступны в разных версиях, которые идентифицируются с помощью тега, такого как :lts-alpine, 20-bullseye-slim или просто latest.

Обратите внимание, что Alpine – это крошечное распространение Linux с размером базового образа около 5 МБ. В нем нет многих библиотек, но для простых проектов, таких как в этом учебнике, это вполне достаточно.

Запуск сложных приложений

Скрипт version.js выше простой и не содержит зависимостей или шагов сборки. Большинство приложений Node.js используют npm для установки и управления модулями в каталоге node_modules. Вы не можете использовать вышеуказанную команду, потому что:

  • Вы не можете запустить npm на хост-компьютере (у вас может не быть установленного Node.js или правильной версии).
  • Некоторые модули требуют платформозависимых бинарных файлов. Вы не можете установить Windows-бинарник на хост-компьютер и ожидать, что он будет работать в контейнере Linux.

Решение – создать свой собственный образ Docker, который содержит:

  • соответствующую версию исполняемой среды Node.js
  • установленную версию вашего приложения со всеми необходимыми модулями

Демонстрация ниже создает простое приложение Node.js с использованием фреймворка Express.js. Создайте новый каталог с именем simple и добавьте файл package.json со следующим содержимым:

{  "name": "simple",  "version": "1.0.0",  "description": "пример простого приложения Node.js с использованием Docker",  "type": "module",  "main": "index.js",  "scripts": {    "debug": "node --watch --inspect=0.0.0.0:9229 index.js",    "start": "node index.js"  },  "license": "MIT",  "dependencies": {    "express": "^4.18.2"  }}

Добавьте файл index.js с JavaScript кодом:

// Приложение Express
import express from 'express';

// Конфигурация
const cfg = {
  port: process.env.PORT || 3000
};

// Инициализация Express
const app = express();

// Маршрут главной страницы
app.get('/:name?', (req, res) => {
  res.send(`Привет ${req.params.name || 'Мир'}!`);
});

// Запуск сервера
app.listen(cfg.port, () => {
  console.log(`Сервер работает на http://localhost:${cfg.port}`);
});

Не пытайтесь устанавливать зависимости или запустить это приложение на компьютере хоста!

Создайте файл с именем Dockerfile со следующим содержимым:

# Базовый образ Node.js LTS
FROM node:lts-alpine

# Определение переменных среды
ENV HOME=/home/node/app
ENV NODE_ENV=production
ENV NODE_PORT=3000

# Создание папки приложения и назначение прав пользователю node
RUN mkdir -p $HOME && chown -R node:node $HOME

# Установка рабочей директории
WORKDIR $HOME

# Задание активного пользователя
USER node

# Копирование package.json с хоста
COPY --chown=node:node package.json $HOME/

# Установка модулей приложения
RUN npm install && npm cache clean --force

# Копирование оставшихся файлов
COPY --chown=node:node . .

# Открытие порта на хосте
EXPOSE $NODE_PORT

# Команда запуска приложения
CMD [ "node", "./index.js" ]

В этом файле описаны шаги, необходимые для установки и запуска вашего приложения. Обратите внимание, что файл package.json копируется в образ, затем выполняется команда npm install, после чего копируются остальные файлы. Это более эффективно, чем копирование всех файлов сразу, потому что Docker создает слой образа при каждой команде. Если изменяются файлы вашего приложения (index.js), Docker должен выполнить только последние три шага; ему не нужно заново выполнять команду npm install.

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

Dockerfile.git.gitignore.vscodenode_modulesREADME.md

Создайте Docker-образ с именем simple, выполнив следующую команду (обратите внимание на точку . в конце — она указывает, что вы используете файлы из текущего каталога):

$ docker image build -t simple .

Если образ node:lts-alpine Docker, использованный выше, не был удален с вашей системы, образ должен собраться за несколько секунд.

Предполагая, что сборка прошла успешно, запустите контейнер из вашего образа:

$ docker run -it --rm --name simple -p 3000:3000 simple
Сервер работает на http://localhost:3000

Флаг -p 3000:3000 открывает <хост-порт> для <порт-контейнера>, поэтому порт 3000 на вашем компьютере маршрутизируется на порт 3000 внутри контейнера.

Откройте браузер и введите URL http://localhost:3000/, чтобы увидеть “Привет, Мир!”

Попробуйте добавить имена в URL, например http://localhost:3000/Craig, чтобы увидеть альтернативные сообщения.

Наконец, остановите работу вашего приложения, нажав на значок stop во вкладке Containers в Docker Desktop, или выполните следующую команду в другом окне терминала:

docker container stop simple

Более эффективный рабочий процесс Docker для разработки

Процесс, описанный выше, имеет несколько недостатков:

  • Любое изменение вашего кода (в файле index.js) требует остановки контейнера, пересборки образа, перезапуска контейнера и повторного тестирования.

  • Вы не можете подключить отладчик Node.js, такой как отладчик доступный в VS Code.

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

  • Установка переменных среды, таких как NODE_ENV=development.

  • Примонтирование локального каталога в контейнер.

  • Запуск приложения с помощью npm run debug. Это запускает node --watch --inspect=0.0.0.0:9229 index.js, который перезапускает приложение при изменении файлов (новое в Node.js 18) и запускает отладчик с внешними запросами разрешенными из контейнера.

  • Открытие порта приложения 3000 и порта отладки 9229 на хосте.

Вы можете сделать это одной длинной командой docker run, но я предпочитаю использовать Docker Compose. Он устанавливается вместе с Docker Desktop и часто используется для запуска нескольких контейнеров. Создайте новый файл с именем docker-compose.yml со следующим содержимым:

version: '3'services:  simple:    environment:      - NODE_ENV=development    build:      context: ./      dockerfile: Dockerfile    container_name: simple    volumes:      - ./:/home/node/app    ports:      - "3000:3000"      - "9229:9229"    command: /bin/sh -c 'npm install && npm run debug'

Запустите ваше приложение в режиме отладки с помощью команды:

$ docker compose up[+] Building 0.0s[+] Running 2/2 ✔ Network simple_default  Created ✔ Container simple        CreatedAttaching to simplesimple  |simple  | up to date, audited 63 packages in 481mssimple  |simple  | > [email protected] debugsimple  | > node --watch --inspect=0.0.0.0:9229 index.jssimple  |simple  | Debugger listening on ws://0.0.0.0:9229/de201ceb-5d00-1234-8692-8916f5969cbasimple  | Справка: https://nodejs.org/en/docs/inspectorsimple  | Сервер слушает на http://localhost:3000

Обратите внимание, что в старых версиях Docker Compose это были сценарии Python, запускаемые с помощью docker-compose. В новых версиях функциональность Compose интегрирована в основное исполняемое приложение, поэтому оно запускается с помощью docker compose.

Перезапуск приложения в режиме реального времени

Откройте файл index.js, внесите изменение (например, поменяйте строку на 14-й строке) и сохраните файл, чтобы увидеть автоматический перезапуск приложения:

simple  | Перезапуск 'index.js'simple  | Debugger listening on ws://0.0.0.0:9229/acd16665-1399-4dbc-881a-8855ddf9d34csimple  | Справка: https://nodejs.org/en/docs/inspectorsimple  | Сервер слушает на http://localhost:3000

Откройте или обновите ваш браузер по адресу https://localhost:3000/, чтобы увидеть обновления.

Отладка с помощью VS Code

Откройте панель Запуск и отладка в VS Code и нажмите создать файл launch.json.

Панель запуска и отладки в VS Code

Выберите Node.js в выпадающем списке, и будет создан и открыт в редакторе файл .vscode/launch.json. Добавьте следующий код, который подключает отладчик к запущенному контейнеру:

{
  // Используйте IntelliSense, чтобы узнать о возможных атрибутах.
  // Наведите указатель, чтобы увидеть описания существующих атрибутов.
  // Дополнительную информацию можно найти по адресу: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to Container",
      "address": "localhost",
      "port": 9229,
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "/home/node/app",
      "skipFiles": [
        "<node_internals>/**"
      ]
    }
  ]
}

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

Запуск и отладка в VS Code

Появится панель отладки. Перейдите к файлу index.js и установите точку останова на 14-й строке, нажав на левый край окна рядом с текстом кода.

Установить точку останова в VS Code

Обновите браузер по адресу https://localhost:3000/, и VS Code приостановит выполнение кода на точке останова и покажет состояние всех переменных приложения. Щелкните по значкам на панели отладки, чтобы продолжить выполнение, пошагово пройти по коду или отключить отладчик.

Остановить контейнер

Остановите работающий контейнер, открыв другой терминал. cd в директорию приложения и выполните команду:

docker compose down

Сводка

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

Это руководство объясняет основы запуска приложений Node.js в контейнерах Docker. Если вы хотите углубиться в тему, рассмотрите эти ресурсы CodesCode:

Поделиться этой статьей


Leave a Reply

Your email address will not be published. Required fields are marked *