Введение
Если вы активно разрабатываете приложение, использование Docker может упростить рабочий процесс и процесс развертывания вашего приложения в рабочей среде. Работа с контейнерами в разработке дает следующие преимущества:
- Среды согласованы, а это означает, что вы можете выбирать языки и зависимости, которые нужны для вашего проекта, не беспокоясь о системных конфликтах.
- Среды изолированы, что упрощает устранение неполадок и подключение новых членов команды.
- Среды являются переносимыми, что позволяет вам упаковывать свой код и делиться им с другими.
Из этого туториала вы узнаете, как настроить среду разработки для приложения Node.js с помощью Docker. Вы создадите два контейнера — один для приложения Node, а другой для базы данных MongoDB — с помощью Docker Compose. Поскольку это приложение работает с Node и MongoDB, ваша установка будет выполнять следующие действия:
- Синхронизируйте код приложения на хосте с кодом в контейнере, чтобы облегчить внесение изменений во время разработки.
- Убедитесь, что изменения в коде приложения работают без перезагрузки.
- Создайте базу данных приложения, защищенную пользователем и паролем.
- Сохраните эти данные.
В конце этого руководства у вас будет работающее приложение с информацией об акулах, работающее в контейнерах Docker:
Предварительные условия
Чтобы следовать этому руководству, вам понадобится:
- Сервер разработки под управлением Ubuntu 18.04, а также пользователь без полномочий root с привилегиями
sudo
и активным брандмауэром. Инструкции по их настройке см. в этом руководстве по первоначальной настройке сервера. - Docker установлен на вашем сервере, следуя Steps 1 and 2 «Как установить и использовать Docker в Ubuntu 18.04».
- Docker Compose установлен на вашем сервере, следуя Step 1 инструкции по установке Docker Compose в Ubuntu 18.04.
Шаг 1 — Клонирование проекта и изменение зависимостей
Первым шагом в создании этой установки будет клонирование кода проекта и изменение его файла package.json
, который включает зависимости проекта. Вы добавите nodemon
в devDependencies
проекта, указав, что будете использовать его во время разработки. Запуск приложения с помощью nodemon
гарантирует, что оно будет автоматически перезапускаться всякий раз, когда вы вносите изменения в свой код.
Сначала клонируйте репозиторий nodejs-mongo-mongoose
из учетной записи GitHub сообщества DigitalOcean. Этот репозиторий включает в себя код из настройки, описанной в разделе «Как интегрировать MongoDB с вашим приложением Node», в котором объясняется, как интегрировать базу данных MongoDB с существующим приложением Node с помощью Mongoose.
Клонируйте репозиторий в каталог с именем node_project
:
1 |
<ol><li data-prefix="$"> клон <span class="token function">git</span> https://github.com/do-community/nodejs-mongo-mongoose.git<mark> node_project</mark></li></ol> |
Перейдите в каталог node_project
:
1
<ol><li data-prefix="$"> <span class="token builtin class-name">CD</span><mark> node_project</mark></li></ol>
Откройте файл package.json
проекта с помощью nano
или вашего любимого редактора:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> -пакет.json</li></ol>
Под зависимостями проекта и над закрывающей фигурной скобкой создайте новый объект devDependencies
, который включает nodemon
:
~/node_project/package.json
1
... <span class="token property">"dependencies"</span> <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"ejs"</span> <span class="token operator">:</span> <span class="token string">"^2.6.1"</span> <span class="token punctuation">,</span> <span class="token property">"express"</span> <span class="token operator">:</span> <span class="token string">"^4.16.4"</span> <span class="token punctuation">,</span> <span class="token property">"mongoose"</span> <span class="token operator">:</span> <span class="token string">"^5.4.10"</span> <span class="token punctuation">}</span></code><mark> <span class="token punctuation">,</span></mark><mark> <span class="token property">"devDependency"</span> <span class="token operator">:</span> <span class="token punctuation">{</span></mark><mark> <span class="token property">"нодемон"</span> <span class="token operator">:</span> <span class="token string">"^1.18.10"</span></mark><mark> <span class="token punctuation">}</span></mark> <span class="token punctuation">}</span>
Сохраните и закройте файл, когда закончите редактирование. Если вы используете nano
, нажмите CTRL+X
, затем Y
, затем ENTER
.
Подготовив код проекта и изменив его зависимости, вы можете перейти к рефакторингу кода для контейнерного рабочего процесса.
Шаг 2. Настройка приложения для работы с контейнерами
Модификация вашего приложения для контейнерного рабочего процесса означает сделать ваш код более модульным. Контейнеры обеспечивают переносимость между средами, и ваш код должен отражать это, оставаясь максимально отделенным от базовой операционной системы. Для достижения этой цели вы проведете рефакторинг своего кода, чтобы более эффективно использовать свойство Process.env узла Node. Это возвращает объект с информацией о вашей пользовательской среде во время выполнения. Вы можете использовать этот объект в своем коде для динамического назначения информации о конфигурации во время выполнения с помощью переменных среды.
Начните с app.js
, вашей основной точки входа в приложение. Откройте файл:
1
<ol><li data-prefix="$"> <span class="token function">нано-</span> приложение.js</li></ol>
Внутри вы увидите определение константы port
, а также функцию listen
, которая использует эту константу для указания порта, который приложение будет прослушивать:
~/home/node_project/app.js
1
... const port = 8080; ... app.listen(port, function () { console.log('Example app listening on port 8080!'); });
Переопределите константу port
, чтобы обеспечить динамическое назначение во время выполнения с помощью process.env
. Внесите следующие изменения в определение константы и функцию listen
:
~/home/node_project/app.js
1
...</code> константный порт = процесс.env.PORT || 8080; ... app.listen(port, function () { console.log(<mark> `Пример приложения, прослушивающего ${port}!`</mark> ); });
Ваше новое определение константы назначает port
динамически, используя значение, переданное во время выполнения, или 8080
. Аналогичным образом вы переписали функцию listen
, чтобы использовать литерал шаблона, который будет интерполировать значение порта при прослушивании соединений. Поскольку вы будете сопоставлять свои порты где-то еще, эти изменения избавят вас от необходимости постоянно пересматривать этот файл по мере изменения вашей среды.
Когда вы закончите редактирование, сохраните и закройте файл.
Далее вы измените информацию о подключении к базе данных, удалив все учетные данные конфигурации. Откройте файл db.js
, который содержит следующую информацию:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> дб.js</li></ol>
На данный момент файл выполняет следующие действия:
- Импортирует Mongoose, Object Document Mapper (ODM), который вы используете для создания схем и моделей для данных вашего приложения.
- Устанавливает учетные данные базы данных как константы, включая имя пользователя и пароль.
- Подключается к базе данных с помощью метода
mongoose.connect
.
Для получения дополнительной информации о файле см. Шаг 3 статьи «Как интегрировать MongoDB с вашим приложением Node».
Вашим первым шагом в изменении файла будет переопределение констант, содержащих конфиденциальную информацию. На данный момент эти константы выглядят так:
~/node_project/db.js
1
... const MONGO_USERNAME = '</code> Сэмми '; const MONGO_PASSWORD = '<mark> ваш пароль</mark> '; const MONGO_HOSTNAME = '127.0.0.1'; const MONGO_PORT = '27017'; константа MONGO_DB = '<mark> информация о акулах</mark> '; ...
Вместо жесткого кодирования этой информации вы можете использовать process.env
для сбора значений этих констант во время выполнения. Измените блок, чтобы он выглядел так:
~/node_project/db.js
1
<span class="token operator">...</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> <span class="token constant">MONGO_USERNAME</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_PASSWORD</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_HOSTNAME</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_PORT</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_DB</span> <span class="token punctuation">}</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">;</span> <span class="token operator">...</span>
Сохраните и закройте файл, когда закончите редактирование.
На этом этапе вы модифицировали db.js
для работы с переменными среды вашего приложения, но вам все еще нужен способ передать эти переменные в ваше приложение. Создайте файл .env
со значениями, которые вы можете передать приложению во время выполнения.
Откройте файл:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> .env</li></ol>
Этот файл будет содержать информацию, которую вы удалили из db.js
: имя пользователя и пароль для базы данных вашего приложения, а также настройку порта и имя базы данных. Не забудьте обновить имя пользователя, пароль и имя базы данных, указанные здесь, своей собственной информацией:
~/node_project/.env
1
<span class="token constant">MONGO_USERNAME</span> <span class="token operator">=</span></code><mark> Сэмми</mark> <span class="token constant">МОНГО_ПАРОЛЬ</span> <span class="token operator">=</span><mark> ваш пароль</mark> <span class="token constant">МОНГО_ПОРТ</span> <span class="token operator">=</span> <span class="token number">27017</span> <span class="token constant">МОНГО_ДБ</span> <span class="token operator">=</span><mark> информация о акулах</mark>
Обратите внимание, что вы removed настройку хоста, которая изначально присутствовала в db.js
Теперь вы определите свой хост на уровне файла Docker Compose вместе с другой информацией о ваших сервисах и контейнерах.
Сохраните и закройте этот файл, когда закончите редактирование.
Поскольку ваш файл .env
содержит конфиденциальную информацию, вам необходимо убедиться, что он включен в файлы .dockerignore
и .gitignore
вашего проекта, чтобы он не копировался в ваш контроль версий или контейнеры.
Откройте файл .dockerignore
:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> .dockerignore</li></ol>
Добавьте следующую строку в конец файла:
~/node_project/.dockerignore
1
... .gitignore</code> .env
Сохраните и закройте файл, когда закончите редактирование.
Файл .gitignore
в этом репозитории уже включает .env
, но вы можете проверить его наличие:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> .gitignore</li></ol>
~~/node_project/.gitignore
1
... .env ...
На этом этапе вы успешно извлекли конфиденциальную информацию из кода вашего проекта и приняли меры для контроля того, как и где копируется эта информация. Теперь вы можете добавить в свой код подключения к базе данных, чтобы оптимизировать его для контейнерного рабочего процесса.
Шаг 3 — Изменение настроек подключения к базе данных
Следующим вашим шагом будет повышение надежности метода подключения к базе данных путем добавления кода, обрабатывающего случаи, когда вашему приложению не удается подключиться к вашей базе данных. Введение этого уровня устойчивости в код вашего приложения является рекомендуемой практикой при работе с контейнерами с помощью Compose.
Откройте db.js
для редактирования:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> дб.js</li></ol>
Обратите внимание на код, добавленный ранее, а также константу url
для URI подключения Mongo и метод connect
Mongoose:
~/node_project/db.js
1
... 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
:
~/node_project/db.js
1
<span class="token operator">...</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> <span class="token constant">MONGO_USERNAME</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_PASSWORD</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_HOSTNAME</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_PORT</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_DB</span> <span class="token punctuation">}</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">;</span><mark></mark></code> <span class="token keyword">константные</span> параметры <span class="token operator">=</span> <span class="token punctuation">{</span><mark> <span class="token literal-property property">useNewUrlParser</span> <span class="token operator">:</span> <span class="token boolean">правда</span> <span class="token punctuation">,</span></mark><mark> <span class="token literal-property property">reconnectTries</span> <span class="token operator">:</span> Число <span class="token punctuation">.</span> <span class="token constant">MAX_VALUE</span> <span class="token punctuation">,</span></mark><mark> <span class="token literal-property property">reconnectInterval</span> <span class="token operator">:</span> <span class="token number">500</span> <span class="token punctuation">,</span></mark><mark> <span class="token literal-property property">ConnectTimeoutMS</span> <span class="token operator">:</span> <span class="token number">10000</span> <span class="token punctuation">,</span></mark><mark> <span class="token punctuation">}</span> <span class="token punctuation">;</span></mark> <span class="token operator">...</span>
Опция reconnectTries
сообщает Mongoose продолжать попытки подключения бесконечно, а reconnectInterval
определяет период между попытками подключения в миллисекундах. connectTimeoutMS
определяет 10 секунд как период ожидания драйвера Mongo перед неудачной попыткой подключения.
Теперь вы можете использовать новую константу options
в методе connect
Mongoose для точной настройки параметров подключения Mongoose. Вы также добавите обещание обрабатывать потенциальные ошибки соединения.
В настоящее время метод connect
Mongoose выглядит следующим образом:
~/node_project/db.js
1
... mongoose.connect(url, {useNewUrlParser: true});
Удалите существующий метод connect
и замените его следующим кодом, который включает константу options
и обещание:
~/node_project/db.js
1
<span class="token operator">...</span></code> мангуст <span class="token punctuation">.</span> <span class="token function">подключиться</span> <span class="token punctuation">(</span> URL <span class="token punctuation">,</span> параметры <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">тогда</span> <span class="token punctuation">(</span> <span class="token keyword">функция</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span><mark> консоль <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'MongoDB подключен'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span></mark><mark> <span class="token punctuation">}</span> <span class="token punctuation">)</span></mark><mark> <span class="token punctuation">.</span> <span class="token function">поймать</span> <span class="token punctuation">(</span> <span class="token keyword">функция</span> <span class="token punctuation">(</span> <span class="token parameter">ошибка</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span></mark><mark> консоль <span class="token punctuation">.</span> <span class="token function">журнал</span> <span class="token punctuation">(</span> ошибка <span class="token punctuation">)</span> <span class="token punctuation">;</span></mark><mark> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span></mark>
В случае успешного соединения ваша функция регистрирует соответствующее сообщение; в противном случае он catch
и зарегистрирует ошибку, что позволит вам устранить неполадку.
Готовый файл будет выглядеть так:
~/node_project/db.js
1
<span class="token keyword">const</span> mongoose <span class="token operator">=</span> <span class="token function">require</span> <span class="token punctuation">(</span> <span class="token string">'mongoose'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> <span class="token constant">MONGO_USERNAME</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_PASSWORD</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_HOSTNAME</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_PORT</span> <span class="token punctuation">,</span> <span class="token constant">MONGO_DB</span> <span class="token punctuation">}</span> <span class="token operator">=</span> process <span class="token punctuation">.</span> env <span class="token punctuation">;</span> <span class="token keyword">const</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">useNewUrlParser</span> <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> <span class="token literal-property property">reconnectTries</span> <span class="token operator">:</span> Number <span class="token punctuation">.</span> <span class="token constant">MAX_VALUE</span> <span class="token punctuation">,</span> <span class="token literal-property property">reconnectInterval</span> <span class="token operator">:</span> <span class="token number">500</span> <span class="token punctuation">,</span> <span class="token literal-property property">connectTimeoutMS</span> <span class="token operator">:</span> <span class="token number">10000</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> url <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">mongodb://</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">MONGO_USERNAME</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">:</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">MONGO_PASSWORD</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">@</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">MONGO_HOSTNAME</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">:</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">MONGO_PORT</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">/</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> <span class="token constant">MONGO_DB</span> <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token string">?authSource=admin</span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">;</span> mongoose <span class="token punctuation">.</span> <span class="token function">connect</span> <span class="token punctuation">(</span> url <span class="token punctuation">,</span> options <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">then</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">'MongoDB is connected'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">catch</span> <span class="token punctuation">(</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">err</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> err <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span>
Сохраните и закройте файл после завершения редактирования.
Теперь вы добавили устойчивость в код вашего приложения для обработки случаев, когда ваше приложение может не подключиться к вашей базе данных. Имея этот код, вы можете перейти к определению своих сервисов с помощью Compose.
Шаг 4 — Определение сервисов с помощью Docker Compose
После рефакторинга кода вы готовы написать файл docker-compose.yml
с определениями ваших сервисов. Служба в Compose — это работающий контейнер, а определения службы, которые вы включите в файл docker-compose.yml
, содержат информацию о том, как будет запускаться каждый образ контейнера. Инструмент Compose позволяет вам определить несколько сервисов для создания многоконтейнерных приложений.
Прежде чем определять свои службы, вы добавите в свой проект инструмент под названием wait-for
, чтобы гарантировать, что ваше приложение попытается подключиться к вашей базе данных только после завершения задач запуска базы данных. Этот сценарий-оболочка использует netcat
для опроса, принимает ли конкретный хост и порт TCP-соединения. Его использование позволяет вам контролировать попытки вашего приложения подключиться к вашей базе данных, проверяя, готова ли база данных принимать соединения.
Хотя Compose позволяет вам указывать зависимости между службами с помощью параметра depends_on
, этот порядок основан на том, запущен ли контейнер, а не на его готовности. Использование depends_on
не будет оптимальным для вашей настройки, поскольку вы хотите, чтобы ваше приложение подключалось только после завершения задач запуска базы данных, включая добавление пользователя и пароля в базу данных аутентификации admin
. Дополнительную информацию об использовании wait-for
и других инструментов для управления порядком запуска см. в соответствующих рекомендациях в документации Compose.
Откройте файл wait-for.sh
:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> -ожидание.sh</li></ol>
Введите следующий код в файл, чтобы создать функцию опроса:
~/node_project/app/wait-for.sh
1
<span class="token shebang important">#!/bin/sh</span> <span class="token comment"># original script: https://github.com/eficode/wait-for/blob/master/wait-for</span> <span class="token assign-left variable">TIMEOUT</span> <span class="token operator">=</span> <span class="token number">15</span> <span class="token assign-left variable">QUIET</span> <span class="token operator">=</span> <span class="token number">0</span> <span class="token function-name function">echoerr</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">" <span class="token variable">$QUIET</span> "</span> <span class="token parameter variable">-ne</span> <span class="token number">1</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">then</span> <span class="token builtin class-name">printf</span> <span class="token string">"%s <span class="token entity" title="п">n</span> "</span> <span class="token string">" <span class="token variable">$*</span> "</span> <span class="token operator"><span class="token file-descriptor important">1</span> ></span> <span class="token file-descriptor important">&2</span> <span class="token punctuation">;</span> <span class="token keyword">fi</span> <span class="token punctuation">}</span> <span class="token function-name function">usage</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token assign-left variable">exitcode</span> <span class="token operator">=</span> <span class="token string">" <span class="token variable">$1</span> "</span> <span class="token function">cat</span> <span class="token operator"><<</span> <span class="token string">USAGE <span class="token bash punctuation"><span class="token operator">></span> <span class="token file-descriptor important">&2</span></span> Usage: <span class="token variable">$cmdname</span> host:port [-t timeout] [-- command args] -q | --quiet Do not output any status messages -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout -- COMMAND ARGS Execute command with args after the test finishes USAGE</span> <span class="token builtin class-name">exit</span> <span class="token string">" <span class="token variable">$exitcode</span> "</span> <span class="token punctuation">}</span> <span class="token function-name function">wait_for</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">for</span> <span class="token for-or-select variable">i</span> <span class="token keyword">in</span> <span class="token variable"><span class="token variable">`</span> <span class="token function">seq</span> $TIMEOUT <span class="token variable">`</span></span> <span class="token punctuation">;</span> <span class="token keyword">do</span> <span class="token function">nc</span> <span class="token parameter variable">-z</span> <span class="token string">" <span class="token variable">$HOST</span> "</span> <span class="token string">" <span class="token variable">$PORT</span> "</span> <span class="token operator">></span> /dev/null <span class="token operator"><span class="token file-descriptor important">2</span> ></span> <span class="token file-descriptor important">&1</span> <span class="token assign-left variable">result</span> <span class="token operator">=</span> <span class="token variable">$?</span> <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token variable">$result</span> <span class="token parameter variable">-eq</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">then</span> <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token variable">$#</span> <span class="token parameter variable">-gt</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">then</span> <span class="token builtin class-name">exec</span> <span class="token string">" <span class="token variable">$@</span> "</span> <span class="token keyword">fi</span> <span class="token builtin class-name">exit</span> <span class="token number">0</span> <span class="token keyword">fi</span> <span class="token function">sleep</span> <span class="token number">1</span> <span class="token keyword">done</span> <span class="token builtin class-name">echo</span> <span class="token string">"Operation timed out"</span> <span class="token operator">></span> <span class="token file-descriptor important">&2</span> <span class="token builtin class-name">exit</span> <span class="token number">1</span> <span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">[</span> <span class="token variable">$#</span> <span class="token parameter variable">-gt</span> <span class="token number">0</span> <span class="token punctuation">]</span> <span class="token keyword">do</span> <span class="token keyword">case</span> <span class="token string">" <span class="token variable">$1</span> "</span> <span class="token keyword">in</span> *:* <span class="token punctuation">)</span> <span class="token assign-left variable">HOST</span> <span class="token operator">=</span> <span class="token variable"><span class="token variable">$(</span> <span class="token builtin class-name">printf</span> <span class="token string">"%s <span class="token entity" title="п">n</span> "</span> <span class="token string">" <span class="token variable">$1</span> "</span> <span class="token operator">|</span> <span class="token function">cut</span> <span class="token parameter variable">-d</span> <span class="token builtin class-name">:</span> <span class="token parameter variable">-f</span> <span class="token number">1</span> <span class="token variable">)</span></span> <span class="token assign-left variable">PORT</span> <span class="token operator">=</span> <span class="token variable"><span class="token variable">$(</span> <span class="token builtin class-name">printf</span> <span class="token string">"%s <span class="token entity" title="п">n</span> "</span> <span class="token string">" <span class="token variable">$1</span> "</span> <span class="token operator">|</span> <span class="token function">cut</span> <span class="token parameter variable">-d</span> <span class="token builtin class-name">:</span> <span class="token parameter variable">-f</span> <span class="token number">2</span> <span class="token variable">)</span></span> <span class="token builtin class-name">shift</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">;</span> <span class="token parameter variable">-q</span> <span class="token operator">|</span> --quiet <span class="token punctuation">)</span> <span class="token assign-left variable">QUIET</span> <span class="token operator">=</span> <span class="token number">1</span> <span class="token builtin class-name">shift</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">;</span> -t <span class="token punctuation">)</span> <span class="token assign-left variable">TIMEOUT</span> <span class="token operator">=</span> <span class="token string">" <span class="token variable">$2</span> "</span> <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">" <span class="token variable">$TIMEOUT</span> "</span> <span class="token operator">=</span> <span class="token string">""</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">then</span> <span class="token builtin class-name">break</span> <span class="token punctuation">;</span> <span class="token keyword">fi</span> <span class="token builtin class-name">shift</span> <span class="token number">2</span> <span class="token punctuation">;</span> <span class="token punctuation">;</span> <span class="token parameter variable">--timeout</span> <span class="token operator">=</span> * <span class="token punctuation">)</span> <span class="token assign-left variable">TIMEOUT</span> <span class="token operator">=</span> <span class="token string">" <span class="token variable">${1 <span class="token operator">#</span> *=}</span> "</span> <span class="token builtin class-name">shift</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">;</span> -- <span class="token punctuation">)</span> <span class="token builtin class-name">shift</span> <span class="token builtin class-name">break</span> <span class="token punctuation">;</span> <span class="token punctuation">;</span> --help <span class="token punctuation">)</span> usage <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token punctuation">;</span> * <span class="token punctuation">)</span> echoerr <span class="token string">"Unknown argument: <span class="token variable">$1</span> "</span> usage <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">;</span> <span class="token keyword">esac</span> <span class="token keyword">done</span> <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">" <span class="token variable">$HOST</span> "</span> <span class="token operator">=</span> <span class="token string">""</span> <span class="token parameter variable">-o</span> <span class="token string">" <span class="token variable">$PORT</span> "</span> <span class="token operator">=</span> <span class="token string">""</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">then</span> echoerr <span class="token string">"Error: you need to provide a host and port to test."</span> usage <span class="token number">2</span> <span class="token keyword">fi</span> wait_for <span class="token string">" <span class="token variable">$@</span> "</span>
Сохраните и закройте файл, когда закончите добавлять код.
Сделайте скрипт исполняемым:
1
<ol><li data-prefix="$"> <span class="token function">chmod</span> +x ожидание-for.sh</li></ol>
Затем откройте файл docker-compose.yml
:
1
<ol><li data-prefix="$"> <span class="token function">нано</span> docker-compose.yml</li></ol>
Сначала определите службу приложения nodejs
, добавив в файл следующий код:
~/node_project/docker-compose.yml
1
<span class="token key atrule">version</span> <span class="token punctuation">:</span> <span class="token string">'3'</span> <span class="token key atrule">services</span> <span class="token punctuation">:</span> <span class="token key atrule">nodejs</span> <span class="token punctuation">:</span> <span class="token key atrule">build</span> <span class="token punctuation">:</span> <span class="token key atrule">context</span> <span class="token punctuation">:</span> . <span class="token key atrule">dockerfile</span> <span class="token punctuation">:</span> Dockerfile <span class="token key atrule">image</span> <span class="token punctuation">:</span> nodejs <span class="token key atrule">container_name</span> <span class="token punctuation">:</span> nodejs <span class="token key atrule">restart</span> <span class="token punctuation">:</span> unless <span class="token punctuation">-</span> stopped <span class="token key atrule">env_file</span> <span class="token punctuation">:</span> .env <span class="token key atrule">environment</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> MONGO_USERNAME=$MONGO_USERNAME <span class="token punctuation">-</span> MONGO_PASSWORD=$MONGO_PASSWORD <span class="token punctuation">-</span> MONGO_HOSTNAME=db <span class="token punctuation">-</span> MONGO_PORT=$MONGO_PORT <span class="token punctuation">-</span> MONGO_DB=$MONGO_DB <span class="token key atrule">ports</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">"80:8080"</span> <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> . <span class="token punctuation">:</span> /home/node/app <span class="token punctuation">-</span> node_modules <span class="token punctuation">:</span> /home/node/app/node_modules <span class="token key atrule">networks</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> app <span class="token punctuation">-</span> network <span class="token key atrule">command</span> <span class="token punctuation">:</span> ./wait <span class="token punctuation">-</span> for.sh db <span class="token punctuation">:</span> 27017 <span class="token punctuation">-</span> <span class="token punctuation">-</span> /home/node/app/node_modules/.bin/nodemon app.js
Определение службы nodejs
включает следующие параметры:
-
build
: определяет параметры конфигурации, включая context
и dockerfile
, которые будут применяться, когда Compose создает образ приложения. Если вы хотите использовать существующий образ из реестра, такого как Docker Hub, вместо этого вы можете использовать инструкцию image
с информацией о вашем имени пользователя, репозитории и теге изображения.
-
context
: определяет контекст сборки образа — в данном случае текущий каталог проекта.
-
dockerfile
: указывает файл Dockerfile
в текущем каталоге проекта, который Compose будет использовать для создания образа приложения. Дополнительные сведения об этом файле см. в разделе «Как создать приложение Node.js с помощью Docker».
-
image
, container_name
: они присваивают имена изображению и контейнеру.
-
restart
: определяет политику перезапуска. По умолчанию установлено значение no
, но вы настроили перезапуск контейнера, если он не остановлен.
-
env_file
: сообщает Compose, что вы хотите добавить переменные среды из файла с именем .env
, расположенного в вашем контексте сборки.
-
environment
: использование этой опции позволяет вам добавить настройки соединения Mongo, определенные вами в файле .env
. Обратите внимание, что вы не устанавливаете для NODE_ENV
значение development
, поскольку это поведение Express по умолчанию, если NODE_ENV
не установлен. При переходе на производство вы можете установить это значение на production
, чтобы включить кэширование представлений и менее подробные сообщения об ошибках. Также обратите внимание, что вы указали контейнер базы данных db
в качестве хоста, как описано в шаге 2.
-
ports
: это сопоставляет порт 80
на хосте с портом 8080
в контейнере.
-
volumes
: здесь вы включаете два типа монтирования:
- Первый — это привязка, которая монтирует код вашего приложения на хосте в каталог
/home/node/app
контейнера. Это облегчит быструю разработку, поскольку любые изменения, внесенные вами в код хоста, будут немедленно внесены в контейнер.
- Второй — именованный том
node_modules
. Когда Docker запускает инструкцию npm install
указанную в Dockerfile
приложения, npm
создаст в контейнере новый каталог node_modules
, который включает пакеты, необходимые для запуска приложения. Однако только что созданное привязывание скроет этот вновь созданный каталог node_modules
. Поскольку node_modules
на хосте пуст, привязка сопоставит пустой каталог с контейнером, переопределяя новый каталог node_modules
и предотвращая запуск вашего приложения. Именованный том node_modules
решает эту проблему, сохраняя содержимое каталога /home/node/app/node_modules
и монтируя его в контейнер, скрывая привязку.
Keep the following points in mind when using this approach :
-
Ваша привязка смонтирует содержимое каталога node_modules
в контейнере на хост, и этот каталог будет принадлежать пользователю root
, поскольку именованный том был создан Docker.
-
Если у вас уже есть каталог node_modules
на хосте, он переопределит каталог node_modules
, созданный в контейнере. Настройка, которую вы создаете в этом руководстве, предполагает, что у вас not уже существующего каталога node_modules
и вы не будете работать с npm
на своем хосте. Это соответствует двенадцатифакторному подходу к разработке приложений, который сводит к минимуму зависимости между средами выполнения.
-
networks
: указывает, что ваша служба приложений присоединится к сети app-network
, которую вы определите в нижней части файла.
-
command
: этот параметр позволяет указать команду, которая должна выполняться при запуске образа Compose. Обратите внимание, что это переопределит инструкцию CMD
, которую вы установили в нашем приложении Dockerfile
. Здесь вы запускаете приложение, используя сценарий wait-for
, который опрашивает службу db
на порту 27017
, чтобы проверить, готова ли служба базы данных. После успешного завершения теста готовности скрипт выполнит заданную вами команду /home/node/app/node_modules/.bin/nodemon app.js
, чтобы запустить приложение с помощью nodemon
. Это гарантирует, что любые будущие изменения, которые вы внесете в свой код, будут перезагружены без необходимости перезапускать приложение.
Затем создайте службу db
, добавив следующий код под определением службы приложения:
~/node_project/docker-compose.yml
1
<span class="token punctuation">...</span> <span class="token key atrule">db</span> <span class="token punctuation">:</span> <span class="token key atrule">image</span> <span class="token punctuation">:</span> mongo <span class="token punctuation">:</span> 4.1.8 <span class="token punctuation">-</span> xenial <span class="token key atrule">container_name</span> <span class="token punctuation">:</span> db <span class="token key atrule">restart</span> <span class="token punctuation">:</span> unless <span class="token punctuation">-</span> stopped <span class="token key atrule">env_file</span> <span class="token punctuation">:</span> .env <span class="token key atrule">environment</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME <span class="token punctuation">-</span> MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> dbdata <span class="token punctuation">:</span> /data/db <span class="token key atrule">networks</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> app <span class="token punctuation">-</span> network
Некоторые настройки, определенные для службы nodejs
, остались прежними, но вы также внесли следующие изменения в определения image
, environment
и volumes
:
-
image
: Чтобы создать этот сервис, Compose извлечет образ Mongo 4.1.8-xenial
из Docker Hub. Вы закрепляете определенную версию, чтобы избежать возможных конфликтов в будущем при изменении образа Mongo. Дополнительные сведения о закреплении версий см. в документации Docker, посвященной передовым практикам Dockerfile.
-
MONGO_INITDB_ROOT_USERNAME
, MONGO_INITDB_ROOT_PASSWORD
: образ mongo
делает эти переменные среды доступными, чтобы вы могли изменить инициализацию экземпляра базы данных. MONGO_INITDB_ROOT_USERNAME
и MONGO_INITDB_ROOT_PASSWORD
вместе создают пользователя root
в базе данных аутентификации admin
и обеспечивают включение аутентификации при запуске контейнера. Вы установили MONGO_INITDB_ROOT_USERNAME
и MONGO_INITDB_ROOT_PASSWORD
, используя значения из вашего файла .env
, который вы передаете службе db
с помощью опции env_file
. Это означает, что ваш пользователь приложения sammy
будет пользователем root
в экземпляре базы данных с доступом ко всем административным и операционным привилегиям этой роли. При работе в рабочей среде вам потребуется создать выделенного пользователя приложения с соответствующими привилегиями.
Note: Имейте в виду, что эти переменные не вступят в силу, если вы запустите контейнер с существующим каталогом данных.
-
dbdata:/data/db
: именованный том dbdata
сохранит данные, хранящиеся в каталоге данных Mongo по умолчанию, /data/db
. Это гарантирует, что вы не потеряете данные в случае остановки или удаления контейнеров.
Служба db
также была добавлена в сеть сети app-network
с опцией networks
.
В качестве последнего шага добавьте определения тома и сети в конец файла:
~/node_project/docker-compose.yml
1
<span class="token punctuation">...</span> <span class="token key atrule">networks</span> <span class="token punctuation">:</span> <span class="token key atrule">app-network</span> <span class="token punctuation">:</span> <span class="token key atrule">driver</span> <span class="token punctuation">:</span> bridge <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token key atrule">dbdata</span> <span class="token punctuation">:</span> <span class="token key atrule">node_modules</span> <span class="token punctuation">:</span>
Пользовательская app-network
мостовой сети обеспечивает связь между вашими контейнерами, поскольку они находятся на одном хосте демона Docker. Это оптимизирует трафик и связь внутри приложения, поскольку открывает все порты между контейнерами в одной мостовой сети, не открывая при этом порты внешнему миру. Таким образом, ваши контейнеры db
и nodejs
могут взаимодействовать друг с другом, и вам нужно только открыть порт 80
для внешнего доступа к приложению.
Ваш ключ volumes
верхнего уровня определяет тома dbdata
и node_modules
. Когда Docker создает тома, содержимое тома сохраняется в части файловой системы хоста /var/lib/docker/volumes/
, которой управляет Docker. Содержимое каждого тома хранится в каталоге /var/lib/docker/volumes/
и монтируется к любому контейнеру, использующему этот том. Таким образом, данные с информацией об акулах, которые создадут ваши пользователи, сохранятся в томе dbdata
, даже если вы удалите и заново создадите контейнер db
.
Готовый файл docker-compose.yml
будет выглядеть так:
~/node_project/docker-compose.yml
1
<span class="token key atrule">version</span> <span class="token punctuation">:</span> <span class="token string">'3'</span> <span class="token key atrule">services</span> <span class="token punctuation">:</span> <span class="token key atrule">nodejs</span> <span class="token punctuation">:</span> <span class="token key atrule">build</span> <span class="token punctuation">:</span> <span class="token key atrule">context</span> <span class="token punctuation">:</span> . <span class="token key atrule">dockerfile</span> <span class="token punctuation">:</span> Dockerfile <span class="token key atrule">image</span> <span class="token punctuation">:</span> nodejs <span class="token key atrule">container_name</span> <span class="token punctuation">:</span> nodejs <span class="token key atrule">restart</span> <span class="token punctuation">:</span> unless <span class="token punctuation">-</span> stopped <span class="token key atrule">env_file</span> <span class="token punctuation">:</span> .env <span class="token key atrule">environment</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> MONGO_USERNAME=$MONGO_USERNAME <span class="token punctuation">-</span> MONGO_PASSWORD=$MONGO_PASSWORD <span class="token punctuation">-</span> MONGO_HOSTNAME=db <span class="token punctuation">-</span> MONGO_PORT=$MONGO_PORT <span class="token punctuation">-</span> MONGO_DB=$MONGO_DB <span class="token key atrule">ports</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token string">"80:8080"</span> <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> . <span class="token punctuation">:</span> /home/node/app <span class="token punctuation">-</span> node_modules <span class="token punctuation">:</span> /home/node/app/node_modules <span class="token key atrule">networks</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> app <span class="token punctuation">-</span> network <span class="token key atrule">command</span> <span class="token punctuation">:</span> ./wait <span class="token punctuation">-</span> for.sh db <span class="token punctuation">:</span> 27017 <span class="token punctuation">-</span> <span class="token punctuation">-</span> /home/node/app/node_modules/.bin/nodemon app.js <span class="token key atrule">db</span> <span class="token punctuation">:</span> <span class="token key atrule">image</span> <span class="token punctuation">:</span> mongo <span class="token punctuation">:</span> 4.1.8 <span class="token punctuation">-</span> xenial <span class="token key atrule">container_name</span> <span class="token punctuation">:</span> db <span class="token key atrule">restart</span> <span class="token punctuation">:</span> unless <span class="token punctuation">-</span> stopped <span class="token key atrule">env_file</span> <span class="token punctuation">:</span> .env <span class="token key atrule">environment</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> MONGO_INITDB_ROOT_USERNAME=$MONGO_USERNAME <span class="token punctuation">-</span> MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASSWORD <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> dbdata <span class="token punctuation">:</span> /data/db <span class="token key atrule">networks</span> <span class="token punctuation">:</span> <span class="token punctuation">-</span> app <span class="token punctuation">-</span> network <span class="token key atrule">networks</span> <span class="token punctuation">:</span> <span class="token key atrule">app-network</span> <span class="token punctuation">:</span> <span class="token key atrule">driver</span> <span class="token punctuation">:</span> bridge <span class="token key atrule">volumes</span> <span class="token punctuation">:</span> <span class="token key atrule">dbdata</span> <span class="token punctuation">:</span> <span class="token key atrule">node_modules</span> <span class="token punctuation">:</span>
Сохраните и закройте файл, когда закончите редактирование.
Имея определения служб, вы готовы запустить приложение.
Шаг 5 — Тестирование приложения
Имея файл docker-compose.yml
, вы можете создавать свои сервисы с помощью команды docker-compose up
. Вы также можете проверить, сохранятся ли ваши данные, остановив и удалив контейнеры с помощью docker-compose down
.
Сначала создайте образы контейнеров и создайте службы, запустив docker-compose up
с флагом -d
, который затем запустит контейнеры nodejs
и db
в фоновом режиме:
1
<ol><li data-prefix="$"> <span class="token function">докер-составить</span> <span class="token parameter variable">-d</span></li></ol>
Вывод подтверждает, что ваши сервисы созданы:
1
<div class="secondary-code-label" title="Выход"> Выход</div> ... Создание базы данных... выполнено Создание nodejs... выполнено
Более подробную информацию о процессах запуска вы также можете получить, отобразив вывод журнала сервисов:
1
<ol><li data-prefix="$"> <span class="token function">docker-compose</span> журналы</li></ol>
Если все началось правильно, результат будет следующий:
1
<div class="secondary-code-label" title="Выход"> Выход</div> ... узлы | [nodemon] запуск `node app.js` nodejs | Пример приложения, прослушивающего 8080! узлы | MongoDB подключен... db | 2019-02-22T17:26:27.329+0000 Я ДОСТУП [conn2] Успешно прошел аутентификацию в качестве участника<mark> Сэмми</mark> в администраторе
Вы также можете проверить состояние ваших контейнеров с помощью docker-compose ps
:
1
<ol><li data-prefix="$"> <span class="token function">docker-compose</span> <span class="token function">PS</span></li></ol>
Вывод показывает, что ваши контейнеры запущены:
1
<div class="secondary-code-label" title="Выход"> Выход</div> Имя Состояние команды Порты ---------------------------------------------- ------------------------ db docker-entrypoint.sh mongod Up 27017/tcp nodejs ./wait-for.sh db:27017 -- .. Вверх 0.0.0.0:80->8080/tcp
Когда ваши службы запущены, вы можете посетить http:// your_server_ip
в браузере:
Нажмите кнопку Get Shark Info , чтобы перейти на страницу с формой ввода, где вы можете ввести имя акулы и описание общего характера этой акулы:
В форму добавьте акулу по вашему выбору. Для этой демонстрации добавьте Megalodon Shark
в поле Shark Name и Ancient
в поле Shark Character :
Нажмите кнопку Submit , и вам откроется страница с этой информацией об акулах:
В качестве последнего шага проверьте, что только что введенные данные сохранятся, если вы удалите контейнер базы данных.
Вернувшись к своему терминалу, введите следующую команду, чтобы остановить и удалить контейнеры и сеть:
1
<ol><li data-prefix="$"> <span class="token function">docker-compose</span> вниз</li></ol>
Обратите внимание, что вы не включаете опцию --volumes
; следовательно, ваш том dbdata
не удаляется.
Следующий вывод подтверждает, что ваши контейнеры и сеть были удалены:
1
<div class="secondary-code-label" title="Выход"> Выход</div> Остановка nodejs... готово Остановка db... готово Удаление nodejs... готово Удаление db... готово Удаление сети node_project_app-network
Воссоздайте контейнеры:
1
<ol><li data-prefix="$"> <span class="token function">докер-составить</span> <span class="token parameter variable">-d</span></li></ol>
Теперь вернитесь к форме информации об акулах:
Введите новую акулу по вашему выбору. В этом примере будут использоваться Whale Shark
и Large
:
Нажав Submit , вы заметите, что новая акула была добавлена в коллекцию акул в вашей базе данных без потери уже введенных вами данных:
Теперь ваше приложение работает в контейнерах Docker с включенным сохранением данных и синхронизацией кода.
Заключение
Следуя этому руководству, вы создали настройку разработки для своего приложения Node с использованием контейнеров Docker. Вы сделали свой проект более модульным и переносимым, извлекая конфиденциальную информацию и отделяя состояние вашего приложения от кода приложения. Вы также настроили шаблонный файл docker-compose.yml
, который можно редактировать по мере изменения потребностей и требований разработки.
По мере разработки вам может быть интересно узнать больше о разработке приложений для контейнерных и облачных рабочих процессов. Дополнительные сведения по этим темам см. в разделах «Архитектура приложений для Kubernetes» и «Модернизация приложений для Kubernetes».
Чтобы узнать больше о коде, используемом в этом руководстве, см. разделы «Как создать приложение Node.js с помощью Docker» и «Как интегрировать MongoDB с вашим приложением Node». Информацию о развертывании приложения Node с обратным прокси-сервером Nginx с использованием контейнеров см. в разделе «Как защитить контейнерное приложение Node.js с помощью Nginx, Let's Encrypt и Docker Compose».