easy-deploy-tool

基于pm2与ansible的简易项目运行与发布node库

Usage no npm install needed!

<script type="module">
  import easyDeployTool from 'https://cdn.skypack.dev/easy-deploy-tool';
</script>

README

easy-deploy

基于pm2与ansible的简易项目运行与发布node库

背景

对于一个采用微服务架构的项目,项目的运行与发布是件很麻烦的事.

需求点:

  • 每个服务都有自己的运行参数及相关配置,而且往往开发、生产环境相关配置也不一样,这时需要有个地方能统一管理这些配置,并能方便的拉起,停止,重启,监控项目
  • 项目发布一般会经历线上代码备份、代码发布、初始化操作、重新拉起程序(如果需要),期间可能还会穿插一些本地、远程操作,希望能每个项目少写点发布代码,统一管理这个流程,而且内外网操作能在同一台机器上执行
  • 批量多机部署

本库基于PM2对进程的管理,Ansible是款运维自动化工具,实现本机对外网机器操作.结合这两款工具实现对项目运行、部署管理

依赖要求

本机: node、pm2、ansible、python2.7、rsync

远程主机: node、pm2、python2.7

基本命令

  Usage: easy-deploy [options] [command]

  Options:

    -h, --help                       output usage information

  Commands:

    start [options] <config_file>    启动项目
    stop [options] <config_file>     停止项目
    restart [options] <config_file>  重启项目
    deploy <config_files...>         发布(多个)项目
    ecosystem <target_config_file>   生成配置模板,例如:xxx.js
  Usage: start [options] <config_file>

  启动项目

  Options:

    --only [server_names]     启动部分程序
    --exclude [server_names]  排除部分程序启动
    --silent                  静默模式
    --silentInput [inputs]    静默模式输入(按顺序)
    -h, --help                output usage information
  Usage: stop [options] <config_file>

  停止项目

  Options:

    --only [server_names]     停止部分程序
    --exclude [server_names]  排除部分程序停止
    --silent                  静默模式
    --silentInput [inputs]    静默模式输入(按顺序)
    -h, --help                output usage information
  Usage: restart [options] <config_file>

  重启项目

  Options:

    --only [server_names]     重启部分程序
    --exclude [server_names]  排除部分程序重启
    --silent                  静默模式
    --silentInput [inputs]    静默模式输入(按顺序)
    -h, --help                output usage information

配置模板

module.exports = {
    apps: [                                         //程序配置列表
        {
            namePrefix: "dev/business/",            //若存在,会自动给name加上该前缀
            name      : "activity",                 //pm2上显示的程序名字,默认:default
            script    : "/tmp/test.js",             //程序路径
            args      : {                           //若存在,则运行时添加运行参数
                "host": "0.0.0.0",
                "port": 20003,
                "logPath": "/tmp/activity",
            },                                      
            env: {                                  //若存在,则运行时添加env配置
                "host": "0.0.0.0",
            },
            nodeArgs : {                            //若存在,则运行时添加node配置
                "max-old-space-size": "4096"
            },
            javaArgs: {
                "Xms1024m": "",
                "Xmx4096m": "",
                "Dfile.encoding": "UTF-8"
            },
            // pm2OutFile: "",                      //程序标准输出日志文件位置,默认:~/.pm2/logs/app_name-out.log
            // pm2ErrorFile: "",                    //程序标准出错日志文件位置,默认:~/.pm2/logs/app_name-error.log
            // pm2PidFile: "",                      //程序进程id存放位置,默认:~/.pm2/pids/app_name-id.pid
            // minAliveTime: 10000,                 //程序启动后最短运行时间,单位毫秒,默认:5000,低于此时间属于不正常启动
            // restartLimitBeforeAlive: 2           //正常启动前最多允许错误自动重启的次数,默认:1
            // watch: []                            //监视目录/文件,默认不传,配置时用数组,路径基于启动文件所在目录.例如启动文件路径为/tmp/index.js,监视其下的a目录,即填写['a']
            // ignoreWatch: []                      //忽略监视目录/文件,配合watch参数使用,默认不传,配置时用数组,路径基于启动文件所在目录
            // watchFollowSymlinks: false           //监视时是否跟随软链
        }
    ],
    deploy: {                                       //若存在,可执行发布操作
        user: "test",                               //登录名
        host: "10.10.4.87",                         //远程ip
        sshPort: 22,
        // privateSSHKeyFile: "",                   //登录密钥文件,默认系统配置
        localRoot: "/tmp/abc",                      //本地项目路径
        remoteRoot: "/tmp/abd/",                    //远程项目路径
        exclude: [                                  //若存在,同步到外网忽略的文件列表
            '8888.txt'                 
        ],
        backup: {                                   //若节点存在,则开启发布前备份
            saveDir: "/tmp",                        //备份文件存放路径
            pattern: "YYYY-MM-DD",                  //文件名规则,默认:YYYY-MM-DD HH:mm:ss,格式参见http://momentjs.com/docs/#/displaying/
            exclude: [                              //若存在,则备份时忽略文件列表
                '8888.txt'             
            ]
        },
        hook: {                                     //若节点存在,则发布操作触发钩子
            preLocal: [                             //若节点存在,则发布前本地执行的操作列表
                "echo 'local hello before deploy'"
            ],
            preRemote: [                            //若节点存在,则发布前远程执行的操作列表
                "echo 'remote hello before deploy'"
            ],
            afterLocal: [                           //若节点存在,则发布后本地执行的操作列表
                "echo 'local hello after deploy'"
            ],
            afterRemote: [                          //若节点存在,则发布后远程执行的操作列表
                "echo 'remote hello after deploy'"
            ]
        }
    }
}

配置终端交互

有时配置文件里某些值需要外部传入,那么交互功能则是提供一套组件供开发者使用.其基于readline-sync库进行封装.目前提供以下几种交互: 交互|方法|参数|返回值|备注 ---|:--:|:--:|:--:|--- 输入文本|question|(tip, defaultValue?)|输入的内容|不输入直接回车则采用返回值 输入文件路径|file|(tip)|文件路径|| 输入文件夹路径|dir|(tip)|文件夹路径|| Yes/No|confirm|(tip)|布尔值|| 选项选择|select|(tip, options)|选择项内容||

使用方式

例子中的交互场景可能不太适合,仅做演示用.

const {question, file, dir, confirm, select} = require('easy-deploy-tool').interact;
const name = question('请输入程序名:');
const script = file('请输入启动文件位置:');
const logPath = dir('请输入日志位置:');
const maxOldSpaceSize = select('请选择最大占用内存值:', [1024, 2046, 4098]);
const enableLog = confirm('是否开启日志功能?');

module.exports = {
    apps: [                                        
        {
            namePrefix: "dev/business/",      
            name      : name,                 
            script    : script,          
            args      : {                        
                "host": "0.0.0.0",
                "port": 20003,
                "logPath": logPath,
                "enableLog": enableLog
            },                                      
            env: {                                
                "host": "0.0.0.0",
            },
            nodeArgs : {                       
                "max-old-space-size": maxOldSpaceSize
            }
        }
    ],
    deploy: {                                       //若存在,可执行发布操作
        user: "test",                               //登录名
        host: "10.10.4.87",                         //远程ip
        sshPort: 22,
        // privateSSHKeyFile: "",                   //登录密钥文件,默认系统配置
        localRoot: "/tmp/abc",                      //本地项目路径
        remoteRoot: "/tmp/abd/",                    //远程项目路径
        exclude: [                                  //若存在,同步到外网忽略的文件列表
            '8888.txt'                 
        ],
        backup: {                                   //若节点存在,则开启发布前备份
            saveDir: "/tmp",                        //备份文件存放路径
            pattern: "YYYY-MM-DD",                  //文件名规则,默认:YYYY-MM-DD HH:mm:ss,格式参见http://momentjs.com/docs/#/displaying/
            exclude: [                              //若存在,则备份时忽略文件列表
                '8888.txt'             
            ]
        },
        hook: {                                     //若节点存在,则发布操作触发钩子
            preLocal: [                             //若节点存在,则发布前本地执行的操作列表
                "echo 'local hello before deploy'"
            ],
            preRemote: [                            //若节点存在,则发布前远程执行的操作列表
                "echo 'remote hello before deploy'"
            ],
            afterLocal: [                           //若节点存在,则发布后本地执行的操作列表
                "echo 'local hello after deploy'"
            ],
            afterRemote: [                          //若节点存在,则发布后远程执行的操作列表
                "echo 'remote hello after deploy'"
            ]
        }
    }
}

静默交互

--silent                  静默模式
--silentInput [inputs]    静默模式输入(按顺序)

当配置文件存在交互情况时,有时候不方便输入参数,那么可以通过运行参数形式给配置文件传参数.参数顺序代表输入顺序.目前支持startstoprestartdeploy命令.Deploy Hook preRemoteafterRemote默认给每个命令加上静默参数.若远程命令为easy-deploy的话,可将本地交互内容传给远程命令

const {question} = require('easy-deploy-tool').interact;

module.exports = {
    apps: [         
        {
            namePrefix: "skip/",           
            name      : "activity",                 
            script    : "/tmp/abd1/1.js",             
            args      : {                           
                "host": question("请输入地址:"),
                "port": question("请输入端口号:"),
                "logPath": "/tmp/activity",
            },                                      
            env: {                                  
                "host": "0.0.0.0",
            },
            nodeArgs : {                          
                "max-old-space-size": "4096"
            }
        },
    ]
}
easy-deploy start index.js --silent --silentInput 10.10.4.87 --silentInput 9200

备注

  1. 2018-09-20 增加引用node全局库,对于配置文件里面引用了第三方库情况,只需先行npm -g install xxx对应的库,再执行命令即可
  2. 2019-10-06 本地local shell及pm2内容输出改为流式输出及pm2 watch bug修复
  3. 2020-05-07 start|stop|restart|deploy命令后面支持直接输入目录或者配置文件名字,将会自动查找当前运行目录下的deploy文件夹里的目录下index.js/配置文件,若存在则自动加载该配置文件