如何在 VPS 上使用 Node.js 编写 Linux 守护进程

金钱(警告)

** 状态:** 被贬值

如果您目前正在运行运行 Ubuntu 12.04 的服务器,我们强烈建议升级或迁移到支持的 Ubuntu 版本:

** 原因:** Ubuntu 12.04 已于 2017 年 4 月 28 日到期(EOL)并且不再收到安全补丁或更新。

** 参见相反:** 本指南可能仍然有用作为参考,但可能不会在其他Ubuntu版本上工作. 如果可用,我们强烈建议使用为您正在使用的Ubuntu版本撰写的指南。

介绍


一个 [daemon](http://en.wikipedia.org/wiki/Daemon_(computing)是一个程序,在背景中运行,没有控制终端. 它们通常用于提供背景服务. 例如,一个Web服务器或数据库服务器可以作为一个daemon运行。

本教程将向您展示如何使用 Node.js编写一个 DAEMON,并在您的VPS上使用 Upstart部署它。

我会专注于实施一个 标准 daemon. 我只是为了简单而使用 upstart,但是你可以写一个 System-V init脚本或使用任何你喜欢的启动你的 daemon。

要求

对于本教程,您将需要一个 Linux VPS(最好是 UbuntuCentOS), Node.jsUpstart

Node.js 的

安装 **Node.js 的几种方法,我认为最简单的方法是使用 nvm

或者,您可以遵循这些指南之一:

  1. 如何在Ubuntu 12.04上安装Node.js上流版本
  2. 通过包管理器安装Node.js

升起

Upstart在许多Linux发行版上预先安装,如果没有安装在您选择的发行版上,您应该能够从官方存储库中安装它,您也可以从源代码中编译它。

Daemons 如何工作


基本上,一个戴蒙像一个正常的过程一样开始,然后会发生以下情况:

它创建了自己的副本,因为它是孩子的过程 2 孩子从父母的过程中分离出来 3 孩子的过程关闭了其标准的文件描述器(http://en.wikipedia.org/wiki/File_descriptor)(见下文) 4 父母的过程退出 5 戴蒙在背景中继续工作

代替关闭标准文件描述器,家长进程可以打开 null device并将其附加到孩子的标准文件描述器中。

戴蒙的例子


为了这个教程,我们将创建一个简单的 ** HTTP ** 戴蒙。

我们的DAEMON将能够:

  1. 在背景中开始(我们将使用一个称为 **daemon**的模块) 2.为 HTTP服务器绑定多个工人 3.在 SIGHUP上重新启动工人 4.在 SIGTERM上终止工人 5.在 HTTP服务器启动后放下工人的特权

初步项目结构

以下是初步项目结构:

1node-simple-http-daemon/
2|
3|-- README.md
4|-- bin/
5|   `-- node-simple-http-daemon
6`-- lib/
7    `-- app.js

标签: 杰森

让我们开始创建一个 package.json文件:

1$ npm init

安裝 daemon模組:

1$ npm --save install daemon

以下是包装.json 的样子:

 1{
 2  "name": "node-simple-http-daemon",
 3  "version": "0.0.0",
 4  "description": "Simple HTTP Daemon written in Node.js",
 5  "main": "lib/app.js",
 6  "scripts": {
 7    "test": "echo \"Error: no test specified\" && exit 1",
 8    "start": "node lib/app.js"
 9  },
10  "author": "Fardjad Davari",
11  "license": "MIT",
12  "dependencies": {
13    "daemon": "~1.1.0"
14  }
15}

请注意,我们添加了开始 脚本,因此我们可以稍后使用npm start命令启动应用程序。

HTTP服务器

目前,我们将创建一个简单的 HTTP服务器,该服务器开始在端口 80上聆听并对每个请求响应 Hello world

将以下内容放入lib/app.js文件中:

 1/**
 2 * lib/app.js
 3 */
 4
 5const PORT = 80;
 6const ADDRESS = '0.0.0.0';
 7
 8var http = require('http');
 9
10var server = http.createServer(function (req, res) {
11  res.writeHead(200, {'Content-Type': 'text/plain'});
12  res.end('Hello World\n');
13});
14
15server.listen(PORT, ADDRESS, function () {
16    console.log('Server running at http://%s:%d/', ADDRESS, PORT);
17    console.log('Press CTRL+C to exit');
18});

您可以通过运行sudo npm start来启动VPS。

DAEMON 可执行

以下是 DAEMON 可执行代码。

以下内容应放在 bin/node-simple-http-daemon中:

 1#!/usr/bin/env node
 2
 3/**
 4 * bin/node-simple-http-daemon
 5 */
 6
 7// Everything above this line will be executed twice
 8require('daemon')();
 9
10var cluster = require('cluster');
11
12// Number of CPUs
13var numCPUs = require('os').cpus().length;
14
15/**
16 * Creates a new worker when running as cluster master.
17 * Runs the HTTP server otherwise.
18 */
19function createWorker() {
20  if (cluster.isMaster) {
21    // Fork a worker if running as cluster master
22    var child = cluster.fork();
23
24    // Respawn the child process after exit
25    // (ex. in case of an uncaught exception)
26    child.on('exit', function (code, signal) {
27      createWorker();
28    });
29  } else {
30    // Run the HTTP server if running as worker
31    require('../lib/app');
32  }
33}
34
35/**
36 * Creates the specified number of workers.
37 * @param  {Number} n Number of workers to create.
38 */
39function createWorkers(n) {
40  while (n-- > 0) {
41    createWorker();
42  }
43}
44
45/**
46 * Kills all workers with the given signal.
47 * Also removes all event listeners from workers before sending the signal
48 * to prevent respawning.
49 * @param  {Number} signal
50 */
51function killAllWorkers(signal) {
52  var uniqueID,
53      worker;
54
55  for (uniqueID in cluster.workers) {
56    if (cluster.workers.hasOwnProperty(uniqueID)) {
57      worker = cluster.workers[uniqueID];
58      worker.removeAllListeners();
59      worker.process.kill(signal);
60    }
61  }
62}
63
64/**
65 * Restarts the workers.
66 */
67process.on('SIGHUP', function () {
68  killAllWorkers('SIGTERM');
69  createWorkers(numCPUs * 2);
70});
71
72/**
73 * Gracefully Shuts down the workers.
74 */
75process.on('SIGTERM', function () {
76  killAllWorkers('SIGTERM');
77});
78
79// Create two children for each CPU
80createWorkers(numCPUs * 2);

是时候开始我们的大卫了!但是在那之前,我们应该修改我们的 app.js到 处理 SIGTERM

将以下内容添加到 app.js 文件的末尾:

1process.on('SIGTERM', function () {
2  if (server === undefined) return;
3  server.close(function () {
4    // Disconnect from cluster master
5    process.disconnect && process.disconnect();
6  });
7});

让 DAEMON 脚本可执行:

1$ chmod +x bin/node-simple-http-daemon

其次,要把它放进去([确保没有其他东西在端口80上运行]):

1$ sudo bin/node-simple-http-daemon

你可以 确认通过通过 cURL发送一个 HTTP GET请求:

1$ curl 127.0.0.1

在进入下一步之前,让我们看看进程ID:

1$ ps -axf | grep [n]ode-simple-http-daemon | \
2  awk '{ print "pid:"$2", parent-pid:"$3 }'

样品产量:

1pid:33811, parent-pid:1
2pid:33853, parent-pid:33811
3pid:33856, parent-pid:33811
4pid:33857, parent-pid:33811
5pid:33858, parent-pid:33811
6pid:33859, parent-pid:33811
7pid:33860, parent-pid:33811
8pid:33861, parent-pid:33811
9pid:33862, parent-pid:33811

请注意,戴蒙是 ** parent-pid** 的过程。

尝试通过将 **SIGHUP ** 发送到 DAEMON 来重新启动工人:

1$ kill -HUP 33811 # (replace 33811 with the daemon PID)

现在,如果你再次列出PID,你应该能够看到新的工人流程与新的PID。

要阻止戴蒙,只需运行:

1$ kill -TERM 33811 # (replace 33811 with the daemon PID)

放弃特权

我们只需要让员工在VPS开始后放弃他们的特权。

app.js中修改server.listen()呼叫,这样它会读到:

 1server.listen(PORT, ADDRESS, function () {
 2    console.log('Server running at http://%s:%d/', ADDRESS, PORT);
 3    console.log('Press CTRL+C to exit');
 4
 5    // Check if we are running as root
 6    if (process.getgid() === 0) {
 7      process.setgid('nobody');
 8      process.setuid('nobody');
 9    }
10});

这就是戴蒙的部分。

现在您可以安装整个系统:

1$ sudo npm link

升起


创建一个文件在 /etc/init/node-simple-http-daemon.conf 下列内容:

1# /etc/init/node-simple-http-daemon.conf
2
3start on started network
4stop on stopping network
5
6respawn
7expect daemon
8
9exec https-proxy-daemon

现在你可以:

1$ sudo start node-simple-http-daemon # Start the job
2$ initctl --system node-simple-http-daemon # Check the job status
3$ sudo reload node-simple-http-daemon # Send SIGHUP (restart the workers)
4$ sudo stop node-simple-http-daemon # Stop the job

下一步


你可能想修改大象,以放弃生育工人,当他们被杀害太频繁(旋转)。

我不能足够强调在你的应用程序中有足够的日志的重要性,请确保检查 node-bunyan

Submitted by: Fardjad Davari
Published At
Categories with 技术
comments powered by Disqus