简化部署和更新的Node.js设置

56
我们目前正在为一位客户开发网站(在Apache下使用TYPO3),该网站由一个node.js/socket.io应用程序支持,该应用程序提供实时更新到从CMS提供的内容。
由于这是我们的第一个node.js项目,因此在“完美设置”方面我没有任何最佳实践可供参考,所以我花了一些时间研究部署技术。
还有一些问题需要解决,以实现良好的设置:
1.易于客户部署。这非常重要,因为我们的网站将集成在他们的“现场”TYPO3安装中,该安装服务于大量网站,并且运行在由另一个(集中)组织管理而不是客户管理的服务器上,这使得支持调用和服务器更改变慢的过程。 2.应该容易更新。如上所述,请求重新启动和进行服务器更改是一个缓慢的过程,因此理想情况下,当它接收到通过git推送到live installion的更改时,node安装应该重新启动/更新。
部署 普遍共识似乎是在部署Node应用程序时使用forever来保持其运行。我已经测试了forever,当通过npm install forever -g(全局)安装时,它似乎可以正常工作。但是,在现场环境中全局安装需要外部帮助,因此我更喜欢它从应用程序的node_modules目录运行,但我还没有能够创建一个稳定的包装器来实现这一点。
此外,forever可以正常工作,但必须手动启动。最好的方法是确保它在服务器启动时启动并保持运行状态?
  • 一个简单的init.d脚本?
  • 编写看门狗包装器?
  • 检查forever状态的TYPO3调度程序任务?
快速开发/更新时重新启动 我们目前仍处于项目开发阶段,每次对node.js应用程序进行更改时,我都需要手动重新启动nodeforever。这种方法虽然可行,但远非理想。 有几个较小的npm模块可以检查文件修改并在检测到更改时重新启动node,例如:

有没有人使用过其中任何一个?

更新:为什么不使用Cluster?

Cluster模块通过reload机制提供类似的功能,但不支持Node 0.5+。替代它的核心Cluster模块(Node 0.6+)只提供了集群功能,而没有这些特性。这反过来与socket.io不兼容。至少没有使用Redis是不行的(对我们来说是个问题,因为我们不能强制客户使用另一个先决条件服务)。

--

显然,我正在尝试找到一种最稳定的解决方案,将更新重启程序与forever结合起来,然后将项目交给客户。我真的希望有人已经生产出了一种经过验证的技术组合。

对于任何考虑使用Cluster的人:它在过去三年中没有更新。 - oligofren
3个回答

63
Combining all the knowledge gathered (Big thanks to Julian Knight for the ideas) and methods tested in the past week, I've decided to settle for the deployment solution described below (I thought I'd be nice to share to help others with comparable questions):
Auto-restarting on script errors and automatic reloading on script changes is handled by forever, as it also includes a script watch, as long as Forever is spawned from within a node.js script.
To do so, I've added a server.js to launch the app.js script we actually want to run:

server.js

var forever = require('forever'),
    child = new(forever.Monitor)('app.js', {
        'silent': false,
        'pidFile': 'pids/app.pid',
        'watch': true,
        'watchDirectory': '.',      // Top-level directory to watch from.
        'watchIgnoreDotFiles': true, // whether to ignore dot files
        'watchIgnorePatterns': [], // array of glob patterns to ignore, merged with contents of watchDirectory + '/.foreverignore' file
        'logFile': 'logs/forever.log', // Path to log output from forever process (when daemonized)
        'outFile': 'logs/forever.out', // Path to log output from child stdout
        'errFile': 'logs/forever.err'
    });
child.start();
forever.startServer(child);

这个程序会监视应用目录中的所有文件变化,并在其中一个文件变化时重新启动在forever中运行的脚本。由于日志和pidfile位于应用程序的子目录中,因此必须从文件监视中忽略它们,否则脚本将循环重启: .foreverignore
pids/**
logs/**

为了让系统启动时自动开始并能够轻松地使用“start node-app”和“stop node-app”来控制服务,我们使用Ubuntu的Upstart。我将两个示例(thisthis)合并成一个可以很好地完成工作的示例:

/etc/init/node-app.conf

# This is an upstart (http://upstart.ubuntu.com/) script
# to run the node.js server on system boot and make it
# manageable with commands such as
# 'start node-app' and 'stop node-app'
#
# This script is to be placed in /etc/init to work with upstart.
#
# Internally the 'initctl' command is used to manage:
# initctl help
# initctl status node-app
# initctl reload node-app
# initctl start node-app

description "node.js forever server for node-app"
author      "Remco Overdijk <remco@maxserv.nl>"
version "1.0"

expect fork

# used to be: start on startup
# until we found some mounts weren't ready yet while booting:

start on started mountall
stop on shutdown

# Automatically Respawn:
respawn
respawn limit 99 5

env HOME=/home/user/node-app-dir

script
    # Not sure why $HOME is needed, but we found that it is:
    export HOME=$HOME
    chdir $HOME
    exec /usr/local/bin/node server.js > logs/node.log &
end script

#post-start script
#   # Optionally put a script here that will notifiy you node has (re)started
#   # /root/bin/hoptoad.sh "node.js has started!"
#end script

正如Kevin在他的文章中明智地提到的那样,以root身份运行node是不明智的,因此下周我们在转移到新服务器时将更改为exec sudo -u www-data /usr/local/bin/node

因此,forever会通过node server.js自动启动,由upstart启动,并监视崩溃和文件更改,使整个设置运行时间长达我们想要的时间。

希望这可以帮助任何人。


我刚试了一下,但无法使其工作,你能帮我吗?https://dev59.com/-3DXa4cB1Zd3GeqP9CZZ - alexandernst
2
我使用了相同的启动脚本,但在 Amazon Linux 上使用 Upstart(版本为0.6.5)时,Upstart 脚本会挂起,特别是在使用 sudo start node-app 时更为明显。我不得不删除 expect fork,因为我的 Node 进程没有分叉,所以 Upstart 在等待永远不会到来的 SIGCHLD。非常好的答案,非常感谢! - clay

7

由于我的上一条回答是针对未来的!以下是其他一些链接,可供参考:

目前似乎还没有完美的解决方案,但有许多人正在运行生产环境中的Node实例。希望这些链接能指引你朝正确的方向前进。


非常感谢您的努力帮助解决这个问题!您提供的第一个链接让我找到了最终采用的“upstart”解决方案(请参见我的答案以获取组合解决方案)。非常感谢您的研究! - Rem.co
1
没关系,很抱歉我不能直接回答更多。但请将您自己的答案标记为答案,您被鼓励这样做,这是完全可以接受的。 - Julian Knight

5
你在生产环境中最好使用像Cluster这样的东西。你可能不需要集群功能,但它还包括其他生产功能,如零停机重启、日志记录、工作进程等。
正如你所说,Forever适用于测试,但不适合生产环境。
我似乎依稀记得,Cluster或类似的东西可能会在v0.7时被纳入Node本身。

听起来像是完美的解决方案,但不幸的是它行不通。Node 0.6+附带的核心集群模块非常基础,没有我们实际感兴趣的所有高级功能。此外,旧的模块不适用于Node 0.5+。很遗憾,但这不会是解决方案。非常感谢您的建议! - Rem.co
抱歉,我还没有将任何Node.js投入生产,所以错过了这个。我还没有承诺使用Node的原因之一是它明显缺乏成熟性。希望0.7版本能够在这方面有所改善,但也需要填补广泛的文档不足问题。 - Julian Knight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接