docker_express_js.md 8.4 KB

Создание образа АПИ (express.js). Настройка сети

Предполагается, что АПИ у вас уже написано (для C# и python создание образа рассмотрим на следующих занятиях)

Нам нужна не простая рыба, а АПИ работающее с БД (чтобы задействовать контейнер test_mysql из прошлой лекции). Я накидал простенькое АПИ на основе прошлогодней инструкции.

Код лежит в каталоге docker/api. Весь я его здесь описывать не буду, сосредоточусь только на важных моментах:

  1. В файле .sequelizerc не забудьте указать порт, если он не стандартный

    module.exports = {
        'url': 'mysql://root:toor@127.0.0.1:3308/mydb'
    }
    
  2. Данные в базу накатываем командой npx sequelize-cli db:seed:all

Если всё сделано правильно, то АПИ должен работать и возвращать список жанров:

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

npx sequelize-cli db:seed:undo

Создание образа

При создании образа мы будем копировать в него наш проект, при этом мы должны помнить про безопасность и не хранить в образе пароли, плюс не нужно копировать каталог node_modules, так как в образе проект будет собираться заново.

Для игнорирования файлов нужно добавить в каталог с проектом файл .dockerignore, в который добавить файл .sequelizerc и каталог node_modules (формат у файла такой же как у .gitignore)

.sequelizerc
node_modules

В Dockerfile можно прописать только одну команду (CMD) для запуска приложения, а нам перед запуском нужно запустить миграцию. Для таких случаев в Dockerfile можно прописать не отдельную команду, а скрипт. Для этого служит команда ENTRYPOINT

Создадим в каталоге проекта файл entrypoint.sh:

#!/bin/sh
# накатываем начальные данные
npx sequelize-cli db:seed:all

# запускаем сервер
exec node index.js

Теперь пишем Dockerfile:

# создаем образ на основе Node.js версии 20 на основе минималистичного linux-образа alpine
FROM node:20-alpine

# устанавливаем рабочую директорию
WORKDIR /app

# копируем package.json и package-lock.json
COPY package*.json ./

# устанавливаем зависимости (как раз тут будет заполнен каталог node_modules)
RUN npm install

# копируем остальные файлы проекта
COPY . .

# открываем порт 3000
EXPOSE 3000

# запускаем сервер Express.js - вместо простого запуска будем использовать ENTRYPOINT
# CMD ["node", "index.js"]

# даем права на выполнение скрипту
RUN chmod 777 ./entrypoint.sh
# точка входа 
ENTRYPOINT [ "./entrypoint.sh" ]

Собираем образ

docker build -t test-api .

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

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

По-умолчанию используется режим сети bridge, когда для контейнера создается своя сеть (глубоко в тему сетей мы не полезем, упомяну только, что для разработки можно исользовать режим сети host, когда контейнер работает в сети хоста).

Мы можем посмотреть текущий режим сети в Docker Desktop

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

Для создания сети нужно выполнить команду

docker network create test-network
  • docker network create: консольная команда для создания сети
  • test-network: название создаваемой сети

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

Апи мы запустим с использованием созданной сети, а как быть с базой?

Можно перезапустить контейнер с указанием сети, а можно подключить уже запущенный контейнер к новой сети командой:

docker network connect test-network test_mysql

Теперь, когда все готово, запускаем контейнер с АПИ

docker run --name test_api --network=test-network -d -p 3000:3000 -e NODE_ENV=production -e DATABASE_URL="mysql://root:toor@test_mysql/mydb" test-api

Тут у нас появились новые опции:

  • --network=test-network: при запуске контейнера присоединиться к существующей сети
  • -e NODE_ENV=production: переменная среды окружения для Node.js, которая указывает приложению, что используется боевой режим (мы его используем для настройки доступа к базе данных)
  • -e DATABASE_URL="mysql://root:toor@test_mysql/mydb": задаём строку подключения к базе данных. Обратите внимание, в качестве хоста указывается имя контейнера, т.е. нам не надо знать адрес контейнера с базой, в докере имя хоста можно использовать вместо IP-адреса. Ну и смена порта не нужна, так как внутри контейнера используется стандартный порт MySQL (3306)

Если все сделали правильно, то контейнер с АПИ запустится, подключится к базе данных по внутренней сети и будет доступен по адресу localhost:3000

Можно посмотреть логи работы в Docker Desktop


Задание на дом

  • Создать свой образ АПИ (если ваше АПИ написано на express.js, то сразу свой вариант, если нет, то собрать пример из этой лекции)
  • Создать сеть и подключить к ней базу данных
  • запустить контейнер c АПИ

В репозитории опубликовать весь проект АПИ (не забываем про .gitignore), в readme.md написать команды для сборки образа и запуска контейнера и скриншот Docker Desktop с запущенным контейнером.