Введение
Docker — это контейнерная платформа, представляющая собой легкую, виртуализированную, портативную, программно-определяемую стандартизированную среду. Она позволяет программному обеспечению работать изолированно от другого ПО, запущенного на физическом хосте. Docker является определяющим компонентом непрерывной разработки и интеграции (CI/CD) в разработке программного обеспечения. Он предлагает легковесную альтернативу виртуальным машинам и позволяет разработчикам использовать преимущества распределенных архитектур приложений. Для подробного обзора экосистемы Docker ознакомьтесь с этой статьей.
Процесс создания приложения с помощью Docker начинается с того, что разработчик создает образ для своего приложения. Затем этот образ развертывается внутри контейнера. Образ содержит определяющие компоненты приложения, такие как код приложения, библиотеки, файлы конфигурации, переменные окружения и среду выполнения. Образ стандартизирует среду внутри контейнера, обеспечивая контейнеризации свойство портативности. Node.js — это кроссплатформенная среда выполнения JavaScript с открытым исходным кодом для бэкенда, которая может выполнять код JavaScript вне веб-браузера. Она построена на базе Chrome V8 JavaScript Engine. Express.js — это минималистичный бэкенд-фреймворк JavaScript, который работает поверх Node.js.
В этом руководстве мы создадим образ для веб-сайта, работающего на фреймворке Express. Мы будем использовать Bootstrap, библиотеку для фронтенда, чтобы улучшить внешний вид интерфейса. После создания образа мы соберем контейнер и отправим его в Docker Hub. Docker Hub позволяет разработчикам размещать контейнеризированные приложения для простого развертывания в любой среде Docker. Как только ваш контейнер будет размещен на Docker Hub, мы скачаем его и создадим еще один образ, который непосредственно будет обслуживать наш веб-сайт.
Предварительные требования
Это практическое руководство. Вам необходимо подготовить окружение, которое позволит вам выполнять описанные шаги.
- У вас должна быть установленная версия Ubuntu 20.04 в качестве исходной операционной среды, а также создан пользователь без прав root с привилегиями sudo. Войдите в систему под этим пользователем и перейдите к следующим шагам.
- Вам необходимо установить Docker. Выполните шаги 1, 2, 3 и 4 из нашего руководства по установке и использованию Docker в Ubuntu. Это должно работать для любого дистрибутива Ubuntu.
- Создайте учетную запись Docker Hub, если у вас ее еще нет. Вы можете перейти по этой ссылке, чтобы открыть краткое руководство по началу работы с Docker Hub.
- Установите Node.js и NPM. NPM — это пакетный менеджер JavaScript. Вы можете следовать этим инструкциям по установке Node и npm.
Шаг 1. Настройка зависимостей приложения
Перед созданием образа вам необходимо подготовить исходный код приложения. Исходный код включает в себя сам код, статический контент и зависимости, которые будут скопированы в контейнер. Начните с создания каталога для вашего проекта в домашней директории пользователя без прав root. Мы назовем его node_express, но вы можете использовать любое другое имя каталога по вашему выбору:
|
1 |
mkdir node_express |
Затем перейдите в этот каталог:
|
1 |
cd node_express |
Это будет корневой каталог вашего приложения. Приложение node.js ожидает наличия файла package.json в корневой папке. Npm использует этот файл для определения зависимостей, необходимых вашему приложению. Введите следующую команду, чтобы создать этот файл:
|
1 |
nano package.json |
После этого добавьте в файл следующий фрагмент кода. Вы можете изменить имя, автора, описание и файл точки входа по своему усмотрению:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{ "name": "node-express-docker-image", "version": "1.0.0", "description": "Nodejs Express Docker Image Example", "author": "hackins", "main": "index.js", "license": "ISC", "keywords": [ "nodejs", "express", "bootstrap" ], "dependencies": { "express": "^4.17.1" } } |
Как видите, этот файл определяет имя проекта, версию, автора и лицензию, под которой будет распространяться код приложения. Рекомендуется использовать короткое и описательное имя для вашего проекта, чтобы избежать дубликатов в npm registry. Мы указали лицензию ISC для проекта, которая разрешает свободное копирование, изменение или распространение кода приложения.
Самое главное, вам следует обратить внимание на следующие директивы в файле:
- “
main»: эта директива указывает точку входа приложения, которую мы установили как index.js. Мы создадим этот файл в ближайшее время. - “
dependencies»: эта директива указывает зависимости приложения, которые будут загружены из реестра npm при запуске командыnpm, в нашем случае нам нужна Express версии 4.17.1 и выше.
Теперь вы можете сохранить файл, нажав Ctrl + O. Затем закройте файл, нажав Ctrl + X. Далее мы установим зависимости, выполнив следующую команду:
|
1 |
npm install |
Эта команда устанавливает зависимости приложения, указанные в файле package.json, в директории node_modules. Они были автоматически созданы при первом запуске команды. После установки зависимостей нашего приложения вы можете начать добавлять код приложения.
Шаг 2. Добавление файлов кода приложения
Мы создадим простой сайт с рецептами, предоставленными allrecipes. Основной точкой входа для приложения является файл index.js. Мы добавим директорию views, в которой будут храниться различные страницы и статические ресурсы проекта. У сайта будет целевая страница, содержащая вводную информацию и ссылки на некоторые рецепты.
Код нашей целевой страницы будет помещен в файл home.html. Сначала создайте файл index.js, введя следующую команду:
|
1 |
nano index.js |
Добавьте следующий код, который импортирует и создает приложение Express. Он также указывает объект Router, базовую директорию и порт, на котором будет работать это приложение:
|
1 2 3 4 5 6 |
const express = require('express'); const app = express(); const router = express.Router(); const path = __dirname + '/views/'; const port = 8090; |
require — это функция JavaScript, которая загружает модуль. В данном случае мы загружаем модуль express. Затем мы будем использовать импортированный модуль для создания объектов express и router. Объект router выполняет функции маршрутизации приложения, отвечая на вызовы методов HTTP, которые мы будем добавлять к этому объекту по ходу руководства.
Мы также установили path и port. Константа path определяет базовую директорию для кода. В нашем случае это поддиректория views внутри корневой директории проекта. port указывает порт, который должно прослушивать приложение express, в нашем примере мы установили его в значение 8090.
После определения констант мы можем указать некоторые маршруты для приложения с помощью объекта router. Добавьте следующий код в файл index.js, чтобы указать маршруты:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
router.use(function (req,res,next) { console.log('/' + req.method); next(); }); router.get('/', function(req,res){ res.sendFile(path + 'home.html'); }); router.get('/lasagna', function(req,res){ res.sendFile(path + 'lasagna.html'); }); router.get('/guacamole', function(req,res){ res.sendFile(path + 'guacamole.html'); }); router.get('/banana-bread', function(req,res){ res.sendFile(path + 'banana_bread.html'); }); |
Вы можете добавить промежуточное ПО к маршрутам с помощью функции router.use. В этом случае мы добавляем функцию, которая логирует запросы маршрутизатора перед их передачей маршрутам приложения. Запрос GET к корню приложения вернет файл home.html страницу. Затем мы добавили страницы для трех рецептов, которые также будут запрашиваться с помощью GET-запроса к конкретной странице рецепта.
Наконец, добавьте следующий код для подключения router промежуточного ПО и статических ресурсов приложения. Кроме того, укажите приложению express прослушивать порт 8090:
|
1 2 3 4 5 6 |
app.use(express.static(path)); app.use('/', router); app.listen(port, function () { console.log('Пример приложения Nodejs Express запущен на порту ' + port) }) |
Ваш готовый файл index.js должен выглядеть следующим образом:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
const express = require('express'); const app = express(); const router = express.Router(); const path = __dirname + '/views/'; const port = 8090; router.use(function (req,res,next) { console.log('/' + req.method); next(); }); router.get('/', function(req,res){ res.sendFile(path + 'home.html'); }); router.get('/lasagna', function(req,res){ res.sendFile(path + 'lasagna.html'); }); router.get('/guacamole', function(req,res){ res.sendFile(path + 'guacamole.html'); }); router.get('/banana-bread', function(req,res){ res.sendFile(path + 'banana_bread.html'); }); app.use(express.static(path)); app.use('/', router); app.listen(port, function () { console.log('Пример приложения Nodejs Express запущен на порту ' + port) }) |
Теперь вы можете сохранить и закрыть файл. Следующий шаг — добавление статических веб-страниц в каталог views. Для начала введите следующую команду, чтобы создать этот каталог:
|
1 |
mkdir views |
Введите следующую команду, чтобы открыть файл home.html целевой страницы:
|
1 |
nano views/home.html |
Добавьте следующий код в файл. Этот код импортирует Bootstrap и предоставляет посетителям сайта информацию о том, чему посвящен сайт:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.80.0"> <title>Потрясающие рецепты</title> <!-- Базовый CSS Bootstrap --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Переключить навигацию</span> </button> <a class="navbar-brand" href="#">Потрясающие рецепты</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Главная</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Лазанья</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Гуакамоле</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Банановый хлеб</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Потрясающий рецепт</h1> <p class="lead text-muted"> Находите повседневное кулинарное вдохновение и делитесь им с помощью этих потрясающих рецептов. Открывайте для себя рецепты, поваров, видеоролики и практические руководства, основанные на любимой вами еде и друзьях, на которых вы подписаны. <br /> <em>(Ничего серьезного, это просто для нашего демонстрационного приложения на базе образа node-express-docker)</em> </p> </div> </div> </section> </main> </body> </html> |
Помимо импорта Bootstrap, страница также добавляет базовое навигационное меню, которое поможет нам перемещаться по страницам и возвращаться на целевую страницу. Мы также добавили строку для импорта нашего собственного CSS-файла:
|
1 |
<link href="css/custom.css" rel="stylesheet"> |
Позже мы будем использовать этот файл для добавления пользовательских стилей в приложение. Теперь давайте создадим три страницы для рецептов. Сначала мы начнем с создания страницы лазаньи. Откройте файл в редакторе nano с помощью следующей команды:
|
1 |
nano views/lasagna.html |
В открытом файле добавьте следующий код. Этот файл импортирует Bootstrap, файл custom.css, определит навигационное меню и предоставит некоторую информацию о рецепте лазаньи:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Марк Отто, Джейкоб Торнтон и соавторы Bootstrap"> <meta name="generator" content="Hugo 0.80.0"> <title>Рецепт лазаньи</title> <!-- Базовый CSS Bootstrap --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Переключить навигацию</span> </button> <a class="navbar-brand" href="#">Потрясающие рецепты</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Главная</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Лазанья</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Гуакамоле</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Банановый хлеб</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Лучший рецепт лазаньи</h1> <p class="lead text-muted"> Это лучшая лазанья, которую вы когда-либо готовили. <br /> <em>(Ничего серьезного, это просто демо-приложение для нашего образа node-express-docker)</em> </p> <h3>Ингредиенты</h3> <ul class="list-group"> <li class="list-group-item">1 фунт сладкой итальянской колбасы</li> <li class="list-group-item">¾ фунта нежирного говяжьего фарша</li> <li class="list-group-item">½ стакана измельченного лука</li> <li class="list-group-item">2 зубчика чеснока, измельченных</li> <li class="list-group-item">1 банка (28 унций) измельченных томатов</li> <li class="list-group-item">2 банки (по 6 унций) томатной пасты</li> <li class="list-group-item">2 банки (по 6,5 унций) консервированного томатного соуса</li> <li class="list-group-item">½ стакана воды</li> <li class="list-group-item">2 столовые ложки белого сахара</li> <li class="list-group-item">1 ½ чайные ложки сушеных листьев базилика</li> <li class="list-group-item">½ чайной ложки семян фенхеля</li> <li class="list-group-item">1 чайная ложка итальянской приправы</li> <li class="list-group-item">1 ½ teaspoons salt, divided, or to taste</li> <li class="list-group-item">¼ teaspoon ground black pepper</li> <li class="list-group-item">4 столовые ложки нарезанной свежей петрушки</li> <li class="list-group-item">12 листов для лазаньи</li> <li class="list-group-item">16 унций сыра рикотта</li> <li class="list-group-item">1 яйцо</li> <li class="list-group-item">¾ фунта сыра моцарелла, нарезанного ломтиками</li> <li class="list-group-item">¾ стакана тертого сыра пармезан</li> </ul> </div> </div> </section> </main> </body> </html> |
Давайте выполним те же действия, чтобы создать файл для страницы рецепта гуакамоле. Откройте файл в nano, выполнив следующую команду:
|
1 |
nano views/guacamole.html |
Затем добавьте этот код в файл:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors"> <meta name="generator" content="Hugo 0.80.0"> <title>Рецепт гуакамоле</title> <!-- Основной CSS Bootstrap --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Переключить навигацию</span> </button> <a class="navbar-brand" href="#">Потрясающие рецепты</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Главная</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Лазанья</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Гуакамоле</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Банановый хлеб</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Лучший рецепт гуакамоле</h1> <p class="lead text-muted"> Вы можете сделать этот салат из авокадо однородным или с кусочками, в зависимости от ваших предпочтений. <br /> <em>(Ничего серьезного, это просто для нашего демонстрационного приложения на базе образа node-express-docker)</em> </p> <h3>Ингредиенты</h3> <ul class="list-group"> <li class="list-group-item">3 авокадо — очищенных, без косточек и размятых</li> <li class="list-group-item">сок 1 лайма</li> <li class="list-group-item">1 чайная ложка соли</li> <li class="list-group-item">½ стакана нарезанного кубиками лука</li> <li class="list-group-item">3 столовые ложки нарезанной свежей кинзы</li> <li class="list-group-item">2 помидора сорта рома (сливовидных), нарезанных кубиками</li> <li class="list-group-item">1 чайная ложка измельченного чеснока</li> <li class="list-group-item">1 щепотка молотого кайенского перца (по желанию)</li> </ul> </div> </div> </section> </main> </body> </html> |
Наконец, давайте создадим файл banana_bread.html, введя команду:
|
1 |
nano views/banana_bread.html |
Затем добавьте в файл следующий HTML-код:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content="Марк Отто, Джейкоб Торнтон и авторы Bootstrap"> <meta name="generator" content="Hugo 0.80.0"> <title>Рецепт бананового хлеба</title> <!-- Основной CSS Bootstrap --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="css/custom.css" rel="stylesheet"> </head> <body> <nav class="navbar navbar-dark bg-dark navbar-static-top navbar-expand-md"> <div class="container"> <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Переключить навигацию</span> </button> <a class="navbar-brand" href="#">Потрясающие рецепты</a> <div class="collapse navbar-collapse justify-content-center" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav justify-content-center"> <li class="active nav-item"> <a href="/" class="nav-link">Главная</a> </li> <li class="nav-item"> <a href="/lasagna" class="nav-link">Лазанья</a> </li> <li class="nav-item"> <a href="/guacamole" class="nav-link">Гуакамоле</a> </li> <li class="nav-item"> <a href="/banana-bread" class="nav-link">Банановый хлеб</a> </li> </ul> </div> </div> </nav> <main> <section class="py-5 text-center container bg-light"> <div class="row py-lg-5"> <div class="col-lg-6 col-md-8 mx-auto"> <h1 class="fw-light">Лучший рецепт бананового хлеба</h1> <p class="lead text-muted"> Зачем идти на компромисс с банановым вкусом? Этот банановый хлеб получается влажным и вкусным, с насыщенным банановым ароматом! Друзьям и семье очень нравится мой рецепт, и они говорят, что он лучший! Он прекрасен в поджаренном виде! Наслаждайтесь! <br /> <em>(Ничего серьезного, это просто для нашего демонстрационного приложения node-express-docker)</em> </p> <h3>Ингредиенты</h3> <ul class="list-group"> <li class="list-group-item">2 стакана пшеничной муки</li> <li class="list-group-item">1 чайная ложка пищевой соды</li> <li class="list-group-item">¼ чайной ложки соли</li> <li class="list-group-item">½ стакана сливочного масла</li> <li class="list-group-item">¾ стакана коричневого сахара</li> <li class="list-group-item">2 яйца, взбитых</li> <li class="list-group-item">2⅓ стакана размятых перезрелых бананов</li> </ul> </div> </div> </section> </main> </body> </html> |
Итак, мы создали все страницы. Если вы помните, нам нужно добавить css/custom.css файл. Введите следующую команду, чтобы создать директорию:
|
1 |
mkdir views/css |
Затем создайте и откройте файл в редакторе nano с помощью команды:
|
1 |
nano views/css/custom.css |
Вы можете добавить больше CSS-кода для стилизации вашего сайта по своему усмотрению. Для краткости давайте добавим в файл следующий фрагмент кода:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.bd-placeholder-img { font-size: 1.125rem; text-anchor: middle; -webkit-user-select: none; -moz-user-select: none; user-select: none; } @media (min-width: 768px) { .bd-placeholder-img-lg { font-size: 3.5rem; } } |
После завершения сохраните и закройте файл.
Вы можете запустить приложение, так как исходный код приложения и зависимости проекта уже установлены.
Мы настроили приложение на прослушивание порта 8090, выполните следующую команду, чтобы указать брандмауэру разрешить трафик через этот порт. Если вы указали другой порт, замените номер порта в команде:
|
1 |
sudo ufw allow 8090 |
Теперь вы можете запустить приложение. Но сначала убедитесь, что вы находитесь в корневой директории проекта, выполнив следующую команду:
|
1 |
cd ~/node_express |
Запустите приложение с помощью команды node index.js. Если вы указали другую точку входа, замените ее на свою:
|
1 |
node index.js |
Если вы перейдете в браузере по адресу http://your_public_server_ip:8090, вы увидите целевую страницу рецептов, как и было настроено:
В меню навигации вы можете увидеть ссылки на различные рецепты. Давайте перейдем по некоторым из них. Ниже представлена страница рецепта Лазанья:
А здесь у нас страница рецепта Гуакамоле:
К этому моменту вы создали свое приложение и проверили, что оно работает должным образом. Вы можете остановить сервер, нажав Ctrl + C, и перейти к созданию Dockerfile. Файлы Dockerfile помогают в масштабировании, позволяя воссоздать экземпляр приложения при необходимости.
Шаг 3. Создание Dockerfile
Docker считывает инструкции, указанные в Dockerfile, при сборке образов. Он определяет среду выполнения приложения. Таким образом, он помогает разработчикам избежать несоответствий в зависимостях или изменения версий среды выполнения. Введите следующую команду, чтобы создать Dockerfile:
|
1 |
nano Dockerfile |
Образ Docker создается с использованием нескольких слоев образов, которые надстраиваются друг над другом. Вы начинаете с добавления базового образа, который служит отправной точкой для приложения.
Поскольку приложение должно работать в среде node.js, мы начнем с добавления образа node:10-alpine image для node.js. На момент написания этого руководства это recommended LTS version of Node.js. Мы выбрали именно этот образ, потому что он основан на проекте Alpine Linux project. Таким образом, это поможет свести размер нашего образа к минимуму. На странице Docker Hub Node images page доступно несколько вариантов образов, которые вы можете выбрать в зависимости от ваших потребностей.
Добавьте следующий код, чтобы задать базовый образ приложения с помощью директивы FROM:
|
1 |
FROM node:10-alpine |
Этот образ включает Node.js и npm. Каждый Dockerfile должен начинаться с директивы FROM. Образ Docker node по умолчанию поставляется с пользователем node без прав root, которого вы можете использовать для запуска контейнера приложения вместо root. Docker security recommends не запускать контейнеры от имени root и ограничивать привилегии только теми, которые необходимы для работы его ресурсов.
В таком случае мы будем использовать домашний каталог пользователя node в качестве рабочей директории для приложения, а также самого пользователя внутри контейнера. Вы можете обратиться к этому руководству по Docker Node image best practices для получения дополнительной информации.
Мы создадим подкаталог node_modules внутри /home/node вместе с директорией app, чтобы упростить настройку прав доступа для кода приложения. Создание этих директорий гарантирует, что они будут иметь правильные права доступа, когда мы запустим команду npm install локально внутри контейнеров. После создания директорий вы должны передать права владения ими пользователю node. Мы сделаем это внутри Dockerfile, добавив следующую строку:
|
1 |
mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app |
Затем вы установите рабочую директорию, добавив следующую строку:
|
1 |
WORKDIR /home/node/app |
Рекомендуется всегда устанавливать WORKDIR, чтобы Docker не приходилось создавать ее по умолчанию.
Добавьте следующую строку, чтобы скопировать файлы package.json и package-lock.json:
|
1 |
COPY package*.json ./ |
Рекомендуется добавлять инструкцию COPY перед запуском npm install или копированием исходного кода приложения. Это позволяет использовать механизм кэширования Docker. В процессе сборки Docker проверяет, есть ли у него кэшированный слой для каждой инструкции. Это означает, что если вы не меняли файл package.json, Docker будет использовать существующий слой образа и избежит повторной установки node modules, что ускорит процесс сборки.
Перед запуском npm install, добавьте следующую строку, чтобы переключить пользователя на node, чтобы гарантировать, что все файлы приложения и директория node_modules принадлежат пользователю node без прав root:
|
1 |
USER node |
Теперь наш контейнер готов к запуску команды npm install. Добавьте следующую строку в Dockerfile:
|
1 |
RUN npm install |
После установки node_modules добавьте следующую строку, которая укажет Docker скопировать код приложения в директорию приложения на контейнере с правильными правами доступа и владельцем, то есть пользователем node без прав root:
|
1 |
COPY --chown=node:node . . |
Последний шаг — открыть порт 8090 на контейнере, как мы определили в нашем входном файле index.js:
|
1 2 |
EXPOSE 8090 CMD [ "node", "index.js" ] |
EXPOSE определяет, какие порты на контейнере будут открыты во время выполнения. CMD запускает команду для запуска приложения, в данном случае node index.js.
В Dockerfile должна быть только одна инструкция CMD, так как действует только последняя. Пожалуйста, ознакомьтесь с справочной документацией по Dockerfile, чтобы узнать, что еще можно делать с помощью Dockerfile.
Ваш готовый Dockerfile должен выглядеть следующим образом:
|
1 2 3 4 5 6 7 8 9 |
FROM node:10-alpine RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY package*.json ./ USER node RUN npm install COPY --chown=node:node . . EXPOSE 8090 CMD [ "node", "index.js" ] |
Теперь вы можете сохранить и закрыть файл.
Следующий шаг — добавление файла .dockerignore. Как и файл .gitignore, .dockerignore указывает, какие файлы и директории в каталоге проекта не следует копировать в контейнер.
Откройте файл в редакторе nano:
|
1 |
nano .dockerignore |
Добавьте в файл следующие строки:
|
1 2 3 4 |
node_modules npm-debug.log Dockerfile .dockerignore |
Если вы работаете с репозиторием git, вам также следует добавить директорию .git и файл .gitignore. Сохраните и закройте файл.
Если все прошло успешно, пришло время собрать образ приложения с помощью команды docker build. Вы можете добавить флаг –t к команде docker build, чтобы присвоить образу понятное имя вместо случайной строки, которую Docker устанавливает по умолчанию. Мы также будем отправлять образ на Docker Hub, поэтому лучше всего включить ваше имя пользователя Docker Hub в тег.
Мы будем использовать nodejs-express-image в качестве имени тега. Вы можете выбрать любое имя тега, которое вам нравится. Вот команда для сборки образа:
|
1 |
sudo docker build -t your_dockerhub_username/nodejs-express-image . |
Не забудьте заменить your_dockerhub_username на ваше настоящее имя пользователя Docker Hub. Точка (.) в конце указывает, что контекстом сборки является текущий каталог.
Процесс сборки занимает минуту или две. Как только он завершится, введите команду для проверки ваших образов:
|
1 |
sudo docker images |
Вы должны увидеть что-то подобное:
Помните, что мы заменили your_dockerhub_username на реальное имя пользователя.
Убедившись, что ваш образ собран, вы можете создать контейнер на его основе с помощью docker run. Будут включены следующие флаги:
-p: публикует порт контейнера и сопоставляет его с портом на хост-системе. В демонстрационных целях мы будем использовать порт 80 на хост-системе. Однако, если на этом порту у вас запущен другой процесс, вы можете изменить его по своему усмотрению. Узнайте больше о привязке портов в документации Docker.-d: для фонового режима (detached mode). Позволяет контейнеру продолжать работу в фоновом режиме.--name: вы можете использовать этот флаг, чтобы задать понятное имя вместо того, чтобы позволить Docker назначить случайную строку.
Команда для создания контейнера выглядит следующим образом. Замените имя пользователя Docker Hub соответствующим образом:
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
Подождите, пока контейнер соберется и запустится. Вы можете использовать эту команду для проверки всех запущенных контейнеров:
|
1 |
sudo docker ps |
Вы должны увидеть вывод, похожий на следующий:
Как видно из вывода, контейнер запущен. Вы можете просмотреть его в браузере, перейдя по публичному IP-адресу вашего сервера без указания порта. Загрузится ваша домашняя страница:
Вы успешно развернули статический веб-сайт Node Express с помощью Docker. Давайте посмотрим, как мы можем отправить этот образ на Docker Hub для дальнейшего использования и масштабирования.
Шаг 4. Работа с репозиториями образов Docker
Вы можете отправлять свои образы в реестры образов, такие как Docker Hub, и сохранять их для будущего использования, делиться ими с другими разработчиками или использовать для масштабирования ваших контейнеров. Мы можем отправить созданный нами образ в Docker Hub и использовать его для повторного создания контейнера.
Используйте следующую команду для входа в свою учетную запись Docker Hub. Замените ее на ваше фактическое имя пользователя Docker Hub:
|
1 |
sudo docker login -u your_dockerhub_username |
Введите пароль по запросу. После входа в систему файл ~/.docker/config.json создается в домашнем каталоге вашего пользователя и содержит ваши учетные данные Docker Hub.
После этого введите следующую команду, чтобы отправить образ в Docker Hub, указав тег, который вы задали при сборке образа ранее:
|
1 |
sudo docker push your_dockerhub_username/nodejs-express-image |
Эта команда отправляет docker-образ в вашу учетную запись Docker Hub. Если вы перейдете в свою учетную запись, вы увидите недавно отправленный образ:
Мы можем протестировать полезность репозитория образов, удалив текущий контейнер приложения и перестроив его с использованием образа из репозитория.
Выведите список текущих контейнеров, введя команду:
|
1 |
sudo docker ps |
Вы должны увидеть вывод, похожий на следующий:
Обратите внимание на CONTAINER ID, указанный в выводе, скопируйте его и используйте для остановки контейнера с помощью команды, заменив ID на ваш:
|
1 |
sudo docker stop 1bb2d65279bb |
Введите следующую команду, чтобы вывести список всех docker-образов, доступных в вашей системе:
|
1 |
sudo docker images –a |
В выводе будет показано имя вашего образа, образ node.js и другие образы, созданные в процессе сборки.
Введите следующую команду, чтобы удалить образы, включая неиспользуемые или висящие образы:
|
1 |
sudo docker system prune |
Введите y для подтверждения. Это удалит остановленные контейнеры и образы. Если вы выведете их список, вы увидите пустой список в выводе:
Теперь вы удалили как контейнер, в котором работало приложение, так и сам образ. Узнайте больше об удалении контейнеров, образов и томов Docker, следуя нашему руководству.
Теперь мы можем воссоздать весь процесс, сначала загрузив образ из Docker Hub с помощью следующей команды. Замените имя пользователя Docker Hub соответствующим образом:
|
1 |
sudo docker pull your_dockerhub_username/nodejs-express-image |
Снова выведите список ваших образов Docker с помощью команды:
|
1 |
sudo docker images |
Вы должны увидеть образ в выводе:
Теперь вы можете перестроить свой контейнер, используя команду из Шага 3. Конечно, замените имя пользователя Docker Hub там, где это необходимо:
|
1 |
sudo docker run --name nodejs-express-image -p 80:8090 -d your_dockerhub_username/nodejs-express-image |
Выведите список ваших контейнеров, чтобы подтвердить, что он был перестроен:
|
1 |
sudo docker ps |
Вы должны увидеть похожий вывод:
В браузере перейдите по публичному IP-адресу вашего сервера, и вы увидите, что ваше приложение работает.
Заключение
Если вы следовали руководству до этого момента, теперь у вас есть статический веб-сайт, созданный с помощью Express и Bootstrap и развернутый с помощью Docker. Вы использовали файлы статического веб-сайта для сборки Docker-образа и использовали этот образ для создания контейнера. Затем вы отправили образ в реестр Docker-образов, Docker Hub, сделав его доступным для будущего использования или масштабирования. Чтобы протестировать использование реестра образов, вы удалили образы и контейнеры, загрузили образы из реестра и заново создали контейнеры.
В этом руководстве объяснялось, как развернуть приложение Node.js. Если вы хотите узнать, как использовать другой стек веб-разработки, у нас есть руководство по Развертыванию приложения Laravel с помощью Docker Compose на Nginx.
Дополнительные ресурсы по использованию Docker см. в следующих руководствах:
- Как установить и настроить Docker Compose на Ubuntu 20.04
- Как обмениваться данными между контейнером Docker и хостом
- Установка и настройка Docker на CentOS 7
Приятной работы!











Комментарии
Комментариев пока нет. Будьте первым.