The author selected the Electronic Frontier Foundation to receive a donation as part of the Write for DOnations program.
作者选择了电子前沿基金会来接受捐款,这是Write for DOnations计划的一部分。
Shipit is a universal automation and deployment tool for Node.js developers. It features a task flow based on the popular Orchestrator package, login and interactive SSH commands through OpenSSH, and an extensible API. Developers can use Shipit to automate build and deployment workflows for a wide range of Node.js applications.
Shipit是面向Node.js开发人员的通用自动化和部署工具。 它具有基于流行的Orchestrator软件包的任务流,通过OpenSSH登录和交互SSH命令以及可扩展的API。 开发人员可以使用Shipit自动化各种Node.js应用程序的构建和部署工作流。
The Shipit workflow allows developers to not only configure tasks, but also to specify the order in which they are executed; whether they should be run synchronously or asynchronously and on which environment.
通过Shipit工作流,开发人员不仅可以配置任务,还可以指定执行顺序。 它们应在哪个环境上同步或异步运行。
In this tutorial you will install and configure Shipit to deploy a Node.js application from your local development environment to your production environment. You’ll use Shipit to deploy your application and configure the remote server by:
在本教程中,您将安装并配置Shipit,以将Node.js应用程序从本地开发环境部署到生产环境。 您将使用Shipit通过以下方式部署应用程序并配置远程服务器:
transferring your Node.js application’s files from your local environment to the production environment (using rsync
, git
, and ssh
).
将Node.js应用程序的文件从本地环境传输到生产环境(使用rsync
, git
和ssh
)。
configuring and managing the Node.js processes running on the remote server with PM2.
使用PM2配置和管理在远程服务器上运行的Node.js进程。
Before you begin this tutorial you’ll need the following:
在开始本教程之前,您需要满足以下条件:
Two CentOS 7 servers (in this tutorial they will be named app and web) configured with private networking by following the How To Set Up a Node.js Application for Production on CentOS 7 tutorial.
通过遵循如何在CentOS 7上设置生产环境的Node.js应用程序来配置两台使用专用网络配置的CentOS 7服务器(在本教程中,它们分别称为app和web )。
Nginx (on your web server) secured with TLS/SSL as shown in the How To Secure Nginx with Let’s Encrypt on CentOS 7 tutorial. Note, if you are following the prerequisites chronologically, then you only need to complete steps 1, 4, and 6 on your web server.
Nginx(在Web服务器上)已使用TLS / SSL进行了保护,如“ 如何在CentOS 7上使用Let's Encrypt来保护Nginx”教程中所示。 请注意,如果您按时间顺序遵循先决条件,则只需完成Web服务器上的步骤1、4和6。
Node.js and npm installed on your development environment. This tutorial uses version 10.17.0. To install this on macOS or Ubuntu 18.04, follow the steps in How To Install Node.js and Create a Local Development Environment on macOS or the Installing Using a PPA section of How To Install Node.js on Ubuntu 18.04. By having Node.js installed you will also have npm installed; this tutorial uses version 6.11.3.
在您的开发环境中安装了Node.js和npm。 本教程使用版本10.17.0。 要将其安装在macOS或Ubuntu 18.04上,请遵循如何在macOS上安装Node.js并创建本地开发环境中的步骤,或如何在Ubuntu 18.04上安装Node.js的 使用PPA安装部分中的步骤 。 通过安装Node.js,您还将安装npm。 本教程使用版本6.11.3。
On macOS you can install these with Homebrew.
在macOS上,您可以使用Homebrew安装它们。
To install git
on Linux distributions, follow the How To Install Git tutorial.
要在Linux发行版上安装git
,请遵循“ 如何安装Git”教程。
A local development computer with rsync
and git
installed.
安装了rsync
和git
本地开发计算机。
An account with GitHub or another hosted git
service provider. This tutorial will use GitHub.
具有GitHub或其他托管git
服务提供商的帐户。 本教程将使用GitHub。
Note: Windows users will need to install the Windows Subsystem for Linux to execute the commands in this guide.
注意: Windows用户将需要安装Linux的Windows子系统来执行本指南中的命令。
Shipit requires a Git repository to synchronize between the local development machine and the remote server. In this step you’ll create a remote repository on Github.com
. While each provider is slightly different the commands are somewhat transferrable.
Shipit需要一个Git存储库以在本地开发计算机和远程服务器之间进行同步。 在这一步中,您将在Github.com
上创建一个远程存储库。 尽管每个提供程序都略有不同,但是命令在一定程度上是可以转移的。
To create a repository, open Github.com
in your web browser and log in. You will notice that in the upper-right corner of any page there is a + symbol. Click +, and then click New repository.
要创建存储库, Github.com
在Web浏览器中打开Github.com
并登录。您会注意到,在任何页面的右上角都有一个+符号。 单击+ ,然后单击新建存储库 。
Type a short, memorable name for your repository, for example, hello-world
. Note that whatever name you choose here will be replicated as the project folder that you’ll work from on your local machine.
为您的存储库键入一个简短易记的名称,例如hello-world
。 请注意,您在此处选择的任何名称都将被复制为您将在本地计算机上使用的项目文件夹。
Optionally, add a description of your repository.
(可选)添加对存储库的描述。
Set your repository’s visibility to your preference, either public or private.
根据您的喜好将存储库的可见性设置为公共或私有。
Make sure the repository is initialized with a .gitignore
, select Node
from the Add .gitignore
dropdown list. This step is important to avoid having unnecessary files (like the node_modules
folder) being added to your repository.
确保使用.gitignore
初始化存储库,然后从Add .gitignore
下拉列表中选择Node
。 此步骤很重要,可以避免将不必要的文件(例如node_modules
文件夹)添加到存储库中。
Click the Create repository button.
单击创建存储库按钮。
The repository now needs to be cloned from Github.com
to your local machine.
现在需要将存储库从Github.com
到本地计算机。
Open your terminal and navigate to the location where you want to store all your Node.js project files. Note that this process will create a sub-folder within the current directory. To clone the repository to your local machine, run the following command:
打开终端,然后导航到要存储所有Node.js项目文件的位置。 请注意,此过程将在当前目录中创建一个子文件夹。 要将存储库克隆到本地计算机,请运行以下命令:
git clone https://github.com/your-github-username/your-github-repository-name.git
git clone https://github.com/ your-github-username / your-github-repository-name .git
You will need to replace your-github-username
and your-github-repository-name
to reflect your Github username and the previously supplied repository name.
您将需要替换your-github-username
和your-github-repository-name
以反映您的Github用户名和先前提供的存储库名称。
Note: If you have enabled two-factor authentication (2FA) on Github.com
, you must use a personal access token or SSH key instead of your password when accessing Github on the command line. The Github Help page related to 2FA provides further information.
注意:如果您已在Github.com
上启用了双重身份验证(2FA), Github.com
在通过命令行访问Github时,必须使用个人访问令牌或SSH密钥而不是密码。 与2FA相关的Github帮助页面提供了更多信息。
You’ll see output similar to:
您将看到类似于以下内容的输出:
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.
Move to the repository by running the following command:
通过运行以下命令移至存储库:
cd your-github-repository-name
cd your-github-repository-name
Inside the repository is a single file and folder, both of which are files used by Git to manage the repository. You can verify this with:
存储库内部是一个文件和文件夹,这两个文件都是Git用于管理存储库的文件。 您可以使用以下方法进行验证:
You’ll see output similar to the following:
您将看到类似于以下内容的输出:
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
Now that you have configured a working git
repository, you’ll create the shipit.js
file that manages your deployment process.
现在,您已经配置了一个可用的git
存储库,接下来,您将创建用于管理部署过程的shipit.js
文件。
In this step, you’ll create an example Node.js project and then add the Shipit packages. This tutorial provides an example app—the Node.js web server that accepts HTTP requests and responds with Hello World
in plain text. To create the application, run the following command:
在此步骤中,您将创建一个示例Node.js项目,然后添加Shipit包。 本教程提供了一个示例应用程序-Node.js Web服务器,它接受HTTP请求并以纯文本格式与Hello World
进行响应。 要创建该应用程序,请运行以下命令:
Add the following example application code to hello.js
(updating the APP_PRIVATE_IP_ADDRESS
variable to your app server’s private network IP address):
将以下示例应用程序代码添加到hello.js
(将APP_PRIVATE_IP_ADDRESS
变量更新为应用程序服务器的专用网络IP地址):
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/');
Now create your package.json
file for your application:
现在为您的应用程序创建package.json
文件:
This command creates a package.json
file, which you’ll use to configure your Node.js application. In the next step, you’ll add dependencies to this file with the npm
command line interface.
此命令创建一个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"
}
Next, install the necessary npm
packages with the following command:
接下来,使用以下命令安装必要的npm
软件包:
You use the --save-dev
flag here as the Shipit packages are only required on your local machine. You’ll see output similar to the following:
您在此处使用--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
This also added the three packages to your package.json
file as development dependencies:
这还将三个软件包作为开发依赖项添加到package.json
文件中:
. . .
"devDependencies": {
"shipit-cli": "^4.2.0",
"shipit-deploy": "^4.1.4",
"shipit-shared": "^4.4.2"
},
. . .
With your local environment configured, you can now move on to preparing the remote app server for Shipit-based deployments.
配置本地环境后,您现在可以继续为基于Shipit的部署准备远程应用服务器。
In this step, you’ll use ssh
to connect to your app server and install your remote dependency rsync
. Rsync is a utility for efficiently transferring and synchronizing files between local computer drives and across networked computers by comparing the modification times and sizes of files.
在此步骤中,您将使用ssh
连接到应用服务器并安装远程依赖项rsync
。 Rsync是一个实用程序,用于通过比较文件的修改时间和大小来在本地计算机驱动器之间以及在联网的计算机之间高效地传输和同步文件。
Shipit uses rsync
to transfer and synchronize files between your local computer and the remote app server. You won’t be issuing any commands to rsync
directly; Shipit will handle it for you.
Shipit使用rsync
在本地计算机和远程应用程序服务器之间传输和同步文件。 您不会发出任何命令直接进行rsync
; Shipit将为您处理。
Note: How To Set Up a Node.js Application for Production on CentOS 7 left you with two servers app and web. These commands should be executed on app only.
注意: 如何在CentOS 7上设置生产用Node.js应用程序使您拥有了两个服务器app和web 。 这些命令应仅在应用程序上执行。
Connect to your remote app server via ssh
:
通过ssh
连接到远程应用服务器:
ssh deployer@your_app_server_ip
ssh deployer @ your_app_server_ip
Install rsync
on your server by running the following command:
通过运行以下命令在服务器上安装rsync
:
Confirm the installation with:
使用以下命令确认安装:
You’ll see a similar line within the output of this command:
您将在此命令的输出中看到类似的行:
Output
rsync version 3.1.2 protocol version 31
. . .
You can end your ssh
session by typing exit
.
您可以通过键入exit
结束ssh
会话。
With rsync
installed and available on the command line, you can move on to deployment tasks and their relationship with events.
安装了rsync
并在命令行上可用后,您可以继续进行部署任务及其与事件的关系。
Both events and tasks are key components of Shipit deployments and it is important to understand how they complement the deployment of your application. The events triggered by Shipit represent specific points in the deployment lifecycle. Your tasks will execute in response to these events, based on the sequence of the Shipit lifecycle.
事件和任务都是Shipit部署的关键组成部分,了解它们如何补充应用程序部署非常重要。 Shipit触发的事件代表部署生命周期中的特定点。 根据Shipit生命周期的顺序,您的任务将响应这些事件而执行。
A common example of where this task/event system is useful in a Node.js application, is the installation of the app’s dependencies (node_modules
) on the remote server. Later in this step you’ll have Shipit listen for the updated
event (which is issued after the application’s files are transferred) and run a task to install the application’s dependencies (npm install
) on the remote server.
该任务/事件系统在Node.js应用程序中有用的一个常见示例是在远程服务器上安装该应用程序的依赖项( node_modules
)。 在此步骤的稍后部分,您将让Shipit监听updated
事件(在传输应用程序的文件之后发出),并运行任务以在远程服务器上安装应用程序的依赖项( npm install
)。
To listen to events and execute tasks, Shipit needs a configuration file that holds information about your remote server (the app server) and registers event listeners and the commands to be executed by these tasks. This file lives on your local development computer, inside your Node.js application’s directory.
要侦听事件并执行任务,Shipit需要一个配置文件,其中包含有关远程服务器( 应用程序服务器)的信息,并注册事件侦听器以及这些任务要执行的命令。 此文件位于Node.js应用程序目录中的本地开发计算机上。
To get started, create this file, including information about your remote server, the event listeners you want to subscribe to, and some definitions of your tasks. Create shipitfile.js
within your application root directory on your local machine by running the following command:
首先,创建此文件,包括有关远程服务器,要订阅的事件侦听器以及任务的一些定义的信息。 通过运行以下命令,在本地计算机上的应用程序根目录中创建shipitfile.js
:
Now that you’ve created a file, it needs to be populated with the initial environment information that Shipit needs. This is primarily the location of your remote Git
repository and importantly, your app server’s public IP address and SSH user account.
现在,您已经创建了文件,需要使用Shipit所需的初始环境信息来填充该文件。 这主要是您的远程Git
存储库的位置,重要的是您的应用服务器的公共IP地址和SSH用户帐户。
Add this initial configuration and update the highlighted lines to match your environment:
添加此初始配置并更新突出显示的行以匹配您的环境:
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
};
Updating the variables in your shipit.initConfig
method provides Shipit with configuration specific to your deployment. These represent the following to Shipit:
更新shipit.initConfig
方法中的变量将为Shipit提供特定于您的部署的配置。 这些代表了Shipit的以下内容:
deployTo:
is the directory where Shipit will deploy your application’s code to on the remote server. Here you use the /home/
folder for a non-root user with sudo
privileges (/home/sammy
) as it is secure, and will avoid permission issues. The /your-domain
component is a naming convention to distinguish the folder from others in the user’s home folder.
deployTo:
是Shipit将应用程序的代码部署到远程服务器上的目录。 在这里,您将/home/
文件夹用于具有sudo
特权( /home/ sammy
)的非root用户,因为它是安全的,并且可以避免权限问题。 / your-domain
组件是一种命名约定,用于将文件夹与用户主文件夹中的其他文件夹区分开。
repositoryUrl:
is the URL to the full Git repository, Shipit will use this URL to ensure the project files are in sync prior to deployment.
repositoryUrl:
是完整Git存储库的URL,Shipit将使用此URL来确保项目文件在部署之前是同步的。
keepReleases:
is the number of releases to keep on the remote server. A release
is a date-stamped folder containing your application’s files at the time of release. These can be useful for rollback
of a deployment.
keepReleases:
是要保留在远程服务器上的版本数。 release
是带有日期戳的文件夹,其中包含发布时应用程序的文件。 这些对于rollback
部署很有用。
shared:
is configuration that corresponds with keepReleases
that allows directories to be shared
between releases. In this instance, we have a single node_modules
folder that is shared between all releases.
shared:
是与keepReleases
相对应的配置,该配置允许在版本之间shared
目录。 在这种情况下,我们在所有发行版之间共享一个node_modules
文件夹。
production:
represents a remote server to deploy your application to. In this instance, you have a single server (app server) that you name production
, with the servers:
configuration matching your SSH user
and public ip address
. The name production
, corresponds with the Shipit deploy command used toward the end of this tutorial (npx shipit server name deploy
or in your case npx shipit production deploy
).
production:
代表将您的应用程序部署到的远程服务器。 在这种情况下,您只有一个服务器( 应用服务器),您将其命名为production
,其中的servers:
与您的SSH user
和public ip address
匹配的配置。 名称production
对应于本教程末尾使用的Shipit deploy命令( npx shipit server name deploy
或您的情况下npx shipit production deploy
)。
Further information on the Shipit Deploy Configuration object can be found in the Shipit Github repository.
可以在Shipit Github存储库中找到有关Shipit Deploy配置对象的更多信息。
Before continuing to update your shipitfile.js
, let’s review the following example code snippet to understand Shipit tasks:
在继续更新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"')
});
This is an example task that uses the shipit.on
method to subscribe to the deploy
event. This task will wait for the deploy
event to be emitted by the Shipit lifecycle, then when the event is received, the task executes the shipit.start
method that tells Shipit to start
the say-hello
task.
这是一个示例示例任务,该任务使用shipit.on
方法来订阅deploy
事件。 该任务将等待Shipit生命周期发出deploy
事件,然后,当接收到该事件时,该任务将执行shipit.start
方法,该方法告诉Shipit start
say-hello
任务。
The shipit.on
method takes two parameters, the name of the event to listen for and the callback function to execute when the event is received.
shipit.on
方法采用两个参数,即侦听事件的名称和在接收到事件时执行的回调函数。
Under the shipit.on
method declaration, the task is defined with the shipit.blTask
method. This creates a new Shipit task that will block other tasks during its execution (it is a synchronous task). The shipit.blTask
method also takes two parameters, the name of the task it is defining and a callback function to execute when the task is triggered by shipit.start
.
根据shipit.on
方法声明,任务与定义shipit.blTask
方法。 这将创建一个新的Shipit任务,该任务将在执行过程中阻止其他任务(这是一个同步任务)。 shipit.blTask
方法还具有两个参数,即正在定义的任务的名称和当shipit.start
触发任务时执行的回调函数。
Within the callback function of this example task (say-hello
), the shipit.local
method executes a command on the local machine. The local command echos "hello from your local computer"
into the terminal output.
在此示例任务的回调函数( say-hello
)中, shipit.local
方法在本地计算机上执行命令。 本地命令在终端输出中回显"hello from your local computer"
。
If you wanted to execute a command on the remote server, you would use the shipit.remote
method. The two methods, shipit.local
and shipit.remote
, provide an API to issue commands either locally, or remotely as part of a deployment.
如果要在远程服务器上执行命令,则可以使用shipit.remote
方法。 shipit.local
和shipit.remote
这两种方法提供了一个API,可以在本地或作为部署的一部分远程发出命令。
Now update the shipitfile.js
to include event listeners to subscribe to the Shipit lifecycle with shipit.on
. Add the event listeners to your shipitfile.js
, inserting them following the comment placeholder from the initial configuration // Our tasks will go here
:
现在,更新shipitfile.js
以包含事件侦听器,以使用shipit.on
订阅Shipit生命周期。 将事件侦听器添加到您的shipitfile.js
,然后将它们插入初始配置中的注释占位符之后// Our tasks will go here
:
. . .
shipit.on('updated', () => {
shipit.start('npm-install', 'copy-config');
});
shipit.on('published', () => {
shipit.start('pm2-server');
});
These two methods are listening for the updated
and the published
events that are emitted as part of the Shipit deployment lifecycle. When the event is received, they will each initiate tasks using the shipit.start
method, similarly to the example task.
这两种方法正在侦听在Shipit部署生命周期中发出的updated
事件和published
事件。 接收到事件后,它们将分别使用shipit.start
方法启动任务,类似于示例任务。
Now that you’ve scheduled the listeners, you’ll add the corresponding task. Add the following task to your shipitfile.js
, inserting them after your event listeners:
现在已经安排了侦听器,接下来将添加相应的任务。 将以下任务添加到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);
});
You first declare a task called copy-config
. This task creates a local file called ecosystem.config.js
and then copies that file to your remote app server. PM2
uses this file to manage your Node.js application. It provides the necessary file path information to PM2
to ensure that it is running your latest deployed files. Later in the build process, you’ll create a task that runs PM2
with ecosystem.config.js
as configuration.
您首先声明一个名为copy-config
的任务。 此任务将创建一个名为ecosystem.config.js
的本地文件,然后将该文件复制到您的远程应用程序服务器。 PM2
使用此文件来管理您的Node.js应用程序。 它为PM2
提供了必要的文件路径信息,以确保它正在运行最新部署的文件。 在构建过程的稍后部分,您将创建一个运行带有ecosystem.config.js
PM2
作为配置的PM2
的任务。
If your application needs environment variables (like a database connection string) you can declare them either locally in env:
or on the remote server in env_production:
in the same manner that you set the NODE_ENV
variable in these objects.
如果应用程序需要的环境变量(如数据库连接字符串),你可以在本地声明它们env:
或在远程服务器上env_production:
以同样的方式,你设定的NODE_ENV
这些对象变量。
Add the next task to your shipitfile.js
following the copy-config
task:
在copy-config
任务之后, copy-config
下一个任务添加到您的shipitfile.js
:
. . .
shipit.blTask('npm-install', async () => {
shipit.remote(`cd ${shipit.releasePath} && npm install --production`);
});
Next, you declare a task called npm-install
. This task uses a remote bash terminal (via shipit.remote
) to install the app’s dependencies (npm
packages).
接下来,您声明一个名为npm-install
的任务。 此任务使用远程bash终端(通过shipit.remote
)来安装应用程序的依赖项( npm
软件包)。
Add the last task to your shipitfile.js
following the npm-install
task:
在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`
);
});
Finally you declare a task called pm2-server
. This task also uses a remote bash terminal to first stop PM2
from managing your previous deployment through the delete
command and then start a new instance of your Node.js server providing the ecosystem.config.js
file as a variable. You also let PM2
know that it should be using environment variables from the production
block in your initial configuration and you ask PM2
to watch the application, restarting it if it crashes.
最后,您声明一个名为pm2-server
的任务。 此任务还使用远程bash终端,首先通过delete
命令停止PM2
管理先前的部署,然后启动Node.js服务器的新实例,并提供ecosystem.config.js
文件作为变量。 您还让PM2
知道它应该在初始配置中使用production
模块中的环境变量,并要求PM2
监视该应用程序,并在崩溃时重新启动它。
The complete shipitfile.js
file:
完整的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`
);
});
};
Save and exit the file when you’re ready.
准备好后,保存并退出文件。
With your shipitfile.js
configured, event listeners, and associated tasks finalized you can move on to deploying to the app server.
配置好shipitfile.js
,完成事件侦听器和相关任务后,您可以继续部署到应用服务器。
In this step, you will deploy your application remotely and test that the deployment made your application available to the internet.
在此步骤中,您将远程部署应用程序,并测试部署是否使您的应用程序可用于Internet。
Because Shipit clones the project files from the remote Git repository, you need to push your local Node.js application files from your local machine to Github. Navigate to your Node.js project’s application directory (where your hello.js
and shiptitfile.js
are located) and run the following command:
因为Shipit从远程Git存储库克隆项目文件,所以您需要将本地Node.js应用程序文件从本地计算机推送到Github。 导航到您的Node.js项目的应用程序目录(您的hello.js
和shiptitfile.js
所在的目录),然后运行以下命令:
The git status
command displays the state of the working directory and the staging area. It lets you see which changes have been staged, which haven’t, and which files aren’t being tracked by Git. Your files are untracked and appear red in the output:
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)
You can add these files to your repository with the following command:
您可以使用以下命令将这些文件添加到存储库中:
This command does not produce any output, although if you were to run git status
again, the files would appear green with a note that there are changes to be committed.
该命令不会产生任何输出,尽管如果您再次运行git status
,文件将显示为绿色,并带有要提交的更改的注释。
You can create a commit running the following command:
您可以运行以下命令来创建提交:
The output of this command provides some Git-specific information about the files.
该命令的输出提供有关文件的一些特定于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
All that is left now is to push your commit to the remote repository for Shipit to clone to your app server during deployment. Run the following command:
现在剩下的就是将您的提交推送到远程存储库,以便Shipit在部署期间克隆到您的应用服务器。 运行以下命令:
The output includes information about the synchronization with the remote repository:
输出包括有关与远程存储库同步的信息:
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
To deploy your application, run the following command:
要部署您的应用程序,请运行以下命令:
The output of this command (which is too large to include in its entirety) provides detail on the tasks being executed and the result of the specific function. The output following for the pm2-server
task shows the Node.js app has been launched:
该命令的输出(太大而无法完整包含)提供了有关正在执行的任务以及特定功能的结果的详细信息。 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 ]
To view your application as a user would, you can enter your website URL your-domain
in your browser to access your web server. This will serve the Node.js Application, via reverse proxy, on the app server where your files were deployed.
要以用户身份查看您的应用程序,您可以在浏览器中输入网站URL your-domain
来访问Web服务器。 这将通过反向代理在部署文件的应用服务器上为Node.js应用程序提供服务。
You’ll see a Hello World greeting.
您会看到Hello World问候。
Note: After the first deployment, your Git repository will be tracking a newly created file named ecosystem.config.js
. As this file will be rebuilt on each deploy, and may contain compiled application secrets it should be added to the .gitignore
file in the application root directory on your local machine prior to your next git
commit.
注意:第一次部署后,您的Git存储库将跟踪一个新创建的文件名为ecosystem.config.js
。 由于此文件将在每次部署时重建,并且可能包含已编译的应用程序机密,因此应在下次提交git
之前将其添加到本地计算机上应用程序根目录中的.gitignore
文件中。
. . .
# ecosystem.config
ecosystem.config.js
You’ve deployed your Node.js application to your app server, that refers to your new deployment. With everything up and running, you can move on to monitoring your application processes.
您已将Node.js应用程序部署到应用服务器,这是指您的新部署。 在一切正常运行之后,您可以继续监视应用程序过程。
PM2 is a great tool for managing your remote processes, but it also provides features to monitor the performance of these application processes.
PM2是管理远程进程的绝佳工具,但它也提供了监视这些应用程序进程性能的功能。
Connect to your remote app server via SSH with this command:
使用以下命令通过SSH连接到远程应用服务器:
ssh deployer@your_app_server_ip
ssh deployer @ your_app_server_ip
To obtain specific information related to your PM2 managed processes, run the following:
要获取与您的PM2托管流程相关的特定信息,请运行以下命令:
You’ll see output similar to:
您将看到类似于以下内容的输出:
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 │
└─────────────┴────┴─────────┴──────┴──────┴────────┴─────────┴────────┴──────┴───────────┴──────────┴──────────┘
You’ll see a summary of the information PM2 has collected. To see detailed information, you can run:
您将看到PM2收集的信息摘要。 要查看详细信息,可以运行:
The output expands on the summary information provided by the pm2 list
command. It also provides information on a number of ancillary commands and provides log file locations:
输出扩展了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 also provides an in-terminal monitoring tool, accessible with:
PM2还提供了终端内监视工具,可通过以下方式访问:
The output of this command is an interactive dashboard, where pm2
provides realtime process information, logs, metrics, and metadata. This dashboard may assist in monitoring resources and error logs:
该命令的输出是一个交互式仪表板,其中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 │
└───────────────────────────────┘└───────────────────────────────────────────────────────────────────────────┘
With an understanding of how you can monitor your processes with PM2, you can move on to how Shipit can assist in rolling back to a previous working deployment.
了解了如何使用PM2监视流程后,您可以继续学习Shipit如何协助回滚到以前的工作部署。
End your ssh
session on your app server by running exit
.
通过运行exit
在应用服务器上结束ssh
会话。
Deployments occasionally expose unforeseen bugs, or issues that cause your site to fail. The developers and maintainers of Shipit have anticipated this and have provided the ability for you to roll back to the previous (working) deployment of your application.
部署有时会暴露无法预料的错误或导致站点失败的问题。 Shipit的开发人员和维护人员已经预料到了这一点,并为您提供了回滚到应用程序的先前(有效)部署的功能。
To ensure your PM2
configuration persists, add another event listener to shipitfile.js
on the rollback
event:
为确保您的PM2
配置持续存在, shipitfile.js
在rollback
事件上向shipitfile.js
添加另一个事件侦听器:
. . .
shipit.on('rollback', () => {
shipit.start('npm-install', 'copy-config');
});
You add a listener to the rollback
event to run your npm-install
and copy-config
tasks. This is needed because unlike the published
event, the updated
event is not run by the Shipit lifecycle when rolling back a deployment. Adding this event listener ensures your PM2
process manager points to the most recent deployment, even in the event of a rollback.
您将一个侦听器添加到rollback
事件,以运行npm-install
和copy-config
任务。 之所以需要这样做,是因为与published
事件不同,回滚部署时,Shipit生命周期不会运行updated
事件。 添加此事件侦听器,即使在发生回滚的情况下,也可以确保您的PM2
流程管理器指向最新的部署。
This process is similar to deploying, with a minor change in command. To try rolling back to a previous deployment you can execute the following:
此过程类似于部署,只是命令稍有更改。 要尝试回滚到先前的部署,可以执行以下操作:
Like the deploy
command, rollback
provides details on the roll back process and the tasks being executed:
类似于deploy
命令, rollback
提供有关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 ]
You have configured Shipit to keep 5 releases through the keepReleases: 5
configuration in shipitfile.js
. Shipit keeps track of these releases internally to ensure it is able to roll back when required. Shipit also provides a handy way to identify the releases by creating a directory named as a timestamp (YYYYMMDDHHmmss - Example: /home/deployer/your-domain/releases/20190420210548
).
您已配置Shipit继续通过5个版本keepReleases: 5
在配置shipitfile.js
。 Shipit在内部跟踪这些发布,以确保在需要时能够回滚。 Shipit还通过创建名为时间戳的目录(YYYYMMDDHHmmss-示例: /home/deployer/ your-domain /releases/20190420210548
),提供了一种方便的方法来标识发布。
If you wanted to further customize the roll back process, you can listen for events specific to the roll back operation. You can then use these events to execute tasks that will complement your roll back. You can refer to the event list provided in the breakdown of the Shipit lifecycle and configure the tasks/listeners within your shipitfile.js
.
如果要进一步自定义回滚过程,则可以侦听特定于回滚操作的事件。 然后,您可以使用这些事件来执行将补充您的回滚的任务。 您可以参考Shipit生命周期细分中提供的事件列表,并在shipitfile.js
配置任务/侦听shipitfile.js
。
The ability to roll back means that you can always serve a functioning version of your application to your users even if a deployment introduces unexpected bugs/issues.
回滚功能意味着即使部署中引入了意外的错误/问题,您也可以始终向用户提供功能正常的应用程序版本。
In this tutorial, you configured a workflow that allows you to create a highly customizable alternative to Platform as a Service, all from a couple of servers. This workflow allows for customized deployment and configuration, process monitoring with PM2, the potential to scale and add services, or additional servers or environments to the deployment when required.
在本教程中,您配置了一个工作流,该工作流使您可以从几台服务器创建高度可定制的“平台即服务”替代方案。 此工作流允许自定义部署和配置,使用PM2进行过程监控,扩展和添加服务的潜力,或在需要时为部署添加其他服务器或环境。
If you are interested in continuing to develop your Node.js skills, check out the DigtalOcean Node.js content as well as the How To Code in Node.js Series.
如果您有兴趣继续发展Node.js技能,请查看DigtalOcean Node.js内容以及Node.js系列中的How to Code 。