В этой статье поговорим о том, как разработать и запустить бэкэнд на Node.js-Express и фронтенд на React в контейнере Docker.

Published in
JavaScript in Plain
Published in JavaScript in Plain

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)


  1. dvserg
    02.08.2022 12:35

    Как в Россельхозбанке сейчас прогресс IT в целом?


  1. raamid
    02.08.2022 14:35

    Скажите пожалуйста, есть ли возможность при помощи nodemon отслеживать изменения файлов снаружи контейнера? Разработка ведется снаружи и очень желательно, чтобы при сохранении файла старый сервер внутри контейнера останавливался, новый запускался и обновлялась вкладка браузера когда завершится запуск сервера.

    Штатных средств не нашел, в итоге использую собственный велосипед на базе chokidar + websockets + puppeteer. Но все равно, не оставляет чувство, что я упустил что-то и что такой важный кейс разработки кто-то автоматизировал должным образом.


    1. dolfinus
      02.08.2022 23:42

      nodemon -L разве не это делает?


      1. raamid
        04.08.2022 13:38

        В том-то и дело, что эта опция активирует отслеживание через polling. На крупных проектах нужно будет увеличивать интервал до нескольких секунд, а это уже убивает смысл автоматического рестарта сервера.


    1. green_fenix
      03.08.2022 08:50

      В коде из статьи вроде так и должно работать - в описании сервиса фронта папка ./client монтируется в контейнер как /app, так что все локальные изменения будут видны и в контейнере


      1. raamid
        03.08.2022 09:43

        Наверное я не совсем хорошо объяснил суть проблемы. Nodemon успешно работает внутри контейнера: если я захожу внутрь контейнера и там редактирую файл например при помощи vim, то nodemon это отслеживает и перезапускает сервер. Однако, когда я редактирую тот же файл снаружи контейнера, например при помощи VS Code, то nodemon, работающий внутри контейнера не может отследить изменение


        1. dvserg
          03.08.2022 09:48

          Смонтировать внешний том внутрь контейнера можно?


          1. raamid
            03.08.2022 11:34

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

            Иными словами, nodemon, который работает в линуксовом контейнере не получает сообщений, когда я снаружи контейнера в винде нажимаю Ctrl+S в виндовом блокноте.


            1. someone_unimportant
              03.08.2022 17:10

              Не знаю, насколько это правильно, но я использую polling во время разработки чтобы сервер в Docker видел изменения. Другого решения я не нашёл. nodemon тоже так может, но написано, что это "должно быть крайней мерой", потому что будет поллить все файлы, которые найдёт.


  1. monochromer
    03.08.2022 10:22
    +2

    С помощью этого сервиса можно клонировать кодовую базу на нескольких системах – везде будет одинаковый результат.

    Чтобы был действительно одинаковый результат, нужно использовать package-lock.json:

    COPY package.json package-lock.json
    RUN npm ci


  1. md_backend_binance
    03.08.2022 20:11

    не понял зачем nodemone в контейнере если при любых изменениях вы делаете docker-compose up и происходит перезапуск контейнера и соответственно перезапуск nodejs или это имелось виду не продакшен а чисто для локальной разработки?