
我经历了血汗和泪水才为您带来这篇文章。我忍受了死亡谷的酷热,登上了麦金利山的峰顶。我牺牲了很多。
这篇文章中分享的大部分内容并非我的原创作品。在可能的情况下,我会链接回原始作品。
本文假设您能够熟练使用 Linux。
我找不到关于在生产环境中在 Ubuntu 上托管和管理 Nodejs 应用程序的综合指南。我整合了多篇相关文章。希望在本文结束时,您能够设置自己的 Ubuntu 服务器,并通过持续集成服务器部署 Nodejs。
环境
我在 Windows 上使用 TeamCity,然后将代码从 GitHub 部署到托管在 AWS 上的 Ubuntu。
技术栈
本文使用了以下技术:
- AWS 上的 Ubuntu 14.04
- Plink 0.64
- TeamCity 9.1
- GitHub
- Nginx 1.9.3
设置 Ubuntu
我不会在这里详细介绍。Amazon Web Services (AWS) 让这变得相当容易。无论它在哪里或是否在您自己的服务器上都无关紧要。
我遇到了一些陷阱。首先,确保端口 80 已打开。我犯了一个愚蠢的错误,试图在端口 80 关闭的情况下连接。一旦我发现了我的错误,我感觉像犀牛的屁股一样愚蠢。
从源码安装 Nodejs
Nodejs 是一个使用 Google V8 javascript 引擎的服务器技术。自 2010 年发布以来,它变得非常流行。
以下说明最初来自 Digital Ocean 的一篇文章。
您总是可以选择从 apt-get 安装 Nodejs,但它会落后几个版本。要获得最新版本,请从源码安装 Nodejs。
在本节结束时,我们将下载最新稳定版本的 node(截至本文),我们将构建源码并安装 Nodejs。
登录到您的服务器。我们首先更新包列表。
sudo apt-get update
我还建议您升级所有包。这对于 Nodejs 来说不是必需的,但保持服务器更新是一个好习惯。
sudo apt-get upgrade
您的服务器现在是最新的。是时候下载源码了。
cd ~
截至撰写本文时,12.7 是 Nodejs 的最新稳定版本。查看 nodejs.org 获取最新版本。
wget https://nodejs.org/dist/v0.12.7/node-v0.12.7.tar.gz
解压您下载的存档文件。
tar xvf node-v*
进入新创建的目录
cd node-v*
配置和构建 Nodejs。
./configure
make
安装 Nodejs
sudo make install
删除下载和解压的文件。当然,这是可选的。
cd ~
rm -rf node-v*
恭喜!Nodejs 现在已安装!而且并不困难。
设置 Nginx
Nodejs 可以充当 Web 服务器,但这不是我想要暴露给外界的。一个工业级、强化的、功能丰富的 Web 服务器更适合这个任务。我选择了 Nginx 来完成这个任务。
它是一个成熟的 Web 服务器,具有我们需要的功能。要运行多个 Nodejs 实例,我们需要端口转发。
您可能在想,为什么我们需要同时运行多个 Nodejs 实例。这是一个合理的问题…在我的场景中,我有一台服务器,我需要在同一台机器上运行 DEV、QA 和 PROD。是的,我知道这不理想,但我不想为每个环境搭建 3 台服务器。
首先让我们安装 Nginx
sudo -s
add-apt-repository ppa:nginx/stable
apt-get update
apt-get install nginx
一旦 Nginx 成功安装,我们需要设置域名。我假设您希望每个站点都有自己的域名/子域名。如果您不想这样做并且想要使用不同的子文件夹,这是可行的并且很容易做到。我不会在这里涵盖那种场景。关于如何做到这一点有大量文档。关于设置不同域名和端口转发到相应 Nodejs 实例的文档很少。这就是我要涵盖的内容。
现在 Nginx 已安装,在 /etc/nginx/sites-available/
为 yourdomain.com 创建一个文件
sudo nano /etc/nginx/sites-available/yourdomain.com
将以下配置添加到您新创建的文件中
# the IP(s) on which your node server is running. I chose port 9001.
upstream app_myapp1 {
server 127.0.0.1:9001;
keepalive 8;
}
# the nginx server instance
server {
listen 80;
server_name yourdomain.com;
access_log /var/log/nginx/yourdomain.log;
# pass the request to the node.js server with the correct headers
# and much more can be added, see nginx config options
location / {
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://app_myapp1;
}
}
确保将 “yourdomain.com” 替换为您的实际域名。保存并退出编辑器。
在 sites-enabled 目录中创建指向此文件的符号链接。
cd /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/yourdomain.com yourdomain.com
要测试一切是否正常工作,创建一个简单的 node 应用程序并将其保存到 /var/www/yourdomain.com/app.js
并运行它。
如果您手头没有,这里有一个简单的 nodejs 应用程序。
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');}).listen(9001, "127.0.0.1");
console.log('Server running at http://127.0.0.1:9001/');
让我们重启 Nginx。
sudo /etc/init.d/nginx restart
如果您还没有启动 Nodejs 实例,不要忘记启动它。
cd /var/www/yourdomain/ && node app.js
如果一切正常工作,当您导航到 yourdomain.com 时,您会看到 “Hello World”。
要为不同的 Nodejs 实例添加另一个域名,您需要重复上述步骤。具体来说,您需要在新的 Nginx 配置文件中更改上游名称、端口和域名。proxy_pass 地址必须与 nginx 配置文件中的上游名称匹配。查看上游名称和 proxy_pass 值,您就会明白我的意思。
总结一下,我们已经从源码安装了 NodeJS,刚刚完成了 Nginx 的安装。我们已经配置并测试了 Nginx 和 Nodejs 的端口转发。
安装 PM2
您可能在问”什么是 PM2?“就像我第一次听到时一样。PM2 是 Nodejs 应用程序的进程管理器。Nodejs 本身没有提供太多功能。这是它吸引力的一部分。缺点是,您必须提供前面的层。PM2 就是其中一层。
PM2 管理 Nodejs 进程的生命周期。当它被终止时,PM2 会重启它。当服务器重启时,PM2 会为您重启所有 Nodejs 进程。它还有广泛的开发生命周期过程。我们不会涵盖 PM2 的这个方面。我鼓励您阅读写得很好的文档。
假设您已登录到终端,我们将开始通过 NPM 安装 PM2。Npm 是 Nodejs 包管理器 (npm)。它在您安装 Nodejs 时就已安装。
sudo npm install pm2 -g
就是这样。PM2 现在已安装。
使用 PM2
PM2 很容易使用。
PM2 的 hello world 很简单。
pm2 start hello.js
这将您的应用程序添加到 PM2 的进程列表中。每次启动应用程序时都会输出此列表。
在这个例子中,有两个 Nodejs 应用程序在运行。一个叫 api.dev,另一个叫 api.pre。
PM2 自动将应用程序的名称分配给列表中的”App name”。
开箱即用,PM2 不会配置自己在服务器重启时启动。不同 Linux 发行版的命令是不同的。我在 Ubuntu 上运行,所以我将执行 Ubuntu 命令。
pm2 start ubuntu
我们还没有完成。我们必须添加 PM2 二进制文件的路径。幸运的是,前一个命令的输出告诉我们如何做到这一点。
输出:
[PM2] You have to run this command as root
[PM2] Execute the following command :
[PM2] sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
Run the command that was generated (similar to the highlighted output above) to set PM2 up to start on boot (use the command from your own output):
sudo env PATH=$PATH:/usr/local/bin pm2 startup ubuntu -u sammy
其他 PM2 用法示例(可选)
通过应用程序名称停止应用程序
pm2 stop example
通过应用程序名称重启
pm2 restart example
PM2 管理的当前应用程序列表
pm2 list
启动进程时指定名称。如果您调用,PM2 使用 javascript 文件作为名称。这可能不适合您。以下是如何指定名称。
pm2 start www.js --name api.pre
这应该足以让您开始使用 PM2。要了解更多关于 PM2 功能的信息,请访问 GitHub 仓库。
设置和使用 Plink
您可能在想,“Plink 到底是什么鬼东西?“至少我是这么想的。我仍然不确定该怎么看待它。我从未见过类似的东西。
您看过电影《机器人总动员》吗?瓦力拿出一个叉勺。首先他试图把它和叉子放在一起,但不合适,然后他试图把它和勺子放在一起,但也不合适。这就是 Plink。它是 Putty (SSH) 和 Windows 命令行的混合体。
Plink 基本上允许您在登录到 Linux(可能还有 Unix)shell 时通过 Windows 命令行运行 bash 命令。
首先下载 Plink。它只是一个可执行文件。我建议将其放在 C:/Program Files (x86)/Plink
中。我们稍后需要引用它。
如果您在 AWS 中运行 Ubuntu 实例。您已经为 Putty 设置了证书(我假设您正在使用 Putty)。
如果不是,您需要确保您有一个兼容的 ssh 证书用于 AWS 中的 Ubuntu。
如果您不使用 AWS,您可以在命令行中指定用户名和密码,不必担心 ssh 证书。
这是一个使用 Plink 连接到 Ubuntu 的示例命令行。
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk"
这可能有点超前,但要在 Ubuntu 服务器上运行 ssh 脚本,我们在 Plink 命令的末尾添加完整路径。
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-dev-ui.sh
这就是 Plink,亲爱的读者。
理解 NODE_ENV
NODE_ENV
是一个由 expressjs 推广的环境变量。在启动 node 实例之前,将 NODE_ENV
设置为环境。在代码中,您可以根据环境加载特定文件。
设置 NODE_ENV
Linux & Mac: export NODE_ENV=PROD
Windows: set NODE_ENV=PROD
环境变量在 Nodejs 实例内通过使用 process.env.NODE_ENV
检索。
示例
var environment = process.env.NODE_ENV
或者使用 expressjs
app.get('env')
*注意:app.get('env')
默认为 “development”。
整合所有组件
Nodejs
、PM2
、Nginx
和 Plink
已安装并希望正常工作。我们现在需要将所有这些组件整合到持续集成解决方案中。
在 /var/www/yourdomain.com
中克隆您的 GitHub 仓库。虽然 SSH 比 HTTPS 更安全,但我建议使用 HTTPS。我知道这不理想,但我无法让 Plink 在 Ubuntu 上与 GitHub 配合工作。不深入细节,Plink 和 GitHub SSH 证书格式不同,通过 Plink 通过 SSH 调用 GitHub 不起作用。如果您能解决这个问题,请告诉我!
要使 GitHub 拉取无需人工干预,用户名和密码需要成为原始 url 的一部分。
以下是如何设置您的原始 url。当然,您需要在适当的地方替换您的信息。
git remote set-url origin https://username:password@github.com/username/yourdomain.git
克隆您的仓库。
cd /var/www/yourdomain.com
git clone https://username:password@github.com/username/yourdomain.git .
注意,如果此目录不是完全空的,包括隐藏文件,Git 将不会将仓库克隆到此目录。
要查找目录中的隐藏文件,运行此命令
ls -a
对于粘合剂,我们使用 shell 脚本。这是我的脚本副本。
#!/bin/bash
echo "> Current PM2 Apps"
pm2 list
echo "> Stopping running API"
pm2 stop api.dev
echo "> Set Environment variable."
export NODE_ENV=DEV
echo "> Changing directory to dev.momentz.com."
cd /var/www/yourdomain.com
echo "> Listing the contents of the directory."
ls -a
echo "> Remove untracked directories in addition to untracked files."
git clean -f -d
echo "> Pull updates from Github."
git pull
echo "> Install npm updates."
sudo npm install
echo "> Transpile the ECMAScript 2015 code"
gulp babel
echo "> Restart the API"
pm2 start transpiled/www.js --name api.dev
echo "> List folder directories"
ls -a
echo "> All done."
我使用 TeamCity 启动这个 shell 脚本,但您可以使用任何工具启动。
这是原始命令。
"C:\Program Files (x86)\Plink\plink.exe" -ssh ubuntu@xx.xx.xx.xx -i "C:\Program Files (x86)\Plink\ssh certs\aws-ubuntu.ppk" /var/www/deploy-yourdomain.sh
exit
>&2
就是这样。
结语
这个过程有一些粗糙的边缘…我希望及时打磨这些边缘。如果您有建议,请在评论中留言。
这个文档在我的 GitHub 仓库 中。技术在变化,所以如果您发现错误请更新它。然后我会更新这篇文章。
作者:Chuck Conway 专注于软件工程和生成式人工智能。在社交媒体上与他联系:X (@chuckconway) 或访问他的 YouTube。