Введение
Node.js — это среда выполнения JavaScript, которая в последние годы стала популярной для создания серверных приложений.
В этом руководстве показано, как развернуть приложение Node.js на облачном сервере с помощью Docker, Docker Hub и Docker Compose.
Предпосылки
- В этом руководстве предполагается, что Docker установлен на вашей локальной системе. Если у вас его нет, инструкции по установке можно найти в официальной документации.
- Вам также понадобится облачный сервер под управлением дистрибутива Linux, предпочтительно Ubuntu 24.04. Если вы используете другой дистрибутив, вам может потребоваться следовать специальным инструкциям по установке Docker на сервер.
- Для некоторых шагов также потребуется учетная запись Docker Hub (бесплатно) для загрузки образа Docker для приложения.
- Если у вас нет опыта работы с Docker, ничего страшного, это руководство очень простое и объясняет основные концепции того, что мы делаем.
- Вам необходимо приложение Node.js, которое вы можете развернуть.
О Докере
Если вы только начинаете работать с Docker, вот несколько терминов, с которыми стоит ознакомиться, чтобы убедиться, что мы понимаем друг друга.
- Образы: в Docker образы представляют собой «снимки» или шаблоны файловой системы и содержат все необходимое для запуска приложения.
- Контейнеры: это фактически работающие экземпляры приложения. Они создаются путём преобразования шаблона (образа) в нечто, что можно запустить и которое имеет состояние.
- Слои — это элементы, из которых состоит образ Docker. Каждый слой строится поверх другого, что позволяет реализовать функцию кэширования слоёв. Это означает, что при изменении хотя бы одного слоя в образе вам не нужно перестраивать или перезагружать все слои образа.
- Реестры — это место, куда вы загружаете (push) образы, чтобы сделать их доступными для всего мира или для тех, у кого есть учётные данные. В этом руководстве мы будем использовать Docker Hub, но существуют и альтернативы, предоставляемые GCP, AWS, Azure, GitHub и другими.
Шаг 1 — Создание Dockerfile
Создайте файл Dockerfile со следующим содержимым в корневом каталоге вашего проекта Node.js:
FROM node:20.17
ENV NODE_ENV=production
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
EXPOSE 8080
CMD [ "node", "src/index.js" ]Dockerfile — это место, где вы размещаете инструкции, позволяющие Docker собрать образ. Каждая инструкция представляет собой создание слоя, представляющего собой модификацию файловой системы образа.
В данном случае мы создаём образ на основе шаблона, иногда называемого базовым образом, в данном случае это node:20.17. Это официальный образ, предоставленный компанией Docker, и вы можете найти о нём больше информации здесь.
Следующий шаг устанавливает переменную окружения NODE_ENV в режим production. Основной эффект заключается в том, чтобы избежать установки пакетов разработки при запуске следующей установки npm, но часто это может привести к лучшей оптимизации модулей, которые могут вам понадобиться.
С помощью команды WORKDIR мы перемещаем текущий каталог в /app, который, в свою очередь, становится каталогом, в котором выполняются следующие инструкции.
Строка пакета COPY*.json . Копирует файлы package.json и package-lock.json в папку /app файловой системы образа Docker. Обратите внимание, что точка в конце указывает на текущий каталог.
Теперь мы используем директиву RUN для установки производственных зависимостей с помощью команды npm ci (ci означает чистую установку и предназначено для использования в автоматизированных средах).
На этом этапе стоит отметить, что до сих пор мы копировали в сборку только файлы package*.json, а не весь каталог проекта. Это позволяет нам воспользоваться кэшированием слоёв Docker, так что если зависимые пакеты не изменились, слои можно использовать без пересборки.
Следующая строка (COPY . .) копирует оставшиеся файлы в образе.
При желании мы можем указать, что хотим открыть доступ к определённому сетевому порту из контейнера для веб-приложения. Обратите внимание, что директива EXPOSE фактически не открывает порт: как говорится в документации, она «действует как своего рода документ между создателем образа и пользователем контейнера о портах, которые должны быть опубликованы». .
Наконец, последняя директива определяет команду, которую Docker должен использовать для запуска приложения при запуске контейнера. В данном случае мы предполагаем, что точкой входа приложения является файл index.js.
Обычно рекомендуется создать файл .dockerignore вместе с Dockerfile. Это гарантирует, что при запуске COPY.. ненужные файлы с вашего компьютера не будут скопированы в образ:
.git
Dockerfile
node_modulesВ этом случае мы не хотим, чтобы версии каталогов, такие как git или node_modules, находящиеся на стадии разработки, были доступны в создаваемом нами шаблоне.
Шаг 2 — Создание изображения
Теперь, когда у нас есть Dockerfile, мы можем указать Docker использовать его для создания образа.
Базовая команда для этого выглядит следующим образом и должна быть запущена в основной папке проекта:
docker build -t myproject .
Если установка не завершится успешно и возникнет ошибка “/bin/sh -c npm ci”, замените npm ci в Dockerfile на npm install и повторите попытку.
Опция -t задаёт имя образа, в данном случае myproject. В конце строки нужно указать Docker, что нужно искать Dockerfile в текущем каталоге.
Примечание: Первый запуск сборки займет некоторое время, поскольку Docker необходимо загрузить все слои базового образа (в данном случае Node.js 20.17).
Поскольку мы планируем загрузить этот образ в онлайн-реестр Docker Hub (чтобы получить к нему доступ с нашего сервера), нам необходимо назвать образ, используя определенное соглашение об именовании.
Таким образом, приведенная выше команда будет выглядеть так:
docker build -t username/myproject:latest .
Где username — ваше имя пользователя Docker Hub, а last — тег образа. У образа может быть несколько тегов, поэтому иногда можно увидеть рабочий процесс, похожий на этот:
docker build -t myproject .
docker tag myproject username/myproject:latest
docker tag myproject username/myproject:20240905Эти команды создают изображение, а затем присваивают ему теги latest и 20240904 (дата последнего обновления этого руководства).
Docker Hub по умолчанию не удаляет старые образы, поэтому позволяет вести историю всех образов, отправленных в реестр. Образ с последним тегом всегда соответствует образу, собранному последней версией, а более старые образы помечаются датой.
Шаг 3 — Нажмите на изображение
Теперь, когда у нас есть образ, нам нужно отправить его в реестр. Для начала выполните следующую команду, чтобы убедиться, что ваш экземпляр Docker аутентифицирован в Docker Hub:
docker login
Затем запустите docker push, чтобы загрузить образ вместе со всеми тегами.
docker push username/myproject
Если ваше приложение небольшое, эта команда должна выполниться быстро, поскольку необходимо только загрузить слои, связанные с приложением Node.js и его зависимостями JavaScript.
После получения новой версии образа необходимо еще раз выполнить команду push, чтобы убедиться, что она загружена в Docker Hub.
Шаг 4 — Установка Docker в Ubuntu 24.04
Теперь мы можем перейти к установке Docker и Docker Compose на сервер. Как уже упоминалось в предварительных требованиях, предполагается, что у вас уже настроен сервер Ubuntu 24.04.
Прежде всего, для установки Docker требуются некоторые системные зависимости, которые можно установить с помощью следующих команд:
sudo apt-get update
sudo apt-get install ca-certificates curlТеперь добавьте официальный ключ Docker GPG и настройте пользовательский репозиторий apt:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullНаконец, обновите каталог apt еще раз и установите Docker Community Edition:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginПриведенная выше команда также устанавливает Docker Compose — инструмент, который значительно упрощает управление контейнерами и их жизненным циклом.
Последний полезный шаг включает добавление текущего пользователя Ubuntu в группу Docker, чтобы мы могли запускать команды Docker непосредственно из него.
Это можно легко сделать с помощью следующей команды:
sudo gpasswd -a myuser docker
Убедитесь, что все прошло успешно, выполнив следующие команды:
docker --version
docker ps
docker compose versionЕсли вы не видите никаких ошибок или предупреждений, все готово.
Шаг 5 — Запуск контейнера с помощью Docker Compose
Создайте на сервере файл docker-compose.yml со следующим содержимым:
services:
myproject:
container_name: 'myproject'
image: 'username/myproject'
restart: unless-stoppedЭто очень простой файл Docker Compose, который настраивает один контейнер с именем myproject на основе имени пользователя/образа myproject из Docker Hub. Если метка не указана, по умолчанию будет использоваться последняя, но вы также можете указать конкретную метку:
services:
myproject:
container_name: 'myproject'
image: 'username/myproject:20240904'
restart: unless-stoppedНаконец, атрибут перезапуска указывает, что контейнер должен автоматически перезапускаться в случае сбоя, если только он не будет остановлен вручную.
Если вы выполните эту команду Compose сейчас, образ Docker будет отменен, и ваше приложение, как мы надеемся, запустится:
docker compose -f docker-compose.yml up
Эта команда создаёт контейнер и запускает его. Вывод контейнера перехватывается Docker и отображается в консоли. Нажмите CTRL + C (или CMD + C) и подождите несколько секунд, пока контейнер не остановится.
Если всё прошло успешно, теперь вы готовы запустить контейнер как призрак, чтобы он продолжал работать в фоновом режиме до остановки. Это можно сделать, добавив опцию -d к команде:
docker compose -f docker-compose.yml up -dБум, узел! (О, я серьёзно)
Обязательно ознакомьтесь со справочной документацией по Compose-файлу, где вы найдете полезные функции, такие как сопоставление сетевых портов между сервером и контейнером. Вот небольшой пример сопоставления внешнего порта 80 с внутренним портом 8080:
services:
myproject:
container_name: 'myproject'
image: 'username/myproject'
restart: unless-stopped
ports:
- '80:8080'Шаг 6 — Установка новой версии
Предположим, вам нужно выпустить изменение в приложении. Если у вас не включены автоматические сборки, вам придётся повторять шаги 2 и 3, пока в Docker Hub не появится новый образ.
Затем вам необходимо вручную загрузить новое изображение на свой сервер, вот так:
docker compose -f docker-compose.yml pull
И перезапустите контейнер с новым образом:
docker compose -f docker-compose.yml up -d --force-recreate
Результат
Отлично, вы справились! Это было базовое введение в развёртывание приложения Node.js в Ubuntu 24.04 с использованием Docker, Docker Hub и Docker Compose.
Мы увидели, как написать простой Dockerfile, как создать образ, отправить его и развернуть на сервере.
Docker — это больше, чем описано в этом руководстве, поэтому обязательно ознакомьтесь с документацией по Docker и Docker Compose, чтобы узнать больше о концепциях и функциях.









