本文详细讲解如何从零搭建支持ES6语法的Node.js项目,涵盖Babel转码配置、PM2集群部署以及forever进程管理,帮助你将Node.js应用高效部署到生产环境。

创建支持ES6的NodeJS项目

  1. 新建一个空的文件夹,在根目录执行:npm init -y。会生成一个package.json文件

  2. 安装依赖

安装express: npm install --save express

安装babel转码编译:npm install --save-dev babel-register babel-preset-env

  1. 在文件根目录创建.babelrc文件,内容如下:
1
2
3
4
5
6
7
8
9
{
"presets": [
["env", {
"targets": {//只转码当前不支持语法
"node": "current"
}
}]
]
}
  1. 新建一个src文件夹,并在文件内新建 main.js内容如下:
1
2
3
4
5
6
7
8
9
import Express from 'express'

let app = Express()

app.get('/', (req, res) => {
res.send('hello world')
})

app.listen(8080, () => console.log('server is running at http://localhost:8080'))

这样还是不能直接运行的,必须要经过转码后才可执行!新建index.js文件作为主入口:

1
2
require('babel-register');
require('./src/main.js')

编写代码后执行:

node index.js

发布时

因为babel-register是实时转码的,所以实际发布时,应该先转码整个app文件

安装依赖 npm install -g babel-cli

转码 babel app -d dist

这次只需要启动dist目录下的app.js即可


使用forever, pm2 让Nodejs持久运行

最简单粗暴的方法是使用Linux本身后台执行的特性

使用&符号后台执行,并利用nohup命令实现进程禁止挂起

nohup node app.js &

使用PM2运行nodeJS

以下是针对 Egg.js 应用结合 PM2 的配置文件示例,支持集群模式、环境变量配置和日志管理:

// ecosystem.config.js
module.exports = {
  apps: [{
    name: 'egg-app', // 应用名称
    script: 'npm', // 使用 Egg.js 官方脚本
    args: 'run start', // 启动命令
    instances: 'max', // 使用所有 CPU 核心
    exec_mode: 'cluster', // 集群模式
    watch: false, // 生产环境关闭监听
    autorestart: true, // 异常退出时自动重启
    max_memory_restart: '1G', // 内存超过 1G 自动重启
    // 环境变量配置
    env: {
      NODE_ENV: 'development',
      PORT: 7001
    },
    env_production: {
      NODE_ENV: 'production',
      PORT: 7001
    },
    // 日志配置
    log_file: './logs/combined.log',
    out_file: './logs/out.log', // 标准输出日志
    error_file: './logs/error.log', // 错误日志
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z', // 日志时间格式
    // 高级配置
    instance_var: 'INSTANCE_ID',
    min_uptime: '10s',
    max_restarts: 10,
    // Egg.js 特定配置
    node_args: '--harmony',
    cwd: './' // 应用根目录
  }]
};

配套的 Egg.js 配置文件 (config.default.js):

// config/config.default.js
module.exports = appInfo => ({
  cluster: {
    listen: {
      path: '',
      port: process.env.PORT || 7001, // 优先使用环境变量端口
      hostname: '0.0.0.0' // 允许外部访问
    }
  },
  // 自定义日志路径(与 PM2 配置对应)
  logger: {
    dir: './logs',
    level: 'INFO'
  }
});

使用说明:

  1. 启动应用​:

    # 开发环境
    pm2 start ecosystem.config.js
    
    # 生产环境
    pm2 start ecosystem.config.js --env production
    
  2. 常用 PM2 命令​:

    pm2 status egg-app          # 查看状态
    pm2 reload egg-app          # 平滑重启(零停机)
    pm2 logs egg-app --lines 100 # 查看日志
    pm2 save                    # 保存当前进程列表
    pm2 startup                # 设置开机自启
    

关键配置说明:

  • 集群模式​:通过 instances: 'max'充分利用多核 CPU
  • 平滑重启​:使用 pm2 reload避免服务中断
  • 日志管理​:分离输出/错误日志便于问题排查
  • 环境隔离​:通过 env配置区分不同环境变量

此配置已优化生产环境部署,支持高性能集群运行和完整的运维监控需求。


pm2部署项目

使用ssh-agent代理设置ssh通信. ssh-keygen -C "comment" 注意:不要修改文件名称,直接回车即可

⚠️ pm2 内存中只存在一个进程,必须执行pm2 update 刷新内存. ps -ef |grep pm2 查看进程状态。
最好不要运行两个pm2,会相互挤占进程,导致运行错误。
Easy Deploy with SSH

SSH无密码(密钥验证)登录的配置

  • 配置主机A免密登录到主机B(方法一)
    1. 在主机A生产密钥对: ssh-keygen -t rsa, 会在.ssh目录下产生密钥文件
    2. 拷贝主机A的公钥到主机B: scp id\_rsa.pub
    3. 将主机A的公钥加到主机B的授权列表.ssh/authorized\_keys(若不存在,手动创建): cat id\_rsa.pub >> authorized\_keys
    4. 授权列表authorized\_keys的权限必须是600,chmod 600 authorized\_keys
  • (方法二)
    1. 进入到我的home目录 cd \~/.ssh ssh-keygen -t rsa (四个回车) 执行完这个命令后,会生成两个文件id\_rsa(私钥)、id\_rsa.pub(公钥)
    2. 将公钥拷贝到要免登陆的机器上: ssh-copy-id localhost

问题

Permanently added ‘github.com,13.229.188.59’ (RSA) to the list of known hosts.

ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
ssh-keyscan -t rsa gitee.com >> ~/.ssh/known_hosts

ssh -T git@github.com
ssh -T git@gitee.com

You’ve successfully authenticated, but GITEE.COM does not provide shell access.

git pull origin master --allow-unrelated-histories

使用forever让node.js持久运行

npm install forever -g   #安装
forever start app.js  #启动应用
forever stop app.js  #关闭应用
forever restartall  #重启所有应用

#输出日志和错误
forever start -l forever.log -o out.log -e err.log app.js   

# 指定forever信息输出文件,当然,默认它会放到~/.forever/forever.log
forever start -l forever.log app.js  

# 指定app.js中的日志信息和错误日志输出文件,  
# -o 就是console.log输出的信息,-e 就是console.error输出的信息
forever start -o out.log -e err.log app.js 

# 追加日志,forever默认是不能覆盖上次的启动日志,  
# 所以如果第二次启动不加-a,则会不让运行  
forever start -l forever.log -a app.js

# 监听当前文件夹下的所有文件改动(不太建议这样)  
forever start -w app.js  

# 显示所有运行的服务 
forever list  

######停止操作

# 停止所有运行的node App  
forever stopall  
  
# 停止其中一个node App  
forever stop app.js  

# 当然还可以这样  
# forever list 找到对应的id,然后:  
forever stop [id]

# 开发环境下  
NODE_ENV=development forever start -l forever.log -e err.log -a app.js  
# 线上环境下  
NODE_ENV=production forever start -l ~/.forever/forever.log -e ~/.forever/err.log -w -a app.js
#上面加上NODE_ENV为了让app.js辨认当前是什么环境用的

作者:极地瑞雪
链接:https://www.jianshu.com/p/669a618f3212
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

HuiLive shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/bin/sh
# init file for AnyRTCLive web server
# by Ming.Niu
#
# chkconfig: - 90 90
# description: DYNC AnyRTCLive Web Server

. /etc/init.d/functions

#PATH=/usr/local/anyrtc/service/anyrtc_nodejs_server/:$PATH

RUNASUSER=root
UGID=$(getent passwd $RUNASUSER | cut -f 3,4 -d:) || true

prog="HuiLiveWebServer"

daemonStr="/usr/local/anyrtc/HuiLiveWebServer/bin/HuiLive"
logPath="/var/log/node-HuiLive/"
params="-a -l ${logPath}forever.log -o ${logPath}console.log -e ${logPath}error.log"

[[ -d ${logPath} ]] || mkdir ${logPath}
#==============================================================================
start()
{
echo -n $"Starting HuiLive Web Service: "
if [ -z "$UGID" ]; then
echo "User \"$RUNASUSER\" does not exist!"
failure
else
pid="$(__pids_pidof "$prog")"
if [ -z "$pid" ]; then
su - $RUNASUSER -c "forever ${params} start ${daemonStr}"
echo "Log files in ${logPath}"
sleep 2
ps -ef|grep HuiLiveWebServer |grep -v grep
if [ $? -ne 0 ]
then
failure
else
success
fi
else
echo "HuiLive Web Service (pid $pid) is still running..."
failure
fi
fi
echo
}

case "$1" in
start)
start
;;
stop)
su - $RUNASUSER -c "forever stop ${daemonStr}"
;;
restart)
su - $RUNASUSER -c "forever stop ${daemonStr}"
start
;;
status)
su - $RUNASUSER -c "forever list &"
;;
*)
echo "Usage: $0 (start|stop|restart|status)"
esac