Вступление
Платформа Docker позволяет разработчикам упаковывать и запускать приложения как containers. Контейнер - это изолированный процесс, который выполняется в общей операционной системе, предлагая более легкую альтернативу виртуальным машинам. Хотя контейнеры не являются новыми, они предлагают преимущества, в том числе изоляцию процессов и стандартизацию среды, которые приобретают все большее значение по мере того, как все больше разработчиков используют распределенные архитектуры приложений.
При создании и масштабировании приложения с помощью Docker отправной точкой обычно является создание образа для вашего приложения, который затем можно запустить в контейнере. Образ включает в себя код приложения, библиотеки, файлы конфигурации, переменные среды и среду выполнения. Использование изображения гарантирует, что среда в вашем контейнере стандартизирована и содержит только то, что необходимо для построения и запуска вашего приложения.
В этом руководстве вы создадите образ приложения для статического веб-сайта, который использует платформу Express и Bootstrap. Затем вы создадите контейнер с использованием этого изображения и отправите его на Docker Hub для дальнейшего использования. Наконец, вы извлечете сохраненное изображение из вашего хранилища Docker Hub и создадите другой контейнер, демонстрирующий, как вы можете воссоздать и масштабировать ваше приложение.
Предпосылки
Чтобы следовать этому уроку, вам понадобится:
-
Один сервер Ubuntu 18.04, настроенный в соответствии с этим Initial Руководством по установке сервера.
-
Docker установлен на вашем сервере, следуя шагам 1 и 2 из Как установить и Используйте Docker в Ubuntu 18.04.
-
Node.js и npm установлены, следуя these инструкциям при установке с помощью PPA, управляемого NodeSource.
-
Учетная запись Docker Hub. Чтобы узнать, как это настроить, обратитесь к this вводная информация о начале работы с Docker Hub.
Шаг 1 - Установка зависимостей вашего приложения
Чтобы создать изображение, сначала необходимо создать файлы приложения, которые затем можно скопировать в контейнер. Эти файлы будут включать в себя статическое содержимое, код и зависимости вашего приложения.
Сначала создайте каталог для вашего проекта в домашнем каталоге вашего пользователя без полномочий root. Мы назовем наш ++
, но вы можете смело заменять это чем-то другим:
mkdir
Перейдите в этот каталог:
cd
Это будет корневой каталог проекта.
Затем создайте файл https://docs.npmjs.com/files/package.json [+ package.json +
] с зависимостями вашего проекта и другой идентифицирующей информацией. Откройте файл с помощью + nano +
или вашего любимого редактора:
nano package.json
Добавьте следующую информацию о проекте, включая его имя, автора, лицензию, точку входа и зависимости. Обязательно замените информацию об авторе своим именем и контактными данными:
~ / Node_project / package.json
{
"name": "",
"version": "1.0.0",
"description": "nodejs image demo",
"author": "",
"license": "MIT",
"main": "app.js",
"keywords": [
"nodejs",
"bootstrap",
"express"
],
"dependencies": {
"express": "^4.16.4"
}
}
Этот файл содержит имя проекта, автора и лицензию, по которой он является общим. Npm recommend делает имя вашего проекта коротким и наглядным, избегая дубликатов в реестре npm. Мы перечислили MIT license в поле лицензии, разрешив бесплатное использование и распространение кода приложения.
Дополнительно указан файл:
-
" main "
: точка входа для приложения,+ app.js
. Вы создадите этот файл дальше. -
" dependencies "
: зависимости проекта - в данном случае, Express 4.16.4 или выше.
Хотя этот файл не содержит список репозитория, вы можете добавить его, следуя этим рекомендациям на addory репозиторий в ваш файл + package.json +
. Это хорошее дополнение, если вы создаете версию своего приложения.
Сохраните и закройте файл, когда вы закончите вносить изменения.
Чтобы установить зависимости вашего проекта, выполните следующую команду:
npm install
Это установит пакеты, которые вы перечислили в вашем файле + package.json +
в каталоге вашего проекта.
Теперь мы можем перейти к созданию файлов приложения.
Шаг 2 - Создание файлов приложения
Мы создадим сайт, который предлагает пользователям информацию об акулах. Наше приложение будет иметь основную точку входа + app.js +
и каталог + views +
, который будет включать статические ресурсы проекта. Целевая страница + index.html +
предложит пользователям некоторую предварительную информацию и ссылку на страницу с более подробной информацией об акулах + sharks.html +
. В каталоге + views
мы создадим как целевую страницу, так и` + sharks.html`.
Сначала откройте + app.js +
в главном каталоге проекта, чтобы определить маршруты проекта:
nano app.js
Первая часть файла создаст приложение Express и объекты Router и определит базовый каталог и порт как константы:
~ / Node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();
const path = __dirname + '/views/';
const port = 8080;
Функция + require
загружает модуль` + express + , который мы затем используем для создания объектов
+ app` и + router &
. Объект + router +
будет выполнять функцию маршрутизации приложения, и когда мы определим маршруты метода HTTP, мы добавим их в этот объект, чтобы определить, как наше приложение будет обрабатывать запросы.
Этот раздел файла также устанавливает пару констант, + path
и` + port`:
-
+ path +
: Определяет базовый каталог, который будет подкаталогом+ views +
в текущем каталоге проекта. -
+ port +
: говорит приложению прослушивать и связываться с портом+ 8080 +
.
Затем установите маршруты для приложения, используя объект + router +
:
~ / Node_project / app.js
...
router.use(function (req,res,next) {
console.log('/' + req.method);
next();
});
router.get('/', function(req,res){
res.sendFile(path + 'index.html');
});
router.get('/sharks', function(req,res){
res.sendFile(path + 'sharks.html');
});
Функция + router.use +
загружает middleware функцию, которая будет регистрировать запросы маршрутизатора и передавать их на маршруты приложения. Они определены в последующих функциях, которые указывают, что GET-запрос к URL базового проекта должен возвращать страницу + index.html +
, а GET-запрос к маршруту + / sharks +
должен возвращать + sharks.html +
,
Наконец, подключите промежуточное ПО + router +
и статические ресурсы приложения и скажите приложению прослушивать порт + 8080 +
:
~ / Node_project / app.js
...
app.use(express.static(path));
app.use('/', router);
app.listen(port, function () {
console.log('Example app listening on port 8080!')
})
Готовый файл + app.js
будет выглядеть так:
~ / Node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();
const path = __dirname + '/views/';
const port = 8080;
router.use(function (req,res,next) {
console.log('/' + req.method);
next();
});
router.get('/', function(req,res){
res.sendFile(path + 'index.html');
});
router.get('/sharks', function(req,res){
res.sendFile(path + 'sharks.html');
});
app.use(express.static(path));
app.use('/', router);
app.listen(port, function () {
console.log('Example app listening on port 8080!')
})
Сохраните и закройте файл, когда вы закончите.
Далее, давайте добавим немного статического контента в приложение. Начните с создания каталога + views +
:
mkdir views
Откройте файл целевой страницы + index.html
:
nano views/index.html
Добавьте следующий код в файл, который будет импортировать Boostrap и создать компонент jumbotron со ссылкой на более подробную + sharks.html +
информационную страницу :
~ / Node_project / просмотров / index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>About Sharks</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="css/styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
</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">Toggle navigation</span>
</button> <a class="navbar-brand" href="#">Everything Sharks</a>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav mr-auto">
<li class="active nav-item"><a href="/" class="nav-link">Home</a>
</li>
<li class="nav-item"><a href="/sharks" class="nav-link">Sharks</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="jumbotron">
<div class="container">
<h1>Want to Learn About Sharks?</h1>
<p>Are you ready to learn about sharks?</p>
<br>
<p><a class="btn btn-primary btn-lg" href="/sharks" role="button">Get Shark Info</a>
</p>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-6">
<h3>Not all sharks are alike</h3>
<p>Though some are dangerous, sharks generally do not attack humans. Out of the 500 species known to researchers, only 30 have been known to attack humans.
</p>
</div>
<div class="col-lg-6">
<h3>Sharks are ancient</h3>
<p>There is evidence to suggest that sharks lived up to 400 million years ago.
</p>
</div>
</div>
</div>
</body>
</html>
Https://getbootstrap.com/docs/4.0/components/navbar/[navbar] верхнего уровня позволяет пользователям переключаться между страницами * Home * и * Sharks *. В подкомпоненте + navbar-nav
мы используем Bootstrap` + active` для указания текущей страницы пользователю. Мы также указали маршруты к нашим статическим страницам, которые соответствуют маршрутам, которые мы определили в + app.js +
:
~ / Node_project / просмотров / index.html
...
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav mr-auto">
<li class="active nav-item"><a href="/" class="nav-link">Home</a>
</li>
<li class="nav-item"><a href="/sharks" class="nav-link">Sharks</a>
</li>
</ul>
</div>
...
Кроме того, мы создали ссылку на нашу страницу с информацией об акулах в кнопке нашего jumbotron:
~ / Node_project / просмотров / index.html
...
<div class="jumbotron">
<div class="container">
<h1>Want to Learn About Sharks?</h1>
<p>Are you ready to learn about sharks?</p>
<br>
<p><a class="btn btn-primary btn-lg" href="/sharks" role="button">Get Shark Info</a>
</p>
</div>
</div>
...
В шапке также есть ссылка на пользовательскую таблицу стилей:
~ / Node_project / просмотров / index.html
...
<link href="css/styles.css" rel="stylesheet">
...
Мы создадим эту таблицу стилей в конце этого шага.
Сохраните и закройте файл, когда вы закончите.
Имея целевую страницу приложения, мы можем создать нашу информационную страницу об акулах + sharks.html +
, которая будет предлагать заинтересованным пользователям больше информации об акулах.
Откройте файл:
nano views/sharks.html
Добавьте следующий код, который импортирует Bootstrap и пользовательскую таблицу стилей и предлагает пользователям подробную информацию об определенных акулах:
~ / Node_project / просмотров / sharks.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>About Sharks</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="css/styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Merriweather:400,700" rel="stylesheet" type="text/css">
</head>
<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">Toggle navigation</span>
</button> <a class="navbar-brand" href="/">Everything Sharks</a>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav mr-auto">
<li class="nav-item"><a href="/" class="nav-link">Home</a>
</li>
<li class="active nav-item"><a href="/sharks" class="nav-link">Sharks</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="jumbotron text-center">
<h1>Shark Info</h1>
</div>
<div class="container">
<div class="row">
<div class="col-lg-6">
<p>
<div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
</div>
<img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
</p>
</div>
<div class="col-lg-6">
<p>
<div class="caption">Other sharks are known to be friendly and welcoming!</div>
<img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
</p>
</div>
</div>
</div>
</html>
Обратите внимание, что в этом файле мы снова используем класс + active +
для обозначения текущей страницы.
Сохраните и закройте файл, когда вы закончите.
Наконец, создайте пользовательскую таблицу стилей CSS, с которой вы связались в + index.html +
и + sharks.html +
, сначала создав папку + css +
в каталоге + views +
:
mkdir views/css
Откройте таблицу стилей:
nano views/css/styles.css
Добавьте следующий код, который установит желаемый цвет и шрифт для наших страниц:
~ / Node_project / просмотров / CSS / styles.css
.navbar {
margin-bottom: 0;
}
body {
background: #020A1B;
color: #ffffff;
font-family: 'Merriweather', sans-serif;
}
h1,
h2 {
font-weight: bold;
}
p {
font-size: 16px;
color: #ffffff;
}
.jumbotron {
background: #0048CD;
color: white;
text-align: center;
}
.jumbotron p {
color: white;
font-size: 26px;
}
.btn-primary {
color: #fff;
text-color: #000000;
border-color: white;
margin-bottom: 5px;
}
img,
video,
audio {
margin-top: 20px;
max-width: 80%;
}
div.caption: {
float: left;
clear: both;
}
В дополнение к настройке шрифта и цвета этот файл также ограничивает размер изображений, указав + max-width +
в 80%. Это помешает им занять больше места, чем нам хотелось бы на странице.
Сохраните и закройте файл, когда вы закончите.
После установки файлов приложения и установки зависимостей проекта вы готовы запустить приложение.
Если вы выполнили предварительное руководство по настройке сервера в предварительных условиях, у вас будет активный брандмауэр, разрешающий только трафик SSH. Для разрешения трафика на порт + 8080 +
выполните:
sudo ufw allow 8080
Чтобы запустить приложение, убедитесь, что вы находитесь в корневом каталоге вашего проекта:
cd ~/
Запустите приложение с помощью + node app.js
:
node app.js
Перейдите в браузере по адресу + http: //: 8080 +
. Вы увидите следующую целевую страницу:
изображение: https: //assets.digitalocean.com/articles/docker_node_image/landing_page.png [целевая страница приложения]
Нажмите на кнопку * Получить информацию об акуле *. Вы увидите следующую информационную страницу:
изображение: https: //assets.digitalocean.com/articles/docker_node_image/sharks.png [Страница информации об акулах]
Теперь у вас есть приложение и работает. Когда вы будете готовы, выйдите из сервера, набрав + CTRL + C +
. Теперь мы можем перейти к созданию Dockerfile, который позволит нам заново создать и масштабировать это приложение по желанию.
Шаг 3 - Написание Dockerfile
Ваш Dockerfile указывает, что будет включено в контейнер приложения при его выполнении. Использование Dockerfile позволяет вам определять вашу контейнерную среду и избегать расхождений с зависимостями или версиями времени выполнения.
Следуя these руководствам по созданию оптимизированных контейнеров, мы сделаем наше изображение максимально эффективным, сведя к минимуму количество слоев изображения и ограничение функции изображения одной целью - воссоздание файлов нашего приложения и статического содержимого.
В корневом каталоге вашего проекта создайте Dockerfile:
nano Dockerfile
Изображения Docker создаются с использованием последовательности многоуровневых изображений, которые строятся друг на друге. Нашим первым шагом будет добавление базового образа для вашего приложения, который сформирует отправную точку сборки приложения.
Давайте использовать https://hub.docker.com//node/ [+ узел: +
изображение], поскольку на момент написания этой статьи это recom рекомендуется LTS версия Node.js. Изображение + alpine +
получено из проекта Alpine Linux и поможет нам уменьшить размер изображения. Для получения дополнительной информации о том, является ли изображение + alpine +
правильным выбором для вашего проекта, см. Полное обсуждение в разделе * Варианты изображения * на https://hub.docker.com//node/ [ Страница изображения узла докера-концентратора.
Добавьте следующую инструкцию + FROM +
, чтобы установить базовый образ приложения:
~ / Node_project / Dockerfile
FROM node:
Это изображение включает в себя Node.js и npm. Каждый Dockerfile должен начинаться с инструкции + FROM +
.
По умолчанию образ Docker Node включает пользователя без полномочий root * node *, которого вы можете использовать, чтобы избежать запуска контейнера приложения с именем * root *. Рекомендуется избегать запуска контейнеров с правами * root * и указывать restrict в контейнере только те, которые требуются для запустить свои процессы. Поэтому мы будем использовать домашний каталог пользователя * node * в качестве рабочего каталога для нашего приложения и назначать его в качестве нашего пользователя внутри контейнера. Дополнительную информацию о передовых практиках при работе с изображением Docker Node см. В этом best практика руководство.
Чтобы точно настроить разрешения для кода нашего приложения в контейнере, давайте создадим подкаталог + node_modules +
в + / home / node +
вместе с каталогом + app +
. Создание этих каталогов гарантирует, что у них есть необходимые разрешения, что будет важно, когда мы создаем модули локальных узлов в контейнере с помощью + npm install +
. В дополнение к созданию этих каталогов мы установим право собственности на них для нашего пользователя * node *:
~ / Node_project / Dockerfile
...
RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app
Для получения дополнительной информации о полезности консолидации инструкций + RUN +
см. Этот https://www.digitalocean.com/community/tutorials/building-optimized-containers-for-kubernetes#managing-container-layers[discussion о том, как управлять слоями контейнера.
Затем установите рабочий каталог приложения в + / home / node / app
:
~ / Node_project / Dockerfile
...
WORKDIR /home/node/app
Если + WORKDIR +
не установлен, Docker создаст его по умолчанию, поэтому рекомендуется установить его явно.
Затем скопируйте файлы + package.json
и` + package-lock.json` (для npm 5+):
~ / Node_project / Dockerfile
...
COPY package*.json ./
Добавление этой инструкции + COPY +
перед запуском + npm install +
или копирование кода приложения позволяет нам использовать механизм кэширования Docker. На каждом этапе сборки Docker будет проверять наличие кэшированного слоя для этой конкретной инструкции. Если мы изменим + package.json +
, этот слой будет перестроен, но если мы этого не сделаем, эта инструкция позволит Docker использовать существующий слой изображения и пропустить переустановку модулей нашего узла.
Чтобы убедиться, что все файлы приложения принадлежат пользователю без полномочий root * node *, включая содержимое каталога + node_modules +
, переключите пользователя на * node * перед запуском + npm install +
:
~ / Node_project / Dockerfile
...
USER node
После копирования зависимостей проекта и переключения нашего пользователя, мы можем запустить + npm install
:
~ / Node_project / Dockerfile
...
RUN npm install
Затем скопируйте код приложения с соответствующими разрешениями в каталог приложения на контейнере:
~ / Node_project / Dockerfile
...
COPY --chown=node:node . .
Это обеспечит принадлежность файлов приложения пользователю без полномочий root * node *.
Наконец, выставьте порт + 8080 +
на контейнер и запустите приложение:
~ / Node_project / Dockerfile
...
EXPOSE 8080
CMD [ "node", "app.js" ]
+ EXPOSE +
не публикует порт, а вместо этого служит способом документирования того, какие порты в контейнере будут опубликованы во время выполнения. + CMD +
запускает команду для запуска приложения - в этом случае +node app.js + `
, Обратите внимание, что в каждом файле Docker должна быть только одна инструкция `+ CMD +