One place for hosting & domains

      среде

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


      Автор выбрал фонд Electronic Frontier Foundation для получения пожертвований в рамках программы Write for DOnations.

      Введение

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

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

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

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

      Предварительные требования

      Перед началом выполнения этого обучающего руководства вам потребуется следующее:

      • Два сервера CentOS 7 (в этом обучающем руководстве мы будем использовать для них имена app и web) с настроенной частной сетью в соответствии с указаниями обучающего руководства Настройка приложения Node.js для производственной среды в CentOS 7.
      • Веб-сервер Nginx (на сервере web), защищенный протоколами TLS/SSL, как описано в обучающем руководстве Защита Nginx с помощью Let’s Encrypt в CentOS 7. Если вы выполните предварительные требования в хронологическом порядке, вам нужно будет только выполнить шаги 1, 4 и 6 на сервере web.
      • Установка Node.js и npm в производственной среде. В этом обучающем руководстве используется версия 10.17.0. Чтобы установить его в macOS или Ubuntu 18.04, следуйте указаниям руководства Установка Node.js и создание локальной среды разработки в macOS или раздела Установка с помощью PPA руководства Установка Node.js в Ubuntu 18.04. При установке Node.js также выполняется установка npm, в этом обучающем руководстве используется версия 6.11.3.
      • Локальный компьютер для разработки с установленными rsync и git.
        • В macOS вы можете использовать для их установки Homebrew.
        • Инструкции по установке git на дистрибутивах Linux содержатся в обучающем руководстве Установка Git.
      • Учетная запись на GitHub или другой системе хостинга служб git. В этом обучающем руководстве мы будем использовать GitHub.

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

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

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

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

      Github-new-repository

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

      Github-repository-name

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

      Github-repository-description

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

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

      Github-gitignore-node

      Нажмите кнопку 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, вы должны использовать персональный токен доступа или ключ SSH вместо пароля при доступе к Github из командной строки. Дополнительную информацию можно найти на странице справки Github по двухфакторной аутентификации.

      Результат будет выглядеть примерно так:

      Output

      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 для управления репозиторием. Вы можете проверить это с помощью следующей команды:

      Результат будет выглядеть примерно так:

      Output

      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

      Мы настроили рабочий репозиторий git и теперь можем создать файл shipit.js для управления процессом развертывания.

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

      На этом шаге вы создадите образец проекта Node.js, а затем добавите пакеты Shipit. В этом обучающем руководстве приведен пример приложения — сервер Node.js web принимает запросы HTTP и отвечает на них текстовым сообщением Hello World. Для создания приложения запустите следующую команду:

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

      hello.js

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

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

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

      Output

      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 требуются только на локальном компьютере. Результат будет выглядеть примерно так:

      Output

      + 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 три пакета как зависимости разработки:

      package.json

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

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

      Шаг 3 — Подготовка удаленного сервера App

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

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

      Примечание. После выполнения обучающего руководства Настройка приложения Node.js для производственной среды в CentOS 7 у нас осталось два сервера, app и web. Эти команды следует выполнять только на сервере app.

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

      • ssh deployer@your_app_server_ip

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

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

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

      Output

      rsync version 3.1.2 protocol version 31 . . .

      Вы можете завершить сеанс ssh с помощью команды exit.

      Мы установили rsync и сделали эту утилиту доступной в командной строке. Теперь мы можем перейти к задачам развертывания и их связи с событиями.

      Шаг 4 — Настройка и выполнение задач по развертыванию

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

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

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

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

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

      Добавьте эту начальную конфигурацию, изменив выделенные сроки в соответствии с параметрами вашей среды:

      shipitfile.js

      module.exports = shipit => {
        require('shipit-deploy')(shipit);
        require('shipit-shared')(shipit);
      
        const appName = 'hello';
      
        shipit.initConfig({
          default: {
            deployTo: '/home/sammy/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: 'sammy@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
      
      };
      

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

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

      Дополнительную информацию по объекту Shipit Deploy Configuration можно найти в репозитории Shipit на Github.

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

      Example event listener

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

      Это пример задачи, где метод shipit.on используется для подписки на событие deploy. Данная задача ожидает события deploy в жизненном цикле Shipit, а после получения этого события задача выполняет метод shipit.start, предписывающий Shipit запустить задачу 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. Добавьте модули прослушивания событий в файл shipitfile.js, вставьте их после замещающего текста комментария в первоначальной конфигурации // Our tasks will go here:

      shipitfile.js

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

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

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

      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:

      shipitfile.js

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

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

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

      shipitfile.js

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

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

      Полный файл shipitfile.js:

      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. Ваши файлы не отслеживаются и выделяются красным цветом в выводимых результатах:

      Output

      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 status, файлы будут помечены зеленым цветом с отметкой, что имеются изменения для записи.

      Для записи изменений используется следующая команда:

      • git commit -m "Our first commit"

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

      Output

      [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 во время развертывания. Запустите следующую команду:

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

      Output

      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 запущено:

      Output

      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-адрес вашего сайта your-domain в браузере, чтобы получить доступ к серверу web. Приложение Node.js будет обслуживаться через обратный прокси-сервер на сервере app, где развернуты ваши файлы.

      Вы увидите приветствие Hello World.

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

      .gitignore

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

      Мы развернули приложение Node.js на сервере app, проведя новую операцию развертывания. Теперь все работает, и мы можем переходить к мониторингу процессов вашего приложения.

      Шаг 6 — Мониторинг приложения

      PM2 — отличный инструмент для управления удаленными процессами, который также поддерживает мониторинг производительности этих процессов.

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

      • ssh deployer@your_app_server_ip

      Для получения конкретной информации по управляемым процессам PM2 используйте следующую команду:

      Результат будет выглядеть примерно так:

      Output

      ┌─────────────┬────┬─────────┬──────┬──────┬────────┬─────────┬────────┬──────┬───────────┬──────────┬──────────┐ │ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├─────────────┼────┼─────────┼──────┼──────┼────────┼─────────┼────────┼──────┼───────────┼──────────┼──────────┤ │ hello │ 0 │ 0.0.1 │ fork │ 3212 │ online │ 0 │ 62m │ 0.3% │ 45.2 MB │ deployer │ enabled │ └─────────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴──────┴───────────┴──────────┴──────────┘

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

      В результатах раскрывается сводная информация, предоставляемая командой pm2 list. Также предоставляется информация по ряду вспомогательных команд и сведения о расположении файла журнала:

      Output

      Describing process with id 0 - name hello ┌───────────────────┬─────────────────────────────────────────────────────────────┐ │ status │ online │ │ name │ hello │ │ version │ 1.0.0 │ │ restarts │ 0 │ │ uptime │ 82s │ │ script path │ /home/deployer/example.com/releases/20190531213027/hello.js │ │ script args │ N/A │ │ error log path │ /home/deployer/.pm2/logs/hello-error.log │ │ out log path │ /home/deployer/.pm2/logs/hello-out.log │ │ pid path │ /home/deployer/.pm2/pids/hello-0.pid │ │ interpreter │ node │ │ interpreter args │ N/A │ │ script id │ 0 │ │ exec cwd │ /home/deployer │ │ exec mode │ fork_mode │ │ node.js version │ 4.2.3 │ │ node env │ production │ │ watch & reload │ ✔ │ │ unstable restarts │ 0 │ │ created at │ 2019-05-31T21:30:48.334Z │ └───────────────────┴─────────────────────────────────────────────────────────────┘ Revision control metadata ┌──────────────────┬────────────────────────────────────────────────────┐ │ revision control │ git │ │ remote url │ N/A │ │ repository root │ /home/deployer/example.com/releases/20190531213027 │ │ last update │ 2019-05-31T21:30:48.559Z │ │ revision │ 62fba7c8c61c7769022484d0bfa46e756fac8099 │ │ comment │ Our first commit │ │ branch │ master │ └──────────────────┴────────────────────────────────────────────────────┘ Divergent env variables from local env ┌───────────────────────────┬───────────────────────────────────────┐ │ XDG_SESSION_ID │ 15 │ │ HOSTNAME │ N/A │ │ SELINUX_ROLE_REQUESTED │ │ │ TERM │ N/A │ │ HISTSIZE │ N/A │ │ SSH_CLIENT │ 44.222.77.111 58545 22 │ │ SELINUX_USE_CURRENT_RANGE │ │ │ SSH_TTY │ N/A │ │ LS_COLORS │ N/A │ │ MAIL │ /var/mail/deployer │ │ PATH │ /usr/local/bin:/usr/bin │ │ SELINUX_LEVEL_REQUESTED │ │ │ HISTCONTROL │ N/A │ │ SSH_CONNECTION │ 44.222.77.111 58545 209.97.167.252 22 │ └───────────────────────────┴───────────────────────────────────────┘ . . .

      PM2 также предоставляет инструмент для мониторинга через терминал:

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

      Output

      ┌─ Process list ────────────────┐┌─ Global Logs ─────────────────────────────────────────────────────────────┐ │[ 0] hello Mem: 22 MB ││ │ │ ││ │ │ ││ │ └───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘ ┌─ Custom metrics (http://bit.l─┐┌─ Metadata ────────────────────────────────────────────────────────────────┐ │ Heap Size 10.73 ││ App Name hello │ │ Heap Usage 66.14 ││ Version N/A │ │ Used Heap Size 7.10 ││ Restarts 0 │ │ Active requests 0 ││ Uptime 55s │ │ Active handles 4 ││ Script path /home/asciant/hello.js │ │ Event Loop Latency 0.70 ││ Script args N/A │ │ Event Loop Latency p95 ││ Interpreter node │ │ ││ Interpreter args N/A │ └───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘

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

      Закройте сеанс ssh на сервере app с помощью команды exit.

      Шаг 7 — Откат при ошибках развертывания

      Иногда при развертывании могут возникнуть непредвиденные ошибки или проблемы, из-за которых сайт выходит из строя. Команда по разработке и обслуживанию Shipit предвидела эту ситуацию и поэтому предлагает возможность отката к предыдущей (работающей) версии вашего приложения.

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

      shipitfile.js

      . . .
        shipit.on('rollback', () => {
          shipit.start('npm-install', 'copy-config');
        });
      

      Модуль прослушивания событий для события rollback добавляется для запуска заданий npm-install и copy-config. Это необходимо, т. к. в отличие от опубликованного события, обновленное событие не запускается в рабочем цикле Shipit при откате развертывания. При добавлении этого модуля прослушивания событий ваш диспетчер процессов PM2 указывает на последнюю развернутую версию, даже если был произведен откат.

      Этот процесс аналогичен развертыванию, есть лишь небольшое отличие в синтаксисе команд. Попробуйте выполнить откат к предыдущей развернутой версии с помощью следующей команды:

      • npx shipit production rollback

      Как и команда deploy, команда rollback предоставляет детальную информацию по процессу отката и выполняемым задачам:

      Output

      Running 'rollback:init' task... Get current release dirname. Running "if [ -h /home/deployer/example.com/current ]; then readlink /home/deployer/example.com/current; fi" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com releases/20190531213719 Current release dirname : 20190531213719. Getting dist releases. Running "ls -r1 /home/deployer/example.com/releases" on host "centos-ap-app.asciant.com". @centos-ap-app.asciant.com 20190531213719 @centos-ap-app.asciant.com 20190531213519 @centos-ap-app.asciant.com 20190531213027 Dist releases : ["20190531213719","20190531213519","20190531213027"]. Will rollback to 20190531213519. Finished 'rollback:init' after 3.96 s Running 'deploy:publish' task... Publishing release "/home/deployer/example.com/releases/20190531213519" Running "cd /home/deployer/example.com && if [ -d current ] && [ ! -L current ]; then echo "ERR: could not make symlink"; else ln -nfs releases/20190531213519 current_tmp && mv -fT current_tmp current; fi" on host "centos-ap-app.asciant.com". Release published. Finished 'deploy:publish' after 1.8 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 │ 4289 │ 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.55 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.82 s Running 'rollback:finish' task... Finished 'rollback:finish' after 615 μs Finished 'rollback' [ rollback:init, deploy:publish, deploy:clean, rollback:finish ]

      Вы настроили Shipit для сохранения 5 выпусков с помощью параметра конфигурации keepReleases: 5 в shipitfile.js. Shipit обеспечивает внутреннее отслеживание этих выпусков,чтобы обеспечить возможность отката в случае необходимости. Также Shipit обеспечивает удобную возможность идентификации выпусков посредством создания директории с временной меткой в составе имени (YYYYMMDDHHmmss — пример: /home/deployer/your-domain/releases/20190420210548).

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

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

      Заключение

      В этом обучающем руководстве мы научились настраивать рабочий процесс, позволяющий создать настраиваемую альтернативу модели «платформа как услуга» с использованием всего двух серверов. Этот рабочий процесс поддерживает персонализацию развертывания и настроек, мониторинг процессов с помощью PM2, возможность масштабирования и добавления служб, дополнительных серверов или сред, если возникнет такая необходимость.

      Если вы хотите продолжить развивать свои навыки Node.js, ознакомьтесь с материалами DigitalOcean по Node.js и с серией материалов по программированию на Node.js.



      Source link

      Настройка приложения Node.js для работы в среде Ubuntu 18.04


      Введение

      Node.js — среда исполнения JavaScript с открытым исходным кодом, предназначенная для построения серверных и сетевых приложений. Данная платформа работает в операционных системах Linux, macOS, FreeBSD и Windows. Хотя вы можете запускать приложения Node.js через командную строку, этот обучающий модуль посвящен их запуску в качестве службы. Это означает, что они будут перезапускаться при перезагрузке системы или неисправности, и что их можно безопасно использовать в производственной среде.

      В этом обучающем модуле вы научитесь создавать готовую производственную среду Node.js на одном сервере Ubuntu 18.04. Этот сервер будет выполнять приложение Node.js под управлением PM2 и предоставлять пользователям безопасный доступ к приложению через обратный прокси-сервер Nginx. Сервер Nginx обеспечивает поддержку HTTPS с использованием бесплатного сертификата от Let’s Encrypt.

      Предварительные требования

      Этот обучающий модуль предполагает, что у вас имеется следующее:

      Если предварительные требования выполнены, у вас должен быть сервер, обслуживающий используемую по умолчанию страницу назначения вашего домена по адресу https://example.com/.

      Шаг 1 — Установка Node.js

      Для начала мы установим самый быстрый выпуск LTS Node.js, используя архивы пакетов NodeSource.

      Вначале мы установим NodeSource PPA, чтобы получить доступ к его содержимому. Перейдите в каталог home и используйте curl для получения скрипта установки архивов Node.js 8.x:

      • cd ~
      • curl -sL https://deb.nodesource.com/setup_8.x -o nodesource_setup.sh

      Вы можете просмотреть содержимое скрипта с помощью nano или предпочитаемого текстового редактора:

      Завершив проверку скрипта, запустите его от имени пользователя sudo:

      • sudo bash nodesource_setup.sh

      Архив PPA будет добавлен в вашу конфигурацию и кэш локальных пакетов автоматически обновится. После запуска скрипта установки Nodesource вы можете установить пакет Node.js:

      Чтобы проверить номер версии Node.js, установленной на начальном шаге, введите:

      Output

      v8.11.3

      Примечание. При установке из NodeSource PPA исполняемый файл Node.js имеет имя nodejs, а не node.

      Пакет nodejs содержит двоичный файл nodejs, а также диспетчер пакетов npm для модулей Node, так что отдельно устанавливать npm не нужно.

      npm использует файл конфигурации в домашнем каталоге, чтобы отслеживать обновления. Он создается при первом запуске npm. Выполните следующую команду, чтобы проверить установку npm и создать файл конфигурации:

      Output

      5.6.0

      Для работы некоторых пакетов npm (например, требующих компиляцию кода из источника) потребуется установить пакет build-essential:

      • sudo apt install build-essential

      Теперь у вас есть необходимые инструменты для работы с пакетами npm, которые требуют компиляции кода из источника.

      Установив исполняемый модуль Node.js, мы можем перейти к написанию приложения Node.js.

      Шаг 2 — Создание приложения Node.js

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

      Вначале создадим образец приложения под именем hello.js:

      Вставьте в файл следующий код:

      ~/hello.js

      const http = require('http');
      
      const hostname = 'localhost';
      const port = 3000;
      
      const server = http.createServer((req, res) => {
        res.statusCode = 200;
        res.setHeader('Content-Type', 'text/plain');
        res.end('Hello World!n');
      });
      
      server.listen(port, hostname, () => {
        console.log(`Server running at http://${hostname}:${port}/`);
      });
      

      Сохраните файл и выйдите из редактора.

      Это приложение Node.js прослушивает заданный адрес (localhost) и порт (3000) и возвращает текст «Hello World!» с кодом успешного выполнения a 200 HTTP. Поскольку мы прослушиваем localhost, удаленные клиенты не смогут подключиться к нашему приложению.

      Чтобы протестировать приложение, введите:

      Результат будет выглядеть следующим образом:

      Output

      Server running at http://localhost:3000/

      Примечание. Такой способ запуска приложения Node.js блокирует дополнительные команды, пока приложение не будет закрыто нажатием CTRL+C.

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

      • curl http://localhost:3000

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

      Output

      Hello World!

      Если вы не видите ожидаемого результата, убедитесь, что ваше приложение Node.js запущено и настроено для прослушивание правильных адреса и порта.

      Убедившись, что приложение работает, остановите его (если еще не сделали этого) нажатием CTRL+C.

      Шаг 3 — Установка PM2

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

      Используйте npm для установки последней версии PM2 на своем сервере:

      • sudo npm install pm2@latest -g

      Опция -g указывает npm выполнить глобальную установку модуля, чтобы он был доступен в масштабе всей системы.

      Вначале используем команду pm2 для запуска вашего приложения hello.js в фоновом режиме:

      Также она добавит ваше приложение в список процессов PM2, которы йвыводится при каждом запуске приложения:

      Output

      [PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/hello.js in fork_mode (1 instance) [PM2] Done. ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬───────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼───────┼──────────┤ │ hello │ 0 │ fork │ 1338 │ online │ 0 │ 0s │ 0% │ 23.0 MB │ sammy │ disabled │ └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴───────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app

      Как видите, PM2 автоматически назначает App name (по имени файла, без расширения .js и идентификатор PM2 id. PM2 также обслуживает и другие данные, в том числе PID процесса, данные о текущем состоянии и использовании памяти.

      Приложения, запускаемые через PM2, автоматически перезапускаются в случае сбоя или прекращения работы приложения, но мы можем выполнить дополнительный шаг, чтобы запускать приложение при запуске системы с помощью субкоманды startup. Эта субкоманда генерирует и настраивает скрипт запуска PM2 и управляемых им процессов при загрузке сервера:

      Последняя строка результатов содержит команду, которую нужно запустить с привилегиями суперпользователя для настройки запуска PM2 при загрузке:

      Output

      [PM2] Init System found: systemd [PM2] To setup the Startup Script, copy/paste the following command: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      Запустите команду из результатов, указав свое имя пользователя вместо sammy:

      • sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

      Дополнительно мы можем сохранить список процессов PM2 и соответствующие среды:

      Теперь вы создали блок systemd, который запускает pm2 для вашего пользователя при загрузке. Этот экземпляр pm2 запускает hello.js.

      Запустите службу с помощью команды systemctl:

      • sudo systemctl start pm2-sammy

      Проверьте состояние блока systemd:

      • systemctl status pm2-sammy

      Подробный обзор systemd можно найти в документе «Основы работы с Systemd: работа со службами, блоками и журналом».

      В дополнение к уже описанным субкомандам PM2 предоставляет много субкоманд, позволяющих управлять информацией о ваших приложениях и искать такую информацию.

      Остановите приложение с помощью этой команды (укажите имя приложения PM2 или id):

      Перезапустите приложение:

      • pm2 restart app_name_or_id

      Выведем список приложений, управление которыми осуществляет PM2:

      Получим информацию об определенном приложении по App name:

      Монитор процесса PM2 запускается с помощью субкоманды monit. При этом отображается состояние приложение, использование ресурсов ЦП и использование памяти:

      При запуске команды pm2 без аргументов отображается страница справки с примерами использования.

      Теперь ваше приложение Node.js запущено и управляется PM2, и мы можем настроить обратный прокси-сервер.

      Шаг 4 — Настройка Nginx в качестве обратного прокси-сервера

      Ваше приложение запущено и прослушивает localhost, но вам нужно дать пользователям возможность доступа к нему. Для этой цели мы настроим веб-сервер Nginx в качестве обратного прокси-сервера.

      В предварительных обучающих модулях вы настроили конфигурацию Nginx в файле /etc/nginx/sites-available/example.com. Откройте этот файл для редактирования:

      • sudo nano /etc/nginx/sites-available/example.com

      В блоке server должен содержаться блок location /. Замените содержимое этого блока следующей конфигурацией. Если ваше приложение настроено для прослушивания другого порта, измените номер порта в выделенной части на подходящий:

      /etc/nginx/sites-available/example.com

      server {
      ...
          location / {
              proxy_pass http://localhost:3000;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      Так сервер настраивается для ответа на запросы root. Если наш сервер доступен по адресу example.com, при попытке доступа к https://example.com/ через браузер будет отправлен запрос hello.js с прослушиванием порта 3000 хоста localhost.

      Вы можете добавить в этот же серверный блок дополнительные блоки location, чтобы предоставить другим приложениям доступ к этому же серверу. Например, если вы используете другое приложение Node.js на порту 3001, вы сможете добавить следующий блок location, чтобы разрешить доступ к нему через https://example.com/app2:

      /etc/nginx/sites-available/example.com — Optional

      server {
      ...
          location /app2 {
              proxy_pass http://localhost:3001;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection 'upgrade';
              proxy_set_header Host $host;
              proxy_cache_bypass $http_upgrade;
          }
      ...
      }
      

      Завершив добавление блоков location для ваших приложений, сохраните файл и закройте редактор.

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

      Перезапустите Nginx:

      • sudo systemctl restart nginx

      Если ваше приложение Node.js запущено и конфигурации вашего приложения и Nginx настроены правильно, вы должны иметь возможность доступа к вашему приложению через обратный прокси-сервер Nginx. Попробуйте открыть URL вашего сервера (публичный IP-адрес или доменное имя).

      Заключение

      Поздравляем! Теперь у вас есть приложение Node.js, работающее за обратным прокси-сервером Nginx на сервере Ubuntu 18.04. Настройка обратного прокси-сервера достаточно гибкая, чтобы предоставить вашим пользователям доступ к другим приложениям или статическому веб-контенту, который вы хотите опубликовать.



      Source link