如何将Node.js应用程序作为自己的进程运行?

203

什么是部署Node.js的最佳方式?

我有一个Dreamhost VPS(他们称之为VM),我已经能够安装Node.js并设置代理。只要保持我用来启动node的SSH连接开放,这个方法就很好用。


6
嗯,你称使用Forever为“deploying node.js”让我感到有些奇怪。它不仅是一个进程监控和管理工具吗?通常,“web deployment”(至少在我读到的文章中)指的是一系列相关活动,使Web应用程序可用(这个工具只是其中的一部分)。无论如何,这篇在StackOverflow的帖子还是很棒的,因为我从所有人的回答中学到了很多。 - mikong
这只是在Dreamhost上最简单的node.js部署。目标仅仅是可靠地运行node,作为构建的起点。 - respectTheCode
你是如何处理将域名转发到节点运行的端口上的? - grm
2
@grm 我使用HTTP-Proxy https://github.com/nodejitsu/node-http-proxy - respectTheCode
我们现在正在使用弹性 Beanstalk,它运行得非常好。 - respectTheCode
可能是Node.js作为后台服务的重复问题。 - mikemaccana
17个回答

122

2016的答案: 几乎每个Linux发行版都附带有systemd,这意味着 forever、monit、PM2等工具已不再必需 - 您的操作系统已经处理了这些任务

创建一个myapp.service文件(将“myapp”替换为您的应用程序的名称,显然):

[Unit]
Description=My app

[Service]
ExecStart=/var/www/myapp/app.js
Restart=always
User=nobody
# Note Debian/Ubuntu uses 'nogroup', RHEL/Fedora uses 'nobody'
Group=nogroup
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/var/www/myapp

[Install]
WantedBy=multi-user.target

如果您是 Unix 的新手:/var/www/myapp/app.js文件的第一行添加 #!/usr/bin/env node 并执行 chmod +x myapp.js 命令以打开可执行权限。

将服务文件复制到 /etc/systemd/system 文件夹中。

使用 systemctl daemon-reload 命令告诉 systemd 新的服务信息。

使用 systemctl start myapp 命令启动服务。

使用 systemctl enable myapp 命令设置服务开机自启。

使用 journalctl -u myapp 命令查看日志。

这段内容摘自How we deploy node apps on Linux, 2018 edition,其中还包括生成 AWS/DigitalOcean/Azure CloudConfig 构建 Linux/node 服务器(包括 .service 文件)的命令。


1
有没有关于如何处理“无法发出方法调用:单位名称...无效”的想法? - Julien Genestoux
1
@JulienGenestoux,“unit”名称与您的服务相同。听起来似乎有些不一致。将文件复制到“/etc/systemd/system”后,您可能需要运行“systemctl daemon-reload”(如果需要,systemd通常会告诉您)。说实话,最好将其作为单独的问题提出。 - mikemaccana
3
不必将您的服务文件复制到/etc/systemd/system中,您可以使用systemctl enable /full/path/to/myapp.service,它会为您创建一个符号链接放在/etc/systemd/system中。 - Arne
1
@VinodSrivastav node 是由 /var/www/myapp/app.js 自身调用的。在 Unix 中,如果您将文件设置为可执行文件,并且第一行以 #!/some/file 开头,则该文件将使用该二进制文件进行解释。请搜索“Unix 解释器”以了解更多信息。 - mikemaccana
1
通常而言,如果不是systemd,那么就是sysvinit,这意味着需要编写一个shell脚本(请参见“/usr/share/doc/svsvinit *”),然后添加一个额外的工具来监视应用程序并重新启动它。 - mikemaccana
显示剩余3条评论

102

使用Forever。它可以在单独的进程中运行Node.js程序,并在任何进程失败时重新启动它们。

用法:

  • forever start example.js 启动一个进程。
  • forever list 查看所有由Forever启动的进程列表
  • forever stop example.js 停止进程,或者forever stop 0 停止索引为0的进程(如forever list所示)。

这很接近了。它开始得很好,但无法停止任何东西。我能够注销并重新登录,然后杀死节点进程。Forever没有重新启动它。所以我认为它的某些工作方式与DH不兼容。 - respectTheCode
@Kevin,你不能杀死节点进程,因为Forever本身就在节点上运行!我已经在我的答案中添加了一些使用说明,包括如何停止进程。我一直在我的VPS上使用它,效果非常好。 - David Tang
“forever stop 0”出现错误,然后事情就有点儿失控了。我一直尝试在普通用户下进行操作而不使用root权限,这样一旦找到正确的解决方案就可以轻松清理。这可能是我的问题所在。我会进一步研究它。 - respectTheCode
我遇到了一些npm的问题,导致出现了一些问题。当npm和node正确安装后,forever运行得非常好。最终我做的是将forever启动命令添加到一个cronjob中,在重新启动时运行。现在我正在开发一个小的node应用程序,让我可以启动和停止forever进程。 - respectTheCode
有一种替代Forever的工具,它使用了Node的本地集群API:https://github.com/superjoe30/naught - andrewrk
我不在Linux机器上工作,所以最佳答案毫无价值。这个答案是所有可以运行Node的操作系统中唯一正确的答案,而且很容易设置并立即运行。此外,我特意进行了测试,它可以立即重新启动应用程序,甚至没有注意到它在短暂的毫秒内关闭了。 - Nicholas R. Grant

41

我在这里写了关于我的部署方法:部署Node.js应用

简要概述:

  • 使用git post-receive hook
  • Jake作为构建工具
  • Upstart作为node的服务包装器
  • 使用Monit来监控并重启应用程序,以防它们崩溃
  • Nginx用于将请求路由到同一服务器上不同的应用程序

2
如果我在服务器上始终只有一个Node网站,我可以放心地放弃Nginx吗? - Dor
3
链接似乎已经损坏。 - verybadalloc
@Dor 我知道这是晚回复,但我不会这样做。除了SSL终止和缓存等事项外,放置在主机前面的nginx反向代理允许您比直接在端口80上运行节点拥有更大的基础架构灵活性。这也意味着您不必将节点作为root运行,我认为这是支持nginx设置的一个很重要的论点。 - Chris Browne

17

pm2可以帮忙完成技巧性的操作。

其功能包括:监控、热代码重载、内置负载均衡器、自动启动脚本以及进程恢复/转储。


它是否与Heroku等服务兼容? - FRD
@FRD 我不认为它适用于Heroku,请查看这篇文章 - nickleefly
这对我来说是最好的。 - mnrafg

9
您可以使用 monitforeverupstartsystemd 来启动您的服务器。
您可以使用 Varnish 或 HAProxy 替代 Nginx(Nginx 无法处理 WebSockets)。
作为一种快速而简单的解决方案,您可以使用 nohup node your_app.js & 来防止您的应用程序随服务器终止,但是使用 forevermonit 和其他提议的解决方案更好。

2
一个名叫"Sergey Yarotskiy"的用户试图编辑您的帖子,声称Nginx现在支持WebSockets(自版本1.3起)。我拒绝了这个编辑请求,因为我认为它应该作为评论发布。(否则,您的帖子中将有两个相互矛盾的句子,这会让人感到困惑。) - Backlin

7
我创建了一个Upstart脚本,目前用于我的应用程序:
description "YOUR APP NAME"
author "Capy - http://ecapy.com"

env LOG_FILE=/var/log/node/miapp.log
env APP_DIR=/var/node/miapp
env APP=app.js
env PID_NAME=miapp.pid
env USER=www-data
env GROUP=www-data
env POST_START_MESSAGE_TO_LOG="miapp HAS BEEN STARTED."
env NODE_BIN=/usr/local/bin/node
env PID_PATH=/var/opt/node/run
env SERVER_ENV="production"

######################################################

start on runlevel [2345]
stop on runlevel [016]

respawn
respawn limit 99 5

pre-start script
    mkdir -p $PID_PATH
    mkdir -p /var/log/node
end script

script
    export NODE_ENV=$SERVER_ENV
    exec start-stop-daemon --start --chuid $USER:$GROUP --make-pidfile --pidfile $PID_PATH/$PID_NAME --chdir $APP_DIR --exec $NODE_BIN -- $APP >> $LOG_FILE 2>&1
end script

post-start script
    echo $POST_START_MESSAGE_TO_LOG >> $LOG_FILE
end script

在 ######### 之前定制所有内容,创建一个文件 /etc/init/your-service.conf 并在其中粘贴。

然后你可以执行以下操作:

start your-service
stop your-service
restart your-service
status your-service

谢谢,正是我所需要的。 - Nilson Morais

6

这看起来很不错。我正在使用Heroku进行开发和初始启动,但最终需要超越Heroku并直接部署到EC2。我会在有时间时尝试一下。 - respectTheCode

5

以下是使用systemd解决此问题的更长文章: http://savanne.be/articles/deploying-node-js-with-systemd/

需要注意以下几点:

  • 谁来启动您的进程监视器? Forever 是一个很棒的工具,但它需要一个监视工具来保持自身运行。这有点愚蠢,为什么不使用您的 init 系统呢?
  • 您能充分监控您的进程吗?
  • 您是否运行多个后端? 如果是,您是否已经采取措施防止任何一个后端在资源使用方面导致其他后端崩溃?
  • 服务是否一直需要在线? 如果不是,请考虑使用 socket 激活 (请参见文章)。

所有这些都可以轻松使用 systemd 完成。


5

我原本以为我没有root权限,但似乎我只需要在Web面板中启用它。我会尝试一下。 - respectTheCode

3

Forever可以解决这个问题。

@Kevin: 你应该能够成功终止进程。我建议再仔细查阅一下文档。如果你能重现错误,最好在GitHub上发布问题以便解决。


谁是Kevin?OP吗? - Peter Mortensen

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