Как отладить Node JS внутри Docker?


Что такое отладчик?

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

Можно добавить точку останова, чтобы приостановить выполнение. Во-вторых, к точке останова можно добавить логику, чтобы остановить выполнение. В качестве примера рассмотрим цикл for, имеющий 1 000 итераций. Выполнение должно остановиться, когда количество итераций превысит 100. Для этого поставьте точку останова на цикле for. Затем добавьте логику для остановки выполнения, когда количество итераций превысит 100.

Помимо остановки программы, отладчики показывают распределение памяти. Например, остановка выполнения покажет объем памяти, потребляемой в любой момент времени.

Что такое удаленный отладчик?

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

Во-первых, можно отлаживать программы локально. Рассмотрим сценарий, когда программное обеспечение находится в облаке. Оно может быть развернуто либо для разработки, либо для UAT, либо для производства. Теперь проблема возникает в облаке, но не на локальном хосте. В этом случае было бы очень полезно подключиться к облаку и присоединить отладчик к процессу. Можно выполнить программу строка за строкой, чтобы оценить проблему и устранить ее.

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

Docker помогает создавать переносимые контейнеры, которые быстро и легко развертываются на различных машинах. Эти контейнеры можно запускать локально на Windows, Mac & Linux. Кроме того, основные облачные системы, такие как AWS или Azure, поддерживают их из коробки. Если вы хотите изучить основы Docker и вам нужна шпаргалка по Docker CLI, то вот вводная статья об этом.

В этой статье мы настроим проект NodeJS для запуска внутри контейнера docker. Мы также настроим удаленную отладку проекта.

Если вам понравилась эта статья, пожалуйста, следуйте за мной и посмотрите другие такие же замечательные статьи на моем профиле.

Настройка проекта

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

Прежде чем двигаться дальше, на системе должны быть установлены docker desktop и VS Code. Кроме этого, других требований нет.

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

Создание файлов проекта

Мы создадим очень простой экспресс-проект Node JS. Он будет просто возвращать статическую строку JSON при открытии определенного URL. Для этого мы создадим файл server.js, который будет точкой входа в наш проект.

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

const server = require("express")();
server.listen(3000, async () => { });
server.get("/node-app", async (_, response) => {
    response.json({ "node": "app" });
});
Вход в полноэкранный режим Выйти из полноэкранного режима

В файле server.js указано, что отображение {"node": "app"} при открытии http://localhost:3000/node-app URL в браузере.

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

{
    "name": "node-app",
    "dependencies": {
        "express": "^4.17.1"
    }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Выполните команду npm install для локальной установки зависимостей. Это создаст node_modules в каталоге проекта.

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

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

Для запуска проекта в качестве докер-контейнера необходим Dockerfile. Создайте Dockerfile со следующим содержимым:

# Download the slim version of node
FROM node:17-slim
# Needed for monitoring any file changes
RUN npm install -g nodemon
# Set the work directory to app folder. 
# We will be copying our code here
WORKDIR /node
#Copy all files from current directory to the container
COPY . .
# Needed for production. Check comments below
RUN npm install
Войти в полноэкранный режим Выйти из полноэкранного режима

Здесь проект настроен для запуска в качестве простого сервера node без разрешения каких-либо точек останова. Контейнер будет запускать проект из каталога node внутри контейнера. nodemon установлен глобально в контейнере. Он необходим для наблюдения за изменением файлов в каталоге. Подробно о нем рассказано ниже.

Команда RUN npm install нужна только при развертывании в production. Мы сопоставим каталог /node нашего контейнера с текущим каталогом проекта на localhost с помощью Docker Compose (следующий раздел). Но когда приложение будет развернуто на контейнере, ему нужно будет самостоятельно установить зависимости.

Игнорирование Docker

Функция игнорирования Docker очень похожа на git ignore. .gitignore не отслеживает файлы или папки, упомянутые в нем. Точно так же мы не хотим копировать в контейнер ненужные файлы, которые занимают место.

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

node_modules/
Войти в полноэкранный режим Выйти из полноэкранного режима

Docker Compose

Docker Compose — это действительно полезный способ создания и запуска контейнеров docker с помощью одной команды. Он также полезен для одновременного запуска нескольких контейнеров. Это одна из причин, по которой мы используем docker compose вместо обычного docker. Чтобы узнать больше о docker compose и о том, как запускать несколько контейнеров, посетите статью Запуск нескольких контейнеров с помощью Docker Compose.

Теперь давайте создадим файл docker-compose.yml для добавления некоторых дополнительных конфигураций. После создания файла docker-compose.yml добавьте в него следующее содержимое:

version: '3.4'
services:
  node-app:
    # 1. build the current directory
    build: .
    # 2. Run the project using nodemon, for monitoring file changes
    # Run the debugger on 9229 port
    command: nodemon --inspect=0.0.0.0:9229 /node/server.js 3000
    volumes:
      # 3. Bind the current directory on local machine with /node inside the container.
      - .:/node
    ports:
      # 4. map the 3000 and 9229 ports of container and host
      - "3000:3000"
      - "9229:9229"
Войти в полноэкранный режим Выйти из полноэкранного режима

Файл docker-compose.yml объясняется по пунктам ниже.

Укажите на наш текущий каталог для сборки проекта.
Запустите проект с помощью nodemon, так как если в локальной директории произойдут какие-либо изменения, мы хотим перезапустить проект в docker с изменениями. Nodemon — это утилита, которая будет следить за любыми изменениями в вашем исходнике и автоматически перезапускать ваш сервер.
Привяжем наш текущий каталог к каталогу /node с помощью томов.

В дополнение к открытию и привязке порта 3000 для сервера, откройте порт 9229 для подключения отладчика.

Используйте приведенный выше файл docker-compose.yml только для отладки.

Приведенный выше docker-compose.yml раскрывает порт отладки. Кроме того, он отслеживает любые изменения файлов внутри контейнера (которые не произойдут). Наконец, он сопоставляет тома контейнера с каталогом проекта.

Для production создайте новый файл docker-compose-prod.yml со следующим содержимым:

version: '3.4'
services:
  node-app:
    build: .
    command: node /node/server.js 3000
    ports:
      - "3000:3000"
Войти в полноэкранный режим Выйти из полноэкранного режима

Он просто запускает проект и открывает порт 3000. Мы используем несколько файлов docker compose для управления отдельными окружениями. Ознакомьтесь с разделом «Запуск проекта» ниже, чтобы понять, как запустить проект на основе различных docker compose-файлов.

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

Настройка удаленного отладчика

Сначала проверьте, создан ли в вашем проекте файл launch.json. launch.json определяет различные типы конфигураций, которые мы можем запустить для отладки. Если он не создан, перейдите на вкладку RUN AND DEBUG слева в вашем VS Code, как показано на рисунке ниже:

Нажмите на текст, в котором говорится о создании файла launch.json. Прежде чем вы сможете продолжить, появится запрос о типе приложения. Выберите Node.js. Это создаст новый файл launch.json в вашем проекте с конфигурацией Node.js по умолчанию.

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

{
    "version": "0.2.0",
    "configurations": [
        {
            // 1. Type of application to attach to
            "type": "node",

            // 2. Type of request. In this case 'attach'
            "request": "attach",
            // 3. Restart the debugger whenever it gets disconnected
            "restart": true,
            // 4. Port to connect to 
            "port": 9229,
            // 5. Name of the configuration
            "name": "Docker: Attach to Node",
            // 6. Connect to /node directory of docker
            "remoteRoot": "/node"
        }
    ]
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Добавленная конфигурация не требует пояснений. По сути, мы просим отладчик подключиться к удаленному узлу с портом номер 9229. Мы также просим отладчик перезапускаться каждый раз, когда он отключается от хоста. По умолчанию отладчик пытается подключиться к порту http://localhost:9229/. Но проект размещен в каталоге /node в docker. Для сопоставления /node используется атрибут remoteRoot.

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

Вот и все! Теперь, если вы запустите docker compose up, ваш проект начнет выполняться. Для первого запуска он загрузит несколько слоев node slim SDK, а затем установит nodemon внутри контейнера docker. Но последующие запуски будут происходить гораздо быстрее. Запуск docker compose up покажет в терминале следующее сообщение:

docker compose up
Вход в полноэкранный режим Выход из полноэкранного режима

Чтобы присоединить отладчик, выполните команду Docker: Attach to Node из вкладки RUN AND DEBUG. Теперь отладчик будет прикреплен к директории /node вашего контейнера docker. Далее поставьте точку останова на строке 4 файла server.js, т.е. response.json({ "super": "app1" });. Наконец, откройте браузер и нажмите http://localhost:3000. Точка останова будет достигнута, и выполнение остановится.

Для продакшена нам нужно использовать файл docker-compose-prod.yml. Для этого нам нужно указать имя файла в команде docker. Выполните следующую команду, чтобы запустить проект как в производственной среде:

docker compose -f docker-compose-prod.yml up
Войти в полноэкранный режим Выйти из полноэкранного режима

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

Исходный код

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

Заключение

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

Надеюсь, вам понравилась эта статья. Не стесняйтесь ознакомиться с некоторыми из моих других статей:

  • Docker: Введение и шпаргалка
  • Запуск нескольких контейнеров с помощью Docker Compose
  • Настройка CI/CD для Android с помощью Azure Pipelines

Оцените статью
Procodings.ru
Добавить комментарий