| May 9, 2022
В этой статье мы познакомимся с простейшим способом упаковки своeго собственного приложения в Docker контейнер.
Учится мы будем на примере крошечного Node.js приложения. Если Вы не знакомы с Node.js - ничего страшного. Ниже Вы найдёте инструкцию по созданию тестового приложения, с которым мы и будем работать.
Если Вы у Вас уже есть своё Node.js приложение, которые Вы хотите упаковать в Docker контейнер - следующий раздел Вы можете пропустить.
Создание тестового приложения Node.js
Перед тем как мы начнём, убедитесь, что у Вас установлена среда разработки Node.js. Скачать её можно на официальном сайте или установить можно напрямую с Homebrew. Делается это следующей командой:
brew install node
Теперь, Вы готовы к созданию тестового приложения. Следуйте данной инструкции:
- Откройте терминал и перейдите в папку, в которой Вы создадите свой проект
- Выполните следующую команду:
npm init
В процессе, Вам будет задан ряд вопросов о мета-информации о проекте. Для экономии Вашего времени, предлагаю на каждый вопрос отвечать нажатием клавиши Enter. В этом случае, будут использованы значения по умолчанию.
- Установите библиотеку Express.js командой
npm i express
Express.js нам понадобится только для того, чтобы научить наше тестовое приложение отвечать на http-запросы. Мы это используем для проверки работоспособностии нашего тестового приложения в контейнере.
- Создайте javascript файл с Вашим приложением. Сделать это можно, выполнив следующую команду в терминале:
touch server.js
- Скопируйте следующий код в Ваш файл приложения. В моём случае, код ниже, нужно скопировать в файл
server.js
:
const express = require('express')
const app = express()
const port = 9876
app.get('/', (req, res) => {
res.send('Hello fullstackguy.com!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
Вот и всё. Приложение готово. Чтобы проверить его работоспособность, можно выполнить следующие команды в терминале:
node server.js
curl http://localhost:9876
Первая - запустит Ваше приложение и оно начнёт слушать запросы на 9876 порту. Вторая команда - шлёт запрос на порт Вашего приложения и, в результате, оно должно ответить сообщением, которое мы в указали в коде приложения.
Теперь, когда у нас есть тестовое приложение, мы можем перейти к его упаковке.
Как упаковать приложение в Docker контейнер?
Первое, что необходимо сделать - это создать Dockerfile. Dockerfile - описывает образ Вашего приложения в контейнере; то, какими ресурсами оно будет обладать, будучи запущеным в контейнере, и как именно оно будет запущено в нём.
Создание Dockerfile’а
Для этого нужно создать файл под названием Dockerfile
и скопировать в него следующее содержимое:
# команда FROM позволяет указать базовый образ,
# который мы будем использовать для образа с нашим приложением
FROM node:18.0.0
# WORKDIR позволяет установить рабочую директорию, как следует из названия.
# Вы можете думать о WORKDIR, как о команде cd, для смены директории
WORKDIR /app
# COPY позволяет скопировать файлы и директории нашего приложения в Docker образ
# Копируются именно те файлы, которые нужны для работы нашего приложения.
# Как видно ниже, в первую очередь копируются файлы-манифесты.
COPY package.json package.json
COPY package-lock.json package-lock.json
# RUN команда позволяет выполнить произвольную команду. Обычно это команды запуска или команды установки зависимостей.
# В данном случае, выполняется команда npm install, которая установит зависимости Вашего приложения
RUN npm install
# Снова команда COPY, но теперь копируется контент текущей директории в рабочую директорию контейнера.
# То есть, копируются файлы самого приложения, включая наш server.js файл
COPY . .
# И наконец, команда CMD запускает приложение. Первым аргументом передаётся название команды,
# которую необходимо вызвать. Все остальные, это аргументы первой команды.
CMD ["node", "server.js"]
Директория приложения теперь должна выглядеть следующим образом:
Dockerfile
node_modules
package-lock.json
package.json
server.js
Создание Docker-образа
Теперь, когда у нас есть Dockerfile, мы можем создать новый Docker-образ нашего приложения. Делается это следующей командой:
docker build --tag node-docker:1.0.0 .
Разберём эту команду подробнее.
docker build
- отвечает за сборку новых Docker-образов.
--tag node-docker:1.0.0
- параметр говорит о том, что наш новый образ, будет иметь название node-docker
и будет отмечен тегом 1.0.0
. Тег не обязан включать в себя номер версии. Вместо него можно использовать и словестное описание, например, есть тег по умолчанию latest
.
.
- точка в конце означает текущую директорию, а точнее - директорию с Dockerfile’ом
После выполнения команды docker build
, новый Docker-образ с именем node-docker
будет создан с нашим приложением внутри. Самое время попытаться его запустить.
Запуск приложения в Docker-контейнере
Запуск контейнера с нашим приложеним осуществляется с помощью следующей команды:
docker run -p 8000:9876 --name node-docker-try node-docker:1.0.0
Разберём её подробнее:
docker run
- отвечает за запуск контейнеров с приложениями из имеющихся Docker-образов.
-p 8000:9876
- параметр, означает проброс портов. Если Вы помните, в нашем файле server.js
описан запуск приложения на 9876
порту. Так вот, параметр -p
показывает с какого порта хоста на какой порт контейнера будут переадресованы запросы. Если совсем просто - когда вы шлёте запрос на localhost:8000 он автоматически пробрасывается в контейнер на порт 9876, где уже входящий трафик прослушивается нашим приложением.
--name node-docker-try
- параметр, который позволяет задать имя контейнера, с нашим приложением. Если этот параметр явно не указать, то Docker сгенерирует название контейнера за нас.
node-docker:1.0.0
- в качестве обязательного параметра команды docker run
идёт указание названия Docker-образа и тега (версии), из которого и будет запущен контейнер.
После выполнения этих действий и запуска контейнера с нашим приложением, можно проверить его работоспособность, выполнив тот же запрос:
curl http://localhost:8000
Обратите внимание, что номер порта в этот раз, выставлен на 8000
. Это говорит о том, что наш запрос пойдёт в наш контейнер через этот порт, а внутри, приложение получит его на 9876
.
Заключение
В этой статье мы рассмотрели простейший способ вручную упаковать Node.js приложение в Docker контейнер. Этот способ уместно использовать в скриптах в своём CI/CD pipeline’е.
Помимо этого способа, есть и другие. Например, у Java приложений, есть вариант использовать специальные плагины (Jib-plugin для Maven), который под капотом, делает примерно то же самое.
В любом случае, знать этот процесс полезно и имея уже эти знания в своём арсенале, Вы без проблем сможете упаковать любое приложение, написанное на любом языке программирования, в Docker.
Список материалов
Полный плейлист
Плейлист “Docker: Tips & Tricks”