如何在CentOS7上使用Shipit自动化Node.js生产部署
作为 Write for DOnations 计划的一部分,作者选择了 Electronic Frontier Foundation 来接受捐赠。
介绍
Shipit 是 Node.js 开发人员的通用自动化和部署工具。 它具有基于流行的 Orchestrator 包的任务流、通过 OpenSSH 的登录和交互式 SSH 命令以及可扩展的 API。 开发人员可以使用 Shipit 为各种 Node.js 应用程序自动构建和部署工作流。
Shipit 工作流程允许开发人员不仅可以配置任务,还可以指定它们的执行顺序; 它们是应该同步运行还是异步运行以及在哪个环境中运行。
在本教程中,您将安装和配置 Shipit 以将 Node.js 应用程序从本地开发环境部署到生产环境。 您将使用 Shipit 部署您的应用程序并通过以下方式配置远程服务器:
- 将 Node.js 应用程序的文件从本地环境传输到生产环境(使用
rsync
、git
和ssh
)。 - 安装应用程序的依赖项(节点模块)。
- 使用 PM2 配置和管理在远程服务器上运行的 Node.js 进程。
先决条件
在开始本教程之前,您需要以下内容:
- 两台 CentOS 7 服务器(在本教程中它们将被命名为 app 和 web)按照 How To Set Up a Node.js Application for Production on CentOS 7 教程。
- Nginx(在您的 web 服务器上)使用 TLS/SSL 进行保护,如 如何在 CentOS 7 上使用 Let's Encrypt 保护 Nginx 教程。 请注意,如果您按时间顺序遵循先决条件,则只需在 web 服务器上完成步骤 1、4 和 6。
- Node.js 和 npm 安装在您的开发环境中。 本教程使用版本 10.17.0。 要在 macOS 或 Ubuntu 18.04 上安装它,请按照 如何在 macOS 上安装 Node.js 和创建本地开发环境中的步骤或 的 使用 PPA 部分安装如何在 Ubuntu 18.04 上安装 Node.js。 通过安装 Node.js,您还将安装 npm; 本教程使用版本 6.11.3。
- 安装了
rsync
和git
的本地开发计算机。 在 macOS 上,您可以使用 Homebrew 安装它们。 要在 Linux 发行版上安装 git,请遵循如何安装 Git 教程。 - GitHub 或其他托管
git
服务提供商的帐户。 本教程将使用 GitHub。
注意: Windows 用户需要安装 Windows Subsystem for Linux 才能执行本指南中的命令。
第 1 步 — 设置远程存储库
Shipit 需要一个 Git 存储库来在本地开发机器和远程服务器之间进行同步。 在这一步中,您将在 Github.com
上创建一个远程存储库。 虽然每个提供者略有不同,但命令在某种程度上是可转移的。
要创建存储库,请在 Web 浏览器中打开 Github.com
并登录。 您会注意到在任何页面的右上角都有一个 + 符号。 点击【X6X】+【X11X】,然后点击【X33X】新建仓库【X51X】。
为您的存储库键入一个简短易记的名称,例如 hello-world
。 请注意,您在此处选择的任何名称都将被复制为您将在本地计算机上使用的项目文件夹。
(可选)添加存储库的描述。
将存储库的可见性设置为您的偏好,公共或私有。
确保使用 .gitignore
初始化存储库,从 Add .gitignore
下拉列表中选择 Node
。 此步骤对于避免将不必要的文件(如 node_modules
文件夹)添加到您的存储库非常重要。
单击创建存储库按钮。
现在需要将存储库从 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 用户名和之前提供的存储库名称。
注意:如果您在Github.com
上启用了双因素认证(2FA),在命令行访问Github时必须使用个人访问令牌或SSH密钥代替密码。 与 2FA 相关的 Github 帮助页面提供了 更多信息。
您将看到类似于以下内容的输出:
OutputCloning 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
您将看到类似于以下内容的输出:
Outputtotal 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
。 要创建应用程序,请运行以下命令:
nano hello.js
将以下示例应用程序代码添加到 hello.js
(将 APP_PRIVATE_IP_ADDRESS
变量更新为 app 服务器的专用网络 IP 地址):
你好.js
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
命令行界面向此文件添加依赖项。
OutputWrote 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
文件中作为开发依赖项:
包.json
. . . "devDependencies": { "shipit-cli": "^4.2.0", "shipit-deploy": "^4.1.4", "shipit-shared": "^4.4.2" }, . . .
配置好本地环境后,您现在可以继续为基于 Shipit 的部署准备远程 app 服务器。
第 3 步 — 准备远程应用服务器
在这一步中,您将使用 ssh
连接到 app 服务器并安装远程依赖项 rsync
。 Rsync 是一个实用程序,用于通过比较文件的修改时间和大小,在本地计算机驱动器和联网计算机之间有效地传输和同步文件。
Shipit 使用 rsync
在本地计算机和远程 app 服务器之间传输和同步文件。 您不会直接向 rsync
发出任何命令; Shipit 将为您处理。
笔记: 如何在 CentOS 7 上设置用于生产的 Node.js 应用程序 left you with two servers 应用程序 and 网络. These commands should be executed on 应用程序 only.
通过 ssh
连接到远程 app 服务器:
ssh deployer@your_app_server_ip
通过运行以下命令在您的服务器上安装 rsync
:
sudo yum install rsync
确认安装:
rsync --version
您将在此命令的输出中看到类似的行:
Outputrsync version 3.1.2 protocol version 31 . . .
您可以通过键入 exit
来结束 ssh
会话。
安装 rsync
并在命令行上可用后,您可以继续部署任务及其与事件的关系。
第 4 步 — 配置和执行部署任务
events 和 tasks 都是 Shipit 部署的关键组件,了解它们如何补充您的应用程序部署非常重要。 Shipit 触发的事件代表了部署生命周期中的特定点。 您的任务将根据 Shipit 生命周期的顺序执行以响应这些事件。
此任务/事件系统在 Node.js 应用程序中有用的一个常见示例是在远程服务器上安装应用程序的依赖项 (node_modules
)。 在此步骤的后面,您将让 Shipit 侦听 updated
事件(在应用程序文件传输后发出)并运行任务以在远程安装应用程序的依赖项(npm install
)服务器。
要监听事件和执行任务,Shipit 需要一个配置文件,其中包含有关远程服务器(app 服务器)的信息,并注册事件监听器和这些任务要执行的命令。 该文件位于您的本地开发计算机上,位于您的 Node.js 应用程序目录中。
首先,创建此文件,包括有关远程服务器的信息、要订阅的事件侦听器以及任务的一些定义。 通过运行以下命令,在本地计算机上的应用程序根目录中创建 shipitfile.js
:
nano shipitfile.js
现在您已经创建了一个文件,需要使用 Shipit 所需的初始环境信息来填充它。 这主要是您的远程 Git
存储库的位置,重要的是,您的 app 服务器的公共 IP 地址和 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 };
在 shipit.initConfig
方法中更新 variables 可为 Shipit 提供特定于您的部署的配置。 这些代表 Shipit 的以下内容:
deployTo:
是 Shipit 将您的应用程序代码部署到远程服务器上的目录。 在这里,您将/home/
文件夹用于具有sudo
权限 (/home/sammy
) 的非 root 用户,因为它是安全的,并且可以避免权限问题。/your-domain
组件是一种命名约定,用于将文件夹与用户主文件夹中的其他文件夹区分开来。repositoryUrl:
是完整 Git 存储库的 URL,Shipit 将使用此 URL 来确保项目文件在部署之前同步。keepReleases:
是要保留在远程服务器上的版本数。release
是一个带有日期戳的文件夹,其中包含您的应用程序在发布时的文件。 这些对于部署的rollback
很有用。shared:
是对应于keepReleases
的配置,允许目录在版本之间为shared
。 在本例中,我们有一个在所有版本之间共享的node_modules
文件夹。production:
代表将应用程序部署到的远程服务器。 在这种情况下,您有一个名为production
的服务器(app 服务器),其中servers:
配置与您的 SSHuser
和public ip address
。 名称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 生命周期发出 deploy
事件,然后当接收到事件时,任务执行 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.on
订阅 Shipit 生命周期。 将事件侦听器添加到您的 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'); });
这两种方法正在侦听作为 Shipit 部署生命周期的一部分发出的 updated
和 published
事件。 当收到事件时,它们将各自使用 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
提供必要的文件路径信息,以确保它正在运行您最新部署的文件。 稍后在构建过程中,您将创建一个以 ecosystem.config.js
作为配置运行 PM2
的任务。
如果您的应用程序需要环境变量(如数据库连接字符串),您可以在 env:
中本地或在 env_production:
中的远程服务器上声明它们,方式与设置 [ X210X] 这些对象中的变量。
在 copy-config
任务之后将下一个任务添加到 shipitfile.js
中:
shipitfile.js
. . . shipit.blTask('npm-install', async () => { shipit.remote(`cd ${shipit.releasePath} && npm install --production`); });
接下来,您声明一个名为 npm-install
的任务。 此任务使用远程 bash 终端(通过 shipit.remote
)安装应用程序的依赖项(npm
包)。
在 npm-install
任务之后将最后一个任务添加到 shipitfile.js
中:
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
的任务。 此任务还使用远程 bash 终端首先阻止 PM2
通过 delete
命令管理您以前的部署,然后启动 Node.js 服务器的新实例,提供 [X207X ] 文件作为变量。 您还让 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 步 — 部署您的应用程序
在此步骤中,您将远程部署应用程序并测试部署是否使您的应用程序可用于 Internet。
因为 Shipit 从远程 Git 存储库克隆项目文件,所以您需要将本地 Node.js 应用程序文件从本地机器推送到 Github。 导航到 Node.js 项目的应用程序目录(您的 hello.js
和 shiptitfile.js
所在的位置)并运行以下命令:
git status
git status
命令显示工作目录和暂存区的状态。 它可以让您查看哪些更改已暂存,哪些尚未暂存,以及 Git 未跟踪哪些文件。 您的文件未跟踪并在输出中显示为红色:
OutputOn 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 的信息。
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 服务器。 运行以下命令:
git push origin master
输出包括有关与远程存储库同步的信息:
OutputEnumerating 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 应用程序已启动:
OutputRunning '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 服务器。 这将通过反向代理在部署文件的 app 服务器上为 Node.js 应用程序提供服务。
您将看到 Hello World 问候语。
注意: 首次部署后,您的 Git 存储库将跟踪一个名为 ecosystem.config.js
的新创建文件。 由于此文件将在每次部署时重新构建,并且可能包含已编译的应用程序机密,因此应在下一次 git
提交之前将其添加到本地计算机上应用程序根目录中的 .gitignore
文件中。
.gitignore
. . . # ecosystem.config ecosystem.config.js
您已将 Node.js 应用程序部署到您的 app 服务器,这指的是您的新部署。 随着一切都启动并运行,您可以继续监控您的应用程序进程。
第 6 步 — 监控您的应用程序
PM2 是管理远程进程的绝佳工具,但它还提供了监控这些应用程序进程性能的功能。
使用以下命令通过 SSH 连接到远程 app 服务器:
ssh deployer@your_app_server_ip
要获取与您的 PM2 托管进程相关的特定信息,请运行以下命令:
pm2 list
您将看到类似于以下内容的输出:
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 show hello
输出扩展了 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 monit
该命令的输出是一个交互式仪表板,其中 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 如何帮助回滚到以前的工作部署。
通过运行 exit
结束 app 服务器上的 ssh
会话。
第 7 步 — 回滚错误的部署
部署有时会暴露无法预料的错误或导致站点失败的问题。 Shipit 的开发人员和维护人员已经预料到了这一点,并为您提供了回滚到应用程序先前(工作)部署的能力。
为确保您的 PM2
配置持续存在,请在 rollback
事件的 shipitfile.js
中添加另一个事件侦听器:
shipitfile.js
. . . shipit.on('rollback', () => { shipit.start('npm-install', 'copy-config'); });
您将侦听器添加到 rollback
事件以运行 npm-install
和 copy-config
任务。 这是必需的,因为与 published
事件不同,在回滚部署时,Shipit 生命周期不会运行 updated
事件。 添加此事件侦听器可确保您的 PM2
流程管理器指向最近的部署,即使在回滚的情况下也是如此。
此过程类似于部署,只是对命令稍作更改。 要尝试回滚到以前的部署,您可以执行以下操作:
npx shipit production rollback
与 deploy
命令一样,rollback
提供有关回滚过程和正在执行的任务的详细信息:
OutputRunning '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 ]
您已通过 shipitfile.js
中的 keepReleases: 5
配置将 Shipit 配置为保留 5 个版本。 Shipit 在内部跟踪这些版本,以确保它能够在需要时回滚。 Shipit 还提供了一种方便的方法来识别版本,方法是创建一个名为时间戳的目录(YYYYMMDDHHmmss - 示例:/home/deployer/your-domain/releases/20190420210548
)。
如果您想进一步自定义回滚过程,您可以侦听特定于回滚操作的事件。 然后,您可以使用这些事件来执行将补充您的回滚的任务。 您可以参考 Shipit 生命周期 的 细分中提供的事件列表,并在 shipitfile.js
中配置任务/侦听器。
回滚能力意味着即使部署引入了意外的错误/问题,您也可以始终向用户提供应用程序的正常运行版本。
结论
在本教程中,您配置了一个工作流,允许您创建高度可定制的平台即服务替代方案,所有这些都来自几个服务器。 此工作流程允许自定义部署和配置、使用 PM2 进行流程监控、扩展和添加服务的潜力,或者在需要时为部署添加额外的服务器或环境。
如果您有兴趣继续发展您的 Node.js 技能,请查看 DigitalOcean Node.js 内容 以及 如何在 Node.js 系列中编码 。