Автоматизация развертывания приложения Node.js в производство с помощью Shipit в CentOS 7

Shipit – это универсальный инструмент для автоматизации и развертывания приложений, разработанных на Node.js. Он поддерживает поток задач, основанный на популярном пакете Orchestrator, логин и интерактивные SSH-команды по OpenSSH, а также расширяемый API. Разработчики могут использовать Shipit для автоматизации рабочих процессов сборки и развертывания широкого спектра приложений Node.js.

Рабочий процесс Shipit позволяет разработчикам не только настраивать задачи, но и указывать среду порядок их выполнения; Shipit может выполнять их синхронно или асинхронно.

В этом мануале вы узнаете, как установить и настроить Shipit для развертывания приложения Node.js из локальной среды разработки в производственную среду. Процесс развертывания приложения и настройки удаленного сервера будет включать такие этапы:

  • перенос файлов приложения Node.js из локальной среды в производственную среду (с использованием rsync, git и ssh).
  • установка зависимостей приложения (модули Node.js).
  • настройка и управление процессами Node.js, запущенными на удаленном сервере с PM2.

Требования

Примечание: Пользователям Windows нужно установить Windows Subsystem for Linux, чтобы выполнить команды этого мануала.

1: Настройка удаленного репозитория

Для синхронизации между локальным компьютером разработчика и удаленным сервером Shipit требуется Git-репозиторий. На этом этапе мы создадим удаленный репозиторий на Github.com. Хотя провайдеры немного отличаются друг от друга, команды будут почти одинаковые.

Чтобы создать репозиторий, откройте Github.com в своем веб-браузере и войдите в систему. Вы заметите, что в правом верхнем углу страницы есть символ +. Нажмите +, а затем выберите New repository.

Введите короткое запоминающееся имя своего репозитория (например, hello-world). Обратите внимание, любое выбранное здесь имя будет реплицировано как папка проекта, с которой вы будете работать на локальном компьютере.

При желании добавьте описание вашего репозитория.

Настройте видимость репозитория по своему усмотрению (он может быть публичным и частным).

Убедитесь, что репозиторий инициализирован с помощью .gitignore. Выберите Node из выпадающего списка Add .gitignore. Этот шаг важен, поскольку позволяет избежать добавления ненужных файлов (таких как папка node_modules) в ваш репозиторий.

Нажмите кнопку Create repository.

Теперь его необходимо клонировать с Github.com на ваш локальный компьютер.

Откройте свой терминал и перейдите в место, где вы хотите хранить все ваши файлы проекта Node.js. Обратите внимание, этот процесс создаст подпапку в текущем каталоге. Чтобы клонировать репозиторий на свой локальный компьютер, выполните следующую команду:

git clone https://github.com/your-github-username/your-github-repository-name.git

Вам нужно заменить your-github-username и your-github-repository-name и указать ваше имя пользователя Github и ранее выбранное имя репозитория.

Примечание: Если вы включили двухфакторную аутентификацию (2FA) на Github.com, при доступе к Github в командной строке вы должны использовать вместо пароля токен личного доступа или ключ SSH. Страница справки Github о 2FA предоставляет дополнительную информацию.

Вы увидите такой вывод:

Cloning into 'your-github-repository-name'...
remote: Enumerating objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3
Unpacking objects: 100% (3/3), done.

Перейдите в репозиторий, выполнив следующую команду:

cd your-github-repository-name

Внутри репозитория находятся один файл и одна папка, они используются Git для управления репозиторием. Вы можете проверить их наличие с помощью команды:

ls -la
total 8
0 drwxr-xr-x   4 asciant  staff  128 22 Apr 07:16 .
0 drwxr-xr-x   5 asciant  staff  160 22 Apr 07:16 ..
0 drwxr-xr-x  13 asciant  staff  416 22 Apr 07:16 .git
8 -rw-r--r--   1 asciant  staff  914 22 Apr 07:16 .gitignore

Теперь пора создать файл shipit.js, который управляет процессом развертывания.

2: Интеграция Shipit в проект Node.js

На этом этапе вы создадите свой тестовый проект Node.js, а затем добавите пакеты Shipit. В этом мануале тестовое приложение Node.js будет находиться на сервере web, оно будет принимать HTTP-запросы и отвечать «Hello World» в виде простого текста. Чтобы создать приложение, выполните следующую команду:

nano hello.js

Добавьте следующий блок кода приложения в hello.js (в переменной APP_PRIVATE_IP_ADDRESS нужно указать IP-адрес частной сети сервера app).

var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8080, 'APP_PRIVATE_IP_ADDRESS');
console.log('Server running at http://APP_PRIVATE_IP_ADDRESS:8080/');

Теперь создайте файл package.json для своего приложения:

npm init -y

Эта команда создает файл package.json, который вы будете использовать для настройки приложения Node.js. С помощью интерфейса командной строки npm вставьте в этот файл зависимости вашего проекта.

Wrote to ~/hello-world/package.json:
{
"name": "hello-world",
"version": "1.0.0",
"description": "",
"main": index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

Затем установите необходимые пакеты npm с помощью следующей команды:

npm install --save-dev shipit-cli shipit-deploy shipit-shared

Флаг —save-dev в этой команде позволяет установить пакеты Shipit только на вашем локальном компьютере. Вы увидите похожий вывод:

+ shipit-shared@4.4.2
+ shipit-cli@4.2.0
+ shipit-deploy@4.1.4
updated 4 packages and audited 21356 packages in 11.671s
found 62 low severity vulnerabilities run `npm audit fix` to fix them, or `npm audit` for details

Команда также добавила в ваш файл package.json три пакета – зависимости разработки:

. . .
"devDependencies": {
"shipit-cli": "^4.2.0",
"shipit-deploy": "^4.1.4",
"shipit-shared": "^4.4.2"
},
. . .

После настройки локальной среды вы можете перейти к подготовке удаленного сервера app для развертывания приложения Shipit.

3: Подготовка удаленного сервера для развертывания

Сейчас мы с помощью ssh подключимся к серверу app и установим зависимость rsync. Rsync – это утилита для эффективной передачи и синхронизации файлов между локальными и сетевыми компьютерами путем сравнения времени изменения и размеров файлов.

Shipit использует rsync для передачи и синхронизации файлов между вашим локальным компьютером и удаленным сервером app. Вы не будете запускать команды rsync напрямую – Shipit справится с этим самостоятельно.

Примечание: После выполнения мануала Подготовка приложения Node.js к производству в CentOS 7 у вас осталось два сервера – app и web. Эти команды нужно выполнять только на app.

Подключитесь к вашему удаленному серверу приложений через ssh:

ssh deployer@your_app_server_ip

Установите rsync на свой сервер, выполнив следующую команду:

sudo yum install rsync

Подтвердите установку с помощью этой команды:

rsync --version

В выходных данных этой команды вы увидите похожую строку:

rsync  version 3.1.2  protocol version 31
. . .

Вы можете завершить сеанс ssh, введя команду exit.

После установки rsync вы можете перейти к задачам развертывания.

4: Настройка и выполнение задач развертывания

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

Типичным примером использования этой системы «событие-задача» в приложении Node.js является установка зависимостей приложения (node_modules) на удаленном сервере. Позже, когда мы перейдем к этому этапу, Shipit прослушает обновленное событие (которое генерируется после передачи файлов приложения) и запустит задачу для установки зависимостей приложения (npm install) на удаленном сервере.

Чтобы прослушивать события и выполнять задачи, Shipit необходим конфигурационный файл, который содержит информацию о вашем удаленном сервере (сервере app) и регистрирует прослушиватели событий и команды, которые должны быть выполнены этими задачами. Этот файл должен находиться на вашем локальном компьютере разработки, в каталоге приложения Node.js.

Чтобы начать, создайте этот файл, включите в него информацию о вашем удаленном сервере, прослушивателях событий, на которые вы хотите подписаться, и некоторые определения задач. Создайте файл shipitfile.js в корневом каталоге приложения на локальном компьютере, выполнив следующую команду:

nano shipitfile.js

Теперь, когда вы создали файл, его нужно заполнить необходимой Shipit информацией о среде. Это в первую очередь расположение удаленного Git-репозитория и, что важно, внешний IP-адрес сервера app и учетная запись пользователя SSH.

Добавьте эту базовую конфигурацию (в выделенных строках укажите информацию о вашей среде):

module.exports = shipit => {
require('shipit-deploy')(shipit);
require('shipit-shared')(shipit);
const appName = 'hello';
shipit.initConfig({
default: {
deployTo: '/home/8host/your-domain',
repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
keepReleases: 5,
shared: {
overwrite: true,
dirs: ['node_modules']
}
},
production: {
servers: '8host@YOUR_APP_SERVER_PUBLIC_IP'
}
});
const path = require('path');
const ecosystemFilePath = path.join(
shipit.config.deployTo,
'shared',
'ecosystem.config.js'
);
// Our listeners and tasks will go here
};

Обновление переменных в вашем методе shipit.initConfig предоставляет Shipit специфичную конфигурацию для вашего развертывания. Shipit читает их так:

  • deployTo: каталог, в который Shipit будет развертывать код приложения на удаленном сервере. Здесь это папка /home/ вашего пользователя с привилегиями sudo (/home/8host), поскольку он защищен и это позволит избежать проблем с привилегиями. Компонент /your-domain – это соглашение об именах, позволяющее отличать эту папку от других в домашней папке пользователя.
  • repositoryUrl: это URL-адрес полного репозитория Git. Shipit будет использовать этот URL-адрес, чтобы обеспечить синхронизацию файлов проекта перед развертыванием.
  • keepReleases: количество релизов, сохраняемых на удаленном сервере. release  – это папка с меткой даты, содержащая файлы вашего приложения на момент релиза. Они могут быть полезны для отката развертывания.
  • shared: конфигурация, связанная с keepReleases. Она позволяет разделять каталоги между релизами. В этом случае у нас есть одна папка node_modules, которая используется всеми версиями.
  • production: удаленный сервер для развертывания вашего приложения. В этом случае у вас есть один сервер (сервер app), который вы называете production. Конфигурация servers: содержит имя пользователя и внешний IP-адрес. Имя production соответствует команде развертывания Shipit, которую мы используем в конце этого руководства (npx shipit server name deploy, что в нашем случае будет npx shipit production deploy).

Дополнительную информацию о конфигурации развертывания Shipit можно найти в репозитории Shipit на Github.

Прежде чем продолжать работу с shipitfile.js, давайте рассмотрим следующий пример кода, чтобы понять задачи Shipit:

Example event listenershipit.on('deploy', () => {
shipit.start('say-hello');
});
shipit.blTask('say-hello', async () => {
shipit.local('echo "hello from your local computer"')
});

Это задача, которая использует метод shipit.on для подписки на событие deploy. Она будет ожидать, когда событие развертывания будет отправлено жизненным циклом Shipit. Затем, когда задача получит событие, она выполнит метод shipit.start, который сообщает Shipit, что нужно запустить (start ) задачу say-hello.

Метод shipit.on принимает два параметра: имя события, которое нужно прослушать, и функцию обратного вызова, которая будет выполняться при получении события.

В объявлении метода shipit.on задача определяется с помощью метода shipit.blTask. Это создает новую задачу Shipit, которая будет блокировать другие задачи во время своего выполнения (это синхронная задача). Метод shipit.blTask ​​также принимает два параметра: имя задачи, которую он определяет, и функцию обратного вызова, выполняемую, когда задача запускается shipit.start.

В функции обратного вызова этого примера задачи (say-hello) метод shipit.local выполняет команду на локальном компьютере. Локальная команда должна вывести «hello from your local computer» в терминал.

Если вы хотите выполнить команду на удаленном сервере, вы должны использовать метод shipit.remote. В рамках развертывания есть два метода, shipit.local и shipit.remote, они предоставляют API для выдачи команд локально или удаленно.

Теперь добавьте в файл shipitfile.js прослушиватели событий для подписки на жизненный цикл Shipit с помощью shipit.on. Вставьте их после комментария // Our tasks will go here:

. . .
shipit.on('updated', () => {
shipit.start('npm-install', 'copy-config');
});
shipit.on('published', () => {
shipit.start('pm2-server');
});

Эти два метода прослушивают обновленные и опубликованные события (updated и published), которые отправляются как часть жизненного цикла развертывания Shipit. Каждое полученное событие будет инициировать задачи через метод shipit.start (как в нашем примере выше).

Теперь, когда вы добавили прослушиватели, вам нужно добавить и соответствующую задачу. Вставьте следующую задачу в shipitfile.js после слушателей событий:

. . .
shipit.blTask('copy-config', async () => {
const fs = require('fs');
const ecosystem = `
module.exports = {
apps: [
{
name: '${appName}',
script: '${shipit.releasePath}/hello.js',
watch: true,
autorestart: true,
restart_delay: 1000,
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}
]
};`;
fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
if (err) throw err;
console.log('File created successfully.');
});
await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
});

Сначала вы объявляете задачу copy-config. Она создает локальный файл ecosystem.config.js, а затем копирует его на удаленный сервер app. PM2 использует этот файл для управления вашим приложением Node.js. Он предоставляет PM2 необходимую информацию о пути к файлу, чтобы он мог запускать ваши последние развернутые файлы. Позже в процессе сборки мы создадим задачу, которая запускает PM2 и применяет конфигурации ecosystem.config.js.

Если вашему приложению нужны переменные среды (например, строка подключения к базе данных), вы можете объявить их локально в env: или на удаленном сервере в env_production: (так же, как вы устанавливаете переменную NODE_ENV в этих объектах).

Добавьте следующую задачу в файл shipitfile.js после задачи copy-config:

. . .
shipit.blTask('npm-install', async () => {
shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
});

Это объявление задачи по имени npm-install. В ней удаленный терминал bash (через shipit.remote) используется для установки зависимостей приложения (пакетов npm).

Добавьте в файл shipitfile.js после npm-install последнюю задачу:

. . .
shipit.blTask('pm2-server', async () => {
await shipit.remote(`pm2 delete -s ${appName} || :`);
await shipit.remote(
`pm2 start ${ecosystemFilePath} --env production --watch true`
);
});

В этой задаче по имени pm2-server удаленный терминал bash используется, чтобы сначала остановить управление PM2 вашим предыдущим развертыванием с помощью команды delete, а затем запустить новый экземпляр сервера Node.js, предоставив файл ecosystem.config.js в качестве переменной. Также эта задача сообщает PM2, что он должен использовать переменные среды из блока production в вашей исходной конфигурации. Кроме того, PM2 будет наблюдать за приложением, перезапуская его в случае сбоя.

В результате файл shipitfile.js выглядит так:

module.exports = shipit => {
require('shipit-deploy')(shipit);
require('shipit-shared')(shipit);
const appName = 'hello';
shipit.initConfig({
default: {
deployTo: '/home/deployer/example.com',
repositoryUrl: 'https://git-provider.tld/YOUR_GIT_USERNAME/YOUR_GIT_REPO_NAME.git',
keepReleases: 5,
shared: {
overwrite: true,
dirs: ['node_modules']
}
},
production: {
servers: 'deployer@YOUR_APP_SERVER_PUBLIC_IP'
}
});
const path = require('path');
const ecosystemFilePath = path.join(
shipit.config.deployTo,
'shared',
'ecosystem.config.js'
);
// Our listeners and tasks will go here
shipit.on('updated', async () => {
shipit.start('npm-install', 'copy-config');
});
shipit.on('published', async () => {
shipit.start('pm2-server');
});
shipit.blTask('copy-config', async () => {
const fs = require('fs');
const ecosystem = `
module.exports = {
apps: [
{
name: '${appName}',
script: '${shipit.releasePath}/hello.js',
watch: true,
autorestart: true,
restart_delay: 1000,
env: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}
]
};`;
fs.writeFileSync('ecosystem.config.js', ecosystem, function(err) {
if (err) throw err;
console.log('File created successfully.');
});
await shipit.copyToRemote('ecosystem.config.js', ecosystemFilePath);
});
shipit.blTask('npm-install', async () => {
shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
});
shipit.blTask('pm2-server', async () => {
await shipit.remote(`pm2 delete -s ${appName} || :`);
await shipit.remote(
`pm2 start ${ecosystemFilePath} --env production --watch true`
);
});
};

Сохраните и закройте его.

После настройки shipitfile.js, событий и связанных задач вы можете перейти к развертыванию на сервере app.

5: Развертывание приложения

На этом этапе вы можете удаленно развернуть свое приложение и проверить, можно ли получить доступ к вашему приложению в Интернете.

Поскольку Shipit клонирует файлы проекта из удаленного репозитория Git, вам необходимо перенести файлы приложения Node.js с локального компьютера на Github. Перейдите в каталог приложения вашего проекта Node.js (где находятся hello.js и shiptitfile.js) и выполните следующую команду:

git status

Команда git status отображает состояние рабочего каталога и области подготовки. Она позволяет увидеть, какие изменения были внесены, а какие нет, и понять, какие файлы не отслеживаются Git. Если файлы не отслеживаются, они выделяются красным цветом:

On branch master
Your branch is up to date with 'origin/master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
hello.js
package-lock.json
package.json
shipitfile.js
nothing added to commit but untracked files present (use "git add" to track)

Вы можете добавить эти файлы в репозиторий с помощью следующей команды:

git add --all

Эта команда не выдает никаких выходных данных. Но если вы снова запустите git status, файлы будут выделены зеленым с пометкой о том, что есть изменения, которые нужно зафиксировать.

Вы можете создать коммит, выполнив следующую команду:

git commit -m "Our first commit"

Вывод этой команды предоставляет специфическую для Git информацию о файлах.

[master c64ea03] Our first commit
4 files changed, 1948 insertions(+)
create mode 100644 hello.js
create mode 100644 package-lock.json
create mode 100644 package.json
create mode 100644 shipitfile.js

Вам осталось только отправить коммит в удаленный репозиторий, чтобы Shipit клонировал его на сервер app  во время развертывания. Запустите следующую команду:

git push origin master

Вывод будет содержать информацию о синхронизации с удаленным репозиторием:

Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 15.27 KiB | 7.64 MiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:Asciant/hello-world.git
e274312..c64ea03  master -> master

Чтобы развернуть приложение, выполните следующую команду:

npx shipit production deploy

Вывод этой команды (который слишком велик, чтобы включать его полностью) предоставляет подробные сведения о задачах и результате выполнения конкретной функции. Следующие выходные данные для задачи pm2-server показывают, что приложение Node.js было запущено:

Running 'deploy:init' task...
Finished 'deploy:init' after 432 μs
. . .
Running 'pm2-server' task...

Running "pm2 delete -s hello || :" on host "centos-ap-app.asciant.com".


Running "pm2 start /home/deployer/example.com/shared/ecosystem.config.js --env production --watch true" on host "centos-ap-app.asciant.com".


@centos-ap-app.asciant.com [PM2][WARN] Node 4 is deprecated, please upgrade to use pm2 to have all features


@centos-ap-app.asciant.com [PM2][WARN] Applications hello not running, starting...


@centos-ap-app.asciant.com [PM2] App [hello] launched (1 instances)


@centos-ap-app.asciant.com ┌──────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬─────┬──────────┬──────────┬──────────┐


@centos-ap-app.asciant.com │ App name │ id │ version │ mode │ pid  │ status │ restart │ uptime │ cpu │ mem      │ user     │ watching │


@centos-ap-app.asciant.com ├──────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼─────┼──────────┼──────────┼──────────┤


@centos-ap-app.asciant.com │ hello    │ 0  │ 1.0.0   │ fork │ 4177 │ online │ 0       │ 0s     │ 0%  │ 4.5 MB   │ deployer │ enabled  │


@centos-ap-app.asciant.com └──────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴─────┴──────────┴──────────┴──────────┘


@centos-ap-app.asciant.com  Use `pm2 show <id|name>` to get more details about an app


Finished 'pm2-server' after 5.27 s


Running 'deploy:clean' task...


Keeping "5" last releases, cleaning others


Running "(ls -rd /home/deployer/example.com/releases/*|head -n 5;ls -d /home/deployer/example.com/releases/*)|sort|uniq -u|xargs rm -rf" on host "centos-ap-app.asciant.com".


Finished 'deploy:clean' after 1.81 s


Running 'deploy:finish' task...


Finished 'deploy:finish' after 222 μs


Finished 'deploy' [ deploy:init, deploy:fetch, deploy:update, deploy:publish, deploy:clean, deploy:finish ]

Чтобы просмотреть ваше приложение как посетитель, вы можете ввести URL своего веб-сайта в браузере. Так вы получите доступ к вашему серверу web. Он будет обслуживать приложение Node.js через обратный прокси-сервер на сервере app, на котором были развернуты ваши файлы.

Вы увидите на экране приветствие Hello World.

Примечание: После первого развертывания ваш репозиторий Git будет отслеживать только что созданный файл ecosystem.config.js. Поскольку этот файл будет перестраиваться при каждом развертывании и может содержать секреты скомпилированного приложения, его следует добавить в файл .gitignore в корневом каталоге приложения на локальном компьютере до следующего коммита git:

. . .
# ecosystem.config
ecosystem.config.js

Итак, вы развернули свое приложение Node.js на сервере app. Если все работает, вы можете переходить к мониторингу процессов. Об этом мы поговорим во второй части этого мануала.

Tags: , , , ,

Добавить комментарий