Контейнеризация приложения Node.js для разработки: базовая настройка

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

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

В этой серии мануалов вы узнаете, как настроить среду разработки для приложения Node.js с помощью Docker. Мы создадим два контейнера – один для приложения Node, второй для базы данных MongoDB – с помощью Docker Compose. Данный мануал поможет вам подготовить приложение и БД к контейнеризации.

Поскольку это приложение использует Node и MongoDB, такая установка будет делать следующее:

  • Синхронизировать код приложения на хосте с кодом в контейнере (чтобы упростить изменения во время разработки).
  • Проверять, работают ли изменения в коде приложения без перезапуска.
  • Создавать пользовательскую и защищенную паролем БД для данных приложения.
  • Сохранять эти данные.

Читайте также: Контейнеризация приложения Node.js для разработки: определение сервисов с помощью Docker Compose

Требования

1: Клонирование проекта и настройка зависимостей

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

Сначала клонируйте репозиторий nodejs-mongo-mongoose с GitHub. Этот репозиторий содержит код установки, которую мы уже использовали в мануале Интеграция MongoDB в приложение Node.js (в нем мы рассказали, как интегрировать базу данных MongoDB с существующим приложением Node с помощью Mongoose).

Клонируйте репозиторий в каталог node_project:

git clone https://github.com/do-community/nodejs-mongo-mongoose.git node_project

Перейдите в каталог node_project:

cd node_project

Откройте файл package.json проекта:

nano package.json

Под зависимостями проекта и перед закрывающей фигурной скобкой создайте новый объект devDependencies, который включает в себя nodemon:

...
"dependencies": {
"ejs": "^2.6.1",
"express": "^4.16.4",
"mongoose": "^5.4.10"
},

"devDependencies": {


"nodemon": "^1.18.10"


}

}

Сохраните и закройте файл.

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

2: Настройка приложения для работы в контейнерах

Подготовка приложения для контейнеризованного рабочего процесса в основном нацелена на то, чтобы сделать код модульным. Контейнеры обеспечивают переносимость кода между средами, и наш код должен подходить для этой операции, оставаясь максимально отделенным от базовой операционной системы. Чтобы достичь этого, нужно перепроектировать код приложения и более широко использовать в нем свойство Node process.env, которое возвращает объект с информацией о пользовательской среде во время выполнения. Мы можем использовать этот объект в коде для динамического присваивания конфигурации во время выполнения.

Давайте начнем с app.js, основной точки входа в приложение. Откройте файл:

nano app.js

Внутри вы увидите определение константы port, а также функцию listen, которая использует эту константу для определения порта, который будет прослушивать приложение:

...
const port = 8080;
...
app.listen(port, function () {
console.log('Example app listening on port 8080!');
});

Давайте переопределим константу port, чтобы обеспечить динамическое назначение во время выполнения с помощью объекта process.env. Внесите следующие изменения в определение константы и функцию listen:

...
const port = process.env.PORT || 8080;
...
app.listen(port, function () {
console.log(`Example app listening on ${port}!`);
});

Новое определение константы динамически назначает port, используя значение, переданное во время выполнения или 8080. Также мы переписали функцию listen для использования шаблонного литерала, который будет интерполировать значение порта при прослушивании соединений. Поскольку порты будут связаны с другим местом, эти настройки устранят необходимость постоянно пересматривать этот файл при изменении среды.

Когда вы закончите редактирование, сохраните и закройте файл.

Затем нужно изменить информацию о подключении к базе данных, чтобы удалить все учетные данные. Откройте файл db.js, который содержит эту информацию:

nano db.js

В настоящее время файл выполняет следующие действия:

  • Импортирует Mongoose, объектно-документное отображение (Object Document Mapper, ODM), которое мы используем для создания схем и моделей данных приложения.
  • Устанавливает учетные данные БД как константы, включая имя пользователя и пароль.
  • Соединяется с базой данных, используя метод mongoose.connect.

Для получения дополнительной информации о файле см. раздел 3 мануала Интеграция MongoDB в приложение Node.js.

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

...
const MONGO_USERNAME = '8host';
const MONGO_PASSWORD = 'your_password';
const MONGO_HOSTNAME = '127.0.0.1';
const MONGO_PORT = '27017';
const MONGO_DB = 'sharkinfo';
...

Вместо жесткого кодирования этой информации вы можете использовать объект process.env для захвата значений этих констант  во время выполнения. Измените блок, чтобы он выглядел так:

...
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
...

Сохраните и закройте файл.

На этом этапе вы подготовили файл db.js к работе с переменными среды приложения, но вам все еще нужно настроить способ передачи этих переменных в приложение. Давайте создадим файл .env со значениями, которые вы можете передать в приложение во время выполнения.

Откройте файл:

nano .env

Этот файл будет содержать информацию, которую вы удалили из db.js: имя пользователя и пароль базы данных приложения, а также настройки порта и имя БД. Не забудьте указать здесь свои данные.

MONGO_USERNAME=8host
MONGO_PASSWORD=your_password
MONGO_PORT=27017
MONGO_DB=sharkinfo

Обратите внимание, что мы удалили настройки хоста, которые изначально были в db.js. Сейчас мы определим хост на уровне файла Docker Compose вместе с другой информацией о сервисах и контейнерах.

Сохраните и закройте этот файл.

Поскольку ваш файл .env содержит конфиденциальную информацию, вы должны убедиться, что он включен в файлы проекта .dockerignore и .gitignore, чтобы он не копировался в элемент управления версиями или в контейнеры.

Откройте файл .dockerignore:

nano .dockerignore

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

...
.gitignore
.env

Сохраните и закройте файл.

Файл .gitignore в этом хранилище уже содержит .env, но вы можете проверить, есть ли он:

nano .gitignore
...
.env
...

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

3: Отладка параметров подключения БД

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

Откройте db.js для редактирования:

nano db.js

Вы увидите код, который мы добавили ранее, вместе с константой url для URI соединения Mongo и методом Mongoose connect:

...
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;
mongoose.connect(url, {useNewUrlParser: true});

В настоящее время метод connect принимает опцию, которая позволяет Mongoose использовать новый URL парсер Mongo. Давайте добавим еще несколько опций к этому методу, чтобы определить параметры для попыток переподключения. Мы можем сделать это, создав константу options, которая включает соответствующую информацию, в дополнение к новой опции парсера URL. Под константами Mongo добавьте следующее определение константы options:

...
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
const options = {

useNewUrlParser: true,


reconnectTries: Number.MAX_VALUE,


reconnectInterval: 500,


connectTimeoutMS: 10000,


};

...

Параметр reconnectTries позволяет Mongoose продолжать попытки подключения бесконечно, а reconnectInterval определяет период между попытками подключения в миллисекундах. connectTimeoutMS определяет период в 10 секунд – драйвер Mongo ожидает в течение этого периода, прежде чем определить попытку подключения как неудачную.

Теперь можно использовать новую константу options в методе connect для точной настройки параметров подключения Mongoose. Мы также добавим промис для обработки потенциальных ошибок подключения.

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

...
mongoose.connect(url, {useNewUrlParser: true});

Удалите существующий метод connect и замените его следующим кодом, который включает константу options и промис:

...
mongoose.connect(url, options).then( function() {

console.log('MongoDB is connected');


})


.catch( function(err) {


console.log(err);


});

В случае успешного подключения функция регистрирует соответствующее сообщение; в противном случае она обнаружит и зарегистрирует ошибку, что позволит вам позже устранить неполадки.

Готовый файл будет выглядеть так:

const mongoose = require('mongoose');
const {
MONGO_USERNAME,
MONGO_PASSWORD,
MONGO_HOSTNAME,
MONGO_PORT,
MONGO_DB
} = process.env;
const options = {
useNewUrlParser: true,
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 500,
connectTimeoutMS: 10000,
};
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;
mongoose.connect(url, options).then( function() {
console.log('MongoDB is connected');
})
.catch( function(err) {
console.log(err);
});

Сохраните и закройте файл, когда вы закончите редактирование.

Вы внедрили отказоустойчивость в код своего приложения для обработки случаев, когда оно не может подключиться к БД. Теперь можно перейти к определению ваших сервисов с помощью Compose. Об этом мы расскажем в следующем мануале этой серии.

Tags: , , , ,