В этой статье поговорим о том, как разработать и запустить бэкэнд на Node.js-Express и фронтенд на React в контейнере Docker.
Docker дает разработчикам возможность помещать свои приложения в контейнеры. Эти контейнеры могут работать на любом устройстве, на котором установлен Docker, и приложения будут идентичны. С помощью этого сервиса можно клонировать кодовую базу на нескольких системах – везде будет одинаковый результат.
В рабочих процессах CI/CD и средах тестирования DevOps широко используется Docker: по сути, он представляет собой набор программных инструментов, которые можно использовать совместно. Kubernetes — это инструмент, который используется для работы с несколькими контейнерами Docker, но в гораздо большем масштабе.
Разберём, как разработать и запустить бэкэнд на Node.js-Express и фронтенд на React внутри контейнера Docker.
Запуск бэкенда на Node.js-Express в Docker
Когда убедились, что на компьютере установлен и запущен Docker, переходим к следующему шагу.
Используя командную строку, переходим в каталог, например на рабочий стол, а затем выполняем следующие команды.
mkdir my-app-docker
cd my-app-docker
touch docker-compose.yml
mkdir api
cd api
npm init -y
npm i express
touch app.js Dockerfile .dockerignore
cd ..
Мы настроили серверную часть – api и создали несколько файлов Docker. Теперь откройте проект в редакторе кода и добавьте приведенный ниже код в соответствующие файлы.
Это нужно поместить в файл docker-compose.yml. Обращайте внимание на форматирование YAML, иначе при запуске Docker выдаст ошибку.
version: '3.8'
services:
api:
build: ./api
container_name: api_backend
ports:
- '4000:4000'
volumes:
- ./api:/app
- ./app/node_modules
Следующий код нужно добавить в файл app.js:
const express = require('express');
const app = express();
const port = process.env.PORT || 4000;
app.get('/', (req, res) => {
res.send('Home Route');
});
app.listen(port, () =>
console.log(`Server running on port ${port}, http://localhost:${port}`)
);
Эту строку – в файл .dockerignore :
node_modules
Этот кода – в файл Dockerfile:
FROM node:16-alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 4000
CMD ["node", "app.js"]
Наконец, в файл package.json:
"scripts": {
"start": "node app.js"
},
Использование Nodemon для автоматического перезапуска сервера при внесении изменений.
Если вы хотите, чтобы сервер перезагружался каждый раз, когда вы вносите изменения в файлы в бэкэнде, вы можете настроить его на использование Nodemon. Вам нужно лишь обновить файлы Dockerfile и package.json внутри папки api.
Обновите файл Dockerfile, используя приведенный ниже код. Мы установим Nodemon при запуске и используем dev в качестве команды запуска.
FROM node:16-alpine
RUN npm install -g nodemon
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 4000
CMD ["npm", "run", "dev"]
Добавьте в файл package.json скрипт для Nodemon.
"scripts": {
"start": "node app.js",
"dev": "nodemon -L app.js"
},
Мы только что создали базовое приложение Node.js-Express, которое работает на порте 4000. Этот порт также связан с 4000 в Docker, что позволяет нам запускать его в Docker-контейнере.
Запуск серверов
Чтобы запустить сервер вне контейнера Docker как обычно на Node, просто запустите приведенный ниже код в командной строке. Вы должны быть уверены, что находитесь внутри папки api. Если вы перейдете на http://localhost:4000, вы должны увидеть основной пусть (home route) в окне браузера.
npm run start
Для запуска приложения Node.js-Express внутри Docker требуется другая команда. Во-первых, вам нужно находиться в корневой папке, где находится файл docker-compose.yml. Теперь запустите приведенную ниже команду, и она должна работать внутри контейнера Docker.
Важно отследить, что сервер узла не запущен, потому что на порте 4000 может работать только один сервер.
docker-compose up
По адресу http://localhost:4000 вы должны видеть основной (домашний) путь.
Вы можете остановить сервер с помощью приведенной ниже команды либо перейти в приложение Docker и остановить запуск контейнера.
docker-compose down
Запуск фронтенда на React в Docker
Теперь давайте создадим фронтенд на React. Используя командную строку, переместитесь в корневую папку для my-app-docker. Запустите приведенные ниже команды, чтобы настроить проект.
npx create-react-app client
cd client
touch .dockerignore Dockerfile
Теперь добавьте код ниже в соответствующие файлы.
Эту строку – в файл .dockerignore .
node_modules
Этот код – в файл Dockerfile .
FROM node:17-alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Наконец, добавьте в файл docker-compose.yml в корневой папке приведенный ниже код. Таким образом мы добавили клиентский раздел внизу с настройками для запуска React внутри контейнера Docker. Обращайте внимание на форматирование YAML, иначе при запуске Docker выдаст ошибку.
version: '3.8'
services:
api:
build: ./api
container_name: api_backend
ports:
- '4000:4000'
volumes:
- ./api:/app
- ./app/node_modules
client:
build: ./client
container_name: client_frontend
ports:
- '3000:3000'
volumes:
- ./client:/app
- ./app/node_modules
stdin_open: true
tty: true
Чтобы запустить сервер вне контейнера Docker как обычно на Node, запустите приведенный ниже код в командной строке. Убедитесь, что вы находитесь внутри папки клиента. По адресу http://localhost:3000 вы должны увидеть основной (домашний) путь в окне браузера.
npm run start
Для запуска приложения React внутри Docker требуется другая команда. Во-первых, вам нужно находиться в корневой папке, где расположен файл docker-compose.yml. Теперь запустите приведенную ниже команду, и она должна работать внутри контейнера Docker.
Важно отследить, что сервер приложения React не запущен, потому что на порте 3000 может работать только один сервер.
docker-compose up
По адресу http://localhost:3000 вы должны увидеть основной (домашний) путь в окне браузера.
Вы можете остановить сервер с помощью приведенной ниже команды либо перейти в приложение Docker и остановить запуск контейнера.
docker-compose down
С такими настройками вы можете одновременно запускать бэкенд Node.js и фронтенд React внутри Docker. Если вы столкнулись с какими-либо ошибками, возможно, поможет открыть настольное приложение Docker и удалить все образы, связанные с этим проектом. Затем попробуйте снова запустить команду docker-compose up – на этот раз все должно работать как положено.
Надеемся, этот перевод был для вас полезен!
Комментарии (11)
raamid
02.08.2022 14:35Скажите пожалуйста, есть ли возможность при помощи nodemon отслеживать изменения файлов снаружи контейнера? Разработка ведется снаружи и очень желательно, чтобы при сохранении файла старый сервер внутри контейнера останавливался, новый запускался и обновлялась вкладка браузера когда завершится запуск сервера.
Штатных средств не нашел, в итоге использую собственный велосипед на базе chokidar + websockets + puppeteer. Но все равно, не оставляет чувство, что я упустил что-то и что такой важный кейс разработки кто-то автоматизировал должным образом.
green_fenix
03.08.2022 08:50В коде из статьи вроде так и должно работать - в описании сервиса фронта папка ./client монтируется в контейнер как /app, так что все локальные изменения будут видны и в контейнере
raamid
03.08.2022 09:43Наверное я не совсем хорошо объяснил суть проблемы. Nodemon успешно работает внутри контейнера: если я захожу внутрь контейнера и там редактирую файл например при помощи vim, то nodemon это отслеживает и перезапускает сервер. Однако, когда я редактирую тот же файл снаружи контейнера, например при помощи VS Code, то nodemon, работающий внутри контейнера не может отследить изменение
dvserg
03.08.2022 09:48Смонтировать внешний том внутрь контейнера можно?
raamid
03.08.2022 11:34Смонтировано. И вот как раз в смонтированной папке nodemon, который работает внутри контейнера, не отслеживает изменения, которые производятся в той же смонтированной папке в хостовой ОС. Т.е., файлы по факту меняются, но nodemon не получает события об их изменении.
Иными словами, nodemon, который работает в линуксовом контейнере не получает сообщений, когда я снаружи контейнера в винде нажимаю Ctrl+S в виндовом блокноте.
someone_unimportant
03.08.2022 17:10Не знаю, насколько это правильно, но я использую polling во время разработки чтобы сервер в Docker видел изменения. Другого решения я не нашёл. nodemon тоже так может, но написано, что это "должно быть крайней мерой", потому что будет поллить все файлы, которые найдёт.
monochromer
03.08.2022 10:22+2С помощью этого сервиса можно клонировать кодовую базу на нескольких системах – везде будет одинаковый результат.
Чтобы был действительно одинаковый результат, нужно использовать
package-lock.json
:COPY package.json package-lock.json RUN npm ci
md_backend_binance
03.08.2022 20:11не понял зачем nodemone в контейнере если при любых изменениях вы делаете docker-compose up и происходит перезапуск контейнера и соответственно перезапуск nodejs или это имелось виду не продакшен а чисто для локальной разработки?
dvserg
Как в Россельхозбанке сейчас прогресс IT в целом?