Что такое докер?

Докер – это открытая платформа для разработки, запуска и управления контейнерами на сервере и в облаке. Думайте о докер как о CLI, но для облака.

Для примера приложения в этом руководстве мы будем использовать Next.js, и потом создадим Dockerfile чтобы “докерезировать” приложение.

Требования

Для использования докера в вашем Next.js проекте вам понадобится:

  • Установленный Docker на вашем компьютере

  • Установленные Node.js и npm/yarn в вашей системе для создания приложения на Next

Создание приложения на Next.js

Если у вас уже есть приложение, которое мы будем “докереизровать”, тогда переходить к следующему шагу, в ином случае давайте создадим его.

Выполните данную команду в терминале:

yarn create next-app

Данная команда подготовит файлы и конфигурацию, которые необходимы для запуска вашего next.js приложения

Создание Dockerfile

Для начала, давайте откроем наше приложение в VS Code или в любом другом редакторе на ваш выбор.

И запустим данные команды:

cd <имя проекта>
code . 

(Надеюсь, что у вас настроен vscode)

Здесь вы увидите структуру вашего приложения. Должно выглядеть примерно так.

Примечание: я использую typescript, вот почему вы видите tsconfig.json и файлы, которые заканчиваются на .ts.

Продолжим, и создадим новый файл с названием Dockerfile. По умолчанию данный файл будет распознан докером, и он выполнит команды и инструкции, которые мы пропишем в файле.

Запомните: команды будут запущены в том порядке, в котором они записаны.

Пропишите данный код внутри Dockerfile. Я пробегусь по командам и объясню, как они работают в конце гайда.

Примечание: я использую yarn для руководства, вы можете использовать npm, для этого вам всего лишь нужно заменить yarn на npm в файле.

FROM node:lts as dependencies
WORKDIR /<имя проекта>
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

FROM node:lts as builder
WORKDIR /<имя проекта>
COPY . .
COPY --from=dependencies /<имя проекта>/node_modules ./node_modules
RUN yarn build

FROM node:lts as runner
WORKDIR /<имя проекта>
ENV NODE_ENV production

COPY --from=builder /<имя проекта>/public ./public
COPY --from=builder /<имя проекта>/package.json ./package.json
COPY --from=builder /<имя проекта>/.next ./.next
COPY --from=builder /<имя проекта>/node_modules ./node_modules

EXPOSE 3000
CMD ["yarn", "start"]

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

Выполните данную команду для создания образа докера.

docker build . -t <имя проекта>

Данная команда создаст образ докера с названием <имя проекта>.

Запустить образ докера после завершения сборки можно прописав команду:

docker run -p 3000:3000 <имя проекта>

Теперь откройте ваш бразуер, и перейдите по http://localhost:3000, чтобы увидеть ваш проект.

Поздравляю! Вы успешно “докерезировали” своё приложение!

Поговорим о содержимом Dockerfile

Пройдемся по коду, который содержится в Dockerfile.

Напомним, код выполняется на основание того, как он написан, сверху-вниз.

Разобьём весь код на 3 логические части:

  1. Установка зависимостей

  2. Сборка нашего Next.js приложения

  3. Настройка среды выполнения для приложения

1. Установка зависимостей

FROM node:lts as dependencies
WORKDIR /<имя проекта>
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

Что же происходит в данном коде?

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

Вы можете использовать необходимую версию node. Для примера: FROM node:16 будет создавать ваш образ с версией Node 16. Мы также используем as dependencies для того, чтобы экспортировать данный код, и использовать его в дальнейшем при сборке нашего приложения в докер.

Во-вторых, мы хотим создать место, в котором будет храниться код нашего приложения, для используется WORKDIR.

В-третьих, нам нужно скопировать наши package.json и yarn.lock файлы, что даст нам примущество в кэшировании слоев докера. Хорошее объяснение кэширования в докере вы можете найти тут.

И наконец, чтобы установить все зависимости для проекта нужно выполнить команду yarn install. Мы используем --frozen-lockfile потому, что наш yarn.lock или package-lock.json может получить обновления при запуске yarn install (или npm install). А мы не хотим проверять эти изменения.

Если вы используете npm вам нужно использовать npm ci (ci означает чистую установку / используйте это для продакшена или просто используйте RUN npm install)

Для yarn это --frozen-lockfile.

2. Сборка нашего Next.js приложения

FROM node:lts as builder
WORKDIR /<имя проекта>
COPY --from=dependencies /<имя проекта>/node_modules ./node_modules
RUN yarn build

Взглянем на процесс сборки.

Мы создаем наше приложение с помощью копирования зависимостей из node_modules.
И затем собираем его. Если вы используете npm, тогда используйте RUN npm build.

FROM node:lts as runner
WORKDIR /<имя проекта>
ENV NODE_ENV production

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

3. Настройка среды выполнения для приложения

COPY --from=builder /<имя проекта>/public ./public
COPY --from=builder /<имя проекта>/package.json ./package.json
COPY --from=builder /<имя проекта>/.next ./.next
COPY --from=builder /<имя проекта>/node_modules ./node_modules

EXPOSE 3000
CMD ["yarn", "start"]

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

Финальным пунктом нам нужно запустить приложение, для этого используется CMD, в которой мы определяем среду выполнения.

Для нашей среды выполнения мы используем yarn команды.

Если у вас установлено докер приложение, то вы можете видеть там все ваши контейнеры, и запускать их оттуда. Выглядит это примерно так.

На этом руководство заканчивается, спасибо за прочтение!

Комментарии (9)


  1. kricha
    15.04.2022 22:04

    Я бы сразу заменил lts на конкретную версию.


  1. build_your_web
    15.04.2022 22:05
    +1

    Как роуты будут работать после статической сборки?


    1. Doberman2029 Автор
      15.04.2022 22:55
      +1

      Не совсем понял вашего вопроса. В контейнере будет запускаться точная копия вашего проекта, на навигацию это никак не повлияет


  1. uyrij
    16.04.2022 01:47
    +1

    Почему нельзя один раз COPY . . ?

    Можно ещё забиндить фолдер, чтобы .env с секретами не класть в докер. И это можно в той же командной строке, как у вас или в докер-компоузе


    1. OnYourLips
      16.04.2022 04:11
      +2

      Почему нельзя один раз COPY . . ?

      Чтобы ускорить сборку за счёт кэша. Сначала собираем зависимости и они сохраняются в виде слоя. И при изменении файлов проекта их не надо пересобирать.


  1. Exclipt
    16.04.2022 09:37
    +2

    node_modules точно нужны для сбилженного проекта?


    1. Doberman2029 Автор
      16.04.2022 16:31

      Простой ответ, для сбилженного проекта node_modules не нужен.

      Более сложный ответ. Мы копируем node_modules перед стадией билда. Часть кода, который мы импортируем из библиотек, находится в node_modules, и без присутствия данной папки в корне, перед билдом, мы не сможем собрать рабочее приложение.
      Но, если у нас простой проект, у которого нет сторонних зависимостей, т.е. прям чистый js вообще без всего, то, конечно, и отпадает необходимость в node_modules, там ведь ничего нет :). Да и в докере необходимости тогда также нет, легче просто передать минифицированный код


  1. deepform
    16.04.2022 13:29

    Да и картинку сменить неплохо бы


    1. Doberman2029 Автор
      16.04.2022 16:19

      Контейнеры ведь ????