还在用pm2守护你的node进程?试试直接用Systemd

一、前言

作为一个web前端开发,不可避免的会接触到一些偏后端的项目,刚好可以用nodejs开发。 其实开发都没什么问题,关键是如何部署呢?保证系统稳定性呢?

二、Nodemon开发环境启动

以Express框架为例,我们通过官方脚手架,新建一个Express项目。目录结构如下:

├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.pug
    ├── index.pug
    └── layout.pug
复制代码

项目启动的脚本在bin\www文件,因此开发环境,我们启动项目时,直接项目在根目录下,执行:

node ./bin/www
复制代码

即可启动成功。

但是问题来了,这个没法达到热更新部署的效果。也就是本地调试代码的时候,改了文件,它不会自动重启。所以,我们要用到Nodemon

Nodemon is a utility depended on by over 1.5 million projects, that will monitor for any changes in your source and automatically restart your server. Perfect for development. 上述是官网的介绍,主要就是说,Nodemon能监控到任何文件的修改变动,并自动重启服务。完美的适配于开发环境。

用法也及其简单:

npm install -g  nodemon
复制代码

然后再执行启动命令

nodemon ./bin/www
复制代码

三、测试及生产环境pm2启动

这个时候就涉及到几个简单的问题要解决:

  • 环境变量注入
  • 应用进程的稳定性
  • 日志查看 这个时候pm2就派上用场了,

PM2 is a daemon process manager that will help you manage and keep your application online 24/7 简单翻译过来,就是pm2一个是常驻后台的,能够帮助和保持你的应用7x24小时在线的进程管理工具。 根据官方文档,我们可以知道它实现的功能如下:

  • 进程管理和监控(cpu、内存等),支持多个应用,支持其他语言的启动脚本
  • 配置文件,支持设置环境变量、服务名称、入口文件等,支持自动部署,一键部署到生产环境(可以配置 ssh 自动登录)
  • 日志管理,功能比较强大,支持 console 输出的日志
  • cluster mode,可自定义instances数量,支持 reload
  • 提供入口点钩子函数4个方法:onStart,onStop,sensors,actuators 。。。。。。等等。 总之,它就是功能强大,且上手简单,傻瓜式的上手。

使用起来也很简单,首先是全局安装:

npm install -g pm2
复制代码

再编写配置文件,设置环境变量,根目录下新建一个ecosystem.config.js:

module.exports = {
    apps: [{
        name: "your_app_name",
        script: "./bin/www",
        watch: true,
        env: {
            "PORT": 3006,
            "NODE_ENV": "development",
            "DOMAIN": "http://xxx.xxx.xxxx"
        },
        env_uat: {
            "PORT": 3006,
            "NODE_ENV": "uat",
            "DOMAIN": "http://xxx.xxx.xxxx"
        },
        env_production: {
            "PORT": 3006,
            "NODE_ENV": "production",
            "DOMAIN": "http://xxx.xxx.xxxx"
        }
    }]
}
复制代码

package.json编写启动脚本

"scripts": {
    "dev": "cross-env NODE_ENV=development DEBUG=app-server nodemon ./bin/www --name 'app'",
    "start": "pm2 start ecosystem.config.js --env production",
    "uat": "pm2 start ecosystem.config.js --env uat"
  },
复制代码

这样,我们在控制台执行npm run uat,那么pm2就帮我们取到uat的配置,来启动服务了。

注意: ecosystem.config.js配置文件里面的env_xxx 这个写法固定,对应你命令行里面的--env xxx

pm2 常见命令

  • pm2 list:查看pm2守护的node所有的应用列表
  • pm2 logs:查看日志
  • pm2 restart [id]:重启[id]服务 更多命令,可以查看官网的文档。

四、为什么使用Systemd启动应用?

之前我们讲到了一些pm2的特点和实现的功能,其实挺全面的。中小型项目用pm2完全没问题。 如下问题我们需要仔细考虑下:

  • 大多数pm2提供的功能,我们也用不到。
  • pm2需要额外安装
  • 从运维的角度来说,怎样便统一管理和项目启动的脚本。java项目怎么启动?nodejs项目怎么启动,python项目怎么启动?各搞各的,自动化部署方面也存在一定的麻烦。

因此,统一所有的项目启动和进程守护方式,我们可以从Systemd入手。

systemd 是 Linux 系统工具,用来启动守护进程,已成为大多数发行版的标准配置。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。

根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。我们常见的应用部署到系统发行版都是centOS 7以上的。那么这种系统本身就自带了systemd了,所以我们不需要额外再去安装pm2,再通过pm2来守护进程。

Systemd 的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。现在还有很多人反对使用 Systemd,理由就是它过于复杂,与操作系统的其他部分强耦合,违反"keep simple, keep stupid"的Unix 哲学

五、如何使用systemd

systemctlSystemd 的主命令,用于管理系统。

以上述的nodejs项目为例,我们将去pm2,直接通过systemctl启动。

1、新增启动配置

首先、进入到/etc/systemd/system目录下,新增一个serve文件,取名rock-app.service,编辑配置文件内容如下:

cd /etc/systemd/system
vi rock-app.service
复制代码

编辑rock-app.service内容如下:

[Unit]
Description=
Documentation=

[Service]
Type=simple
Environment=PORT=3006
Environment=NODE_ENV=uat
Environment=DOMAIN=http://xxx.xxxx
WorkingDirectory=/home/apps/rock-app
ExecStart=/usr/bin/node bin/www

Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target
复制代码

需要注意的是:

  • Environment就是之前的ecosystem.config.js里面的环境变量
  • WorkingDirectory是要设置为你nodejs应用的根目录。
  • ExecStart是你启动命令。也就是我们通过/usr/bin/node bin/www来启动。这里识别不了全局的node命令,只能通过/usr/bin/node来识别。

2、启动命令并查看应用服务状况

启动应用:

systemctl start rock-app

// 或者 systemctl start rock-app.service
复制代码

查看应用状态:

systemctl status rock-app.service
复制代码

可以看到该服务处于active状态。

如果我们后续有修改到rock-app.service这个配置,需要先执行一个命令:

systemctl daemon-reload

复制代码

再重启服务

systemctl restart rock-app
复制代码

查看日志命令,我们可以通过系统自带的journalctl来查看:

// 基本命令
journalctl -ex -u rock-app.service

// 过滤时间
journalctl -ex -u rock-app.service --since "2018-01-10" --until "2019-01-11 03:00"

// 过滤时间
journalctl -u rock-app.service --since today
复制代码

更多命令,可以参考此处systemd入门

六、结语

艺多不压身,守护nodejs进程,我们又多了一种方式systemd。 此前我们写在应用代码中的环境变量一些启动配置,通过systemd强关联耦合到了服务器上了。方便了开发和运维的职责分离。项目的开发交给开发人员,项目的启动运维,交给运维人员。开发提供最新的配置文件给到运维。但这个过程中也增加了一些配置文件修改的沟通成本。 但是这种方式是否真的合适,具体得根据项目大小,团队开发运维的方式来定。

对于顶尖的技术团队而言,多进程模型(Master-Worker-Agent)是PM2无法支持的。 对于监控功能有更高要求的,pm2支持也不太友好。 但是我们掌握到了linux系统底层的,或者自带的类似systemd这种管理进程的工具的使用,我们才能知道如何去封装自己的进程守护工具。

分类:
前端
标签:
  • 小p
    10小时前