宝塔nodejs项目自动化部署

  1. 首先宝塔要安装一下软件
    1.1 宝塔SSH终端 V1.0
    1.2 宝塔WebHook工具 V1.2
    1.3 PM2管理器 V4.2.3
  2. 打开宝塔SSH
    2.1 cd到自己要下载保存项目的目录,GitClone项目
    2.2 然后cd进拷贝下来的项目
    2.3 然后输入 git config --global credential.helper store
    2.4 执行 git pull 拉去代码
  3. 打开宝塔WebHook
    3.1 点击添加
    3.2 名称要和自己项目的英文地址一致(重要)
    3.3 执行脚本粘贴下方代码,并修改自己的git名称和项目下载的目录
#!/bin/bash
echo ""
#输出当前时间
date --date='0 days ago' "+%Y-%m-%d %H:%M:%S"
echo "Start"
#判断宝塔WebHook参数是否存在
if [ ! -n "$1" ];
then 
          echo "param参数错误"
          echo "End"
          exit
fi
#git项目路径
#路径自己定义
gitPath="/www/wwwroot/项目路径/$1"
#git 下载地址(这里的$1表示添加的时候的名称)
gitHttp="https://gitee.com/自己的git名称/$1.git"

echo "Web站点路径:$gitPath"

#判断项目路径是否存在
if [ -d "$gitPath" ]; then
        cd $gitPath
        #判断是否存在git目录
        if [ ! -d ".git" ]; then
                echo "在该目录下克隆 git"
                sudo git clone $gitHttp gittemp
                sudo mv gittemp/.git .
                sudo rm -rf gittemp
        fi
        echo "拉取最新的项目文件"
        sudo git reset --hard origin/master
        sudo git pull        
        echo "设置目录权限"
        sudo chown -R www:www $gitPath
        echo "End"
        exit
else
        echo "该项目路径不存在"
                echo "新建项目目录"
        mkdir $gitPath
        cd $gitPath
        #判断是否存在git目录
        if [ ! -d ".git" ]; then
                echo "在该目录下克隆 git"
                sudo git clone $gitHttp gittemp
                sudo mv gittemp/.git .
                sudo rm -rf gittemp
        fi
        echo "拉取最新的项目文件"
        sudo git reset --hard origin/master
        sudo git pull
        echo "设置目录权限"
        sudo chown -R www:www $gitPath
        echo "End"
        exit
fi

3.4 点击查看秘钥

3.5 复制GET/POST下面的https开始至param=aaa结束的部分,并且param=后面的aaa改成自己的项目英文名称

  1. 打开gitee码云
    4.1 进入自己的项目点击管理,点击webhook,地址里粘贴刚才的地址保存
  2. 在宝塔的软件市场 找到PM2 点击旁边的文件夹图标 进入pm2的根文件(路径应该是/www/server/panel/plugin/pm2)
    5.1 修改pm2_main.py文件 删除pm2_main.pyc文件
#!/usr/bin/python
#coding: utf-8
#-----------------------------
# PM2管理插件
#-----------------------------
import sys,os,psutil
os.chdir('/www/server/panel')
sys.path.append("class/")
import public,re,json

class pm2_main:
    __SR = None
    __path = '/www/server/panel/plugin/pm2/list/'
    
    def __init__(self):
        s_path = '/www'
        if os.path.islink(s_path):
            s_path=os.readlink(s_path) + '/server'
        else:
            s_path += '/server'
            if os.path.islink(s_path):
                s_path = os.readlink(s_path)
        self.__SR = '''#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
export HOME=/root
export NVM_NODEJS_ORG_MIRROR=http://npm.taobao.org/mirrors/node
export NVM_DIR="{}/nvm"
source /www/server/nvm/nvm.sh ; '''.format(s_path)
    
    #列表
    def List(self,get):
        try:
            tmp = public.ExecShell(self.__SR + "pm2 list -m|grep -v 'pm2 list'|grep -v 'In memory PM2'|grep -v 'Local PM2'")
            appList = tmp[0].strip().split('+---')
            result = []
            tmp = public.ExecShell('lsof -c node -P|grep LISTEN')
            plist = tmp[0].split('\n')
            for app in appList:
                try:
                    if not app: continue
                    tmp2 = re.findall(r"([\w ]+):(.+)",app)
                    tmp3 = {}
                    for t in tmp2:
                        tmp3[t[0].strip()] = t[1].strip()
                    tmp2 = tmp3
                    appInfo = {}
                    appInfo['name'] = app.split('\n')[0].strip()
                    appInfo['id'] = tmp2['pm2 id']
                    appInfo['mode'] = tmp2['mode']
                    appInfo['pid'] = int(tmp2['pid'])
                    appInfo['status'] = tmp2['status']
                    appInfo['restart'] = tmp2['restarted']
                    appInfo['uptime'] = tmp2['uptime']
                    appInfo['cpu'] = 0
                    if appInfo['pid'] and appInfo['pid'] != 'N/A':
                        try:
                            appInfo['cpu'] = psutil.Process(appInfo['pid']).cpu_percent(0.3)
                        except:  appInfo['cpu'] = 0

                    appInfo['mem'] = tmp2['memory usage']
                    appInfo['user'] = 'root'
                    appInfo['watching'] = tmp2['watching']
                    appInfo['port'] = 'OFF'
                    appInfo['path'] = 'OFF'
                    for p in plist:
                        ptmp = p.split()
                        if len(ptmp) < 8: continue
                        if ptmp[1] == str(appInfo['pid']): appInfo['port'] = ptmp[8].split(':')[1].split('->')[0]
                        
                    if os.path.exists(self.__path + appInfo['name']): appInfo['path'] = public.readFile(self.__path + appInfo['name'])
                    result.append(appInfo)
                except: continue
            return result
        except:
            return public.returnMsg(False,'请检查pm2是否正常!'+public.get_error_info())
        
    #获取已安装库
    def GetMod(self,get):
        tmp = public.ExecShell(self.__SR + "npm list --depth=0 -global --json|grep -v '/www/server/nvm'")
        modList = json.loads(tmp[0])
        result = []
        for m in modList['dependencies'].keys():
            mod = {}
            mod['name'] = m
            mod['version'] = modList['dependencies'][m]['version']
            result.append(mod)
        return result
    
    #安装库
    def InstallMod(self,get):
        os.system(self.__SR + 'npm install ' + get.mname + ' -g')
        return public.returnMsg(True,'安装成功!')
    
    #卸载库
    def UninstallMod(self,get):
        MyNot=['pm2','npm']
        if get.mname in MyNot: return public.returnMsg(False,'不能卸载['+get.mname+']')
        os.system(self.__SR + 'npm uninstall ' + get.mname + ' -g')
        return public.returnMsg(True,'卸载成功!')
    
    #获取Node版本列表
    def Versions(self,get):
        result = {}
        rep = r'v\d+\.\d+\.\d+'
        tmp = public.ExecShell(self.__SR+'nvm ls-remote --lts|grep -v v0|grep -v iojs')
        result['list'] = re.findall(rep,tmp[0])
        tmp = public.ExecShell(self.__SR + "nvm version")
        result['version'] = tmp[0].strip()
        print(tmp)
        return result
    
    #切换Node版本
    def SetNodeVersion(self,get):
        version = get.version.replace('v','')
        estr = '''
export NVM_NODEJS_ORG_MIRROR=http://npm.taobao.org/mirrors/node && nvm install %s
nvm use --delete-prefix %s
nvm alias default %s
oldreg=`npm get registry`
npm config set registry http://registry.npm.taobao.org/
npm install pm2 -g
npm config set registry $oldreg 
''' % (version,version,version)
        os.system(self.__SR + estr)
        return public.returnMsg(True,'已切换至['+get.version+']')
    
    #添加
    def Add(self,get):
        #get.pname = get.pname.encode('utf-8');
        if not re.match(r"^\w+$",get.pname):
            return public.returnMsg(False,'项目名称不能包含特殊符号!')
        runFile = (get.path + '/' + get.run).replace('//','/')
        if not os.path.exists(runFile): return public.returnMsg(False,'指定文件不存在!')
        Nlist = self.List(get)
        for node in Nlist:
            if get.pname == node['name']: return public.returnMsg(False,'指定项目名称已经存在!')
        if os.path.exists(get.path + '/package.json') and not os.path.exists(get.path + '/package-lock.json'): os.system(self.__SR + "cd " + get.path + ' && npm install -s')
        os.system(self.__SR + 'cd '+get.path+' && pm2 start ' + runFile +  ' --name "'+get.pname+'" --watch|grep ' + get.pname)
        public.ExecShell(self.__SR + 'pm2 save && pm2 startup')
        if not os.path.exists(self.__path): os.system('mkdir -p ' + self.__path)
        public.writeFile(self.__path + get.pname,get.path)
        return public.returnMsg(True,'ADD_SUCCESS')
    
    #启动
    def Start(self,get):
        #get.pname = get.pname.encode('utf-8');
        result = public.ExecShell(self.__SR + 'pm2 start "' + get.pname + '" --watch|grep ' + get.pname)[0]
        if result.find('online') != -1: return public.returnMsg(True,'项目['+get.pname+']已启动!')
        return public.returnMsg(False,'项目['+get.pname+']启动失败!')
    
    #停止
    def Stop(self,get):
        #get.pname = get.pname.encode('utf-8');
        result = public.ExecShell(self.__SR + 'pm2 stop "' + get.pname + '"|grep ' + get.pname)[0]
        if result.find('stoped') != -1: return public.returnMsg(True,'项目['+get.pname+']已停止!')
        return public.returnMsg(True,'项目['+get.pname+']停止失败!')
    
    #重启
    def Restart(self,get):
        #get.pname = get.pname.encode('utf-8');
        result = public.ExecShell(self.__SR + 'pm2 restart "' + get.pname + '"')[0]
        if result.find('✓') != -1: return public.returnMsg(True,'项目['+get.pname+']已重启!')
        return public.returnMsg(False,'项目['+get.pname+']重启失败!')
    
    #重载
    def Reload(self,get):
        #get.pname = get.pname.encode('utf-8');
        result = public.ExecShell(self.__SR + 'pm2 reload "' + get.pname + '"')[0]
        if result.find('✓') != -1: return public.returnMsg(True,'项目['+get.pname+']已重载!')
        return public.returnMsg(False,'项目['+get.pname+']重载失败!')
    
    #删除
    def Delete(self,get):
       # get.pname = get.pname.encode('utf-8');
        result = public.ExecShell(self.__SR + 'pm2 stop "'+get.pname+'" && pm2 delete "' + get.pname + '"|grep "' + get.pname+'"')[0]
        if result.find('✓') != -1: 
            public.ExecShell(self.__SR + 'pm2 save && pm2 startup')
            if os.path.exists(self.__path + get.pname): os.remove(self.__path + get.pname)
            return public.returnMsg(True,'DEL_SUCCESS')
        return public.returnMsg(False,'DEL_ERROR')
    
    #获取日志
    def GetLogs(self,get):
        path = '/root/.pm2/pm2.log'
        if not os.path.exists(path): return '当前没有日志'
        return public.readFile(path)

if __name__ == "__main__":
    p = pm2_main()
    print(p.List(None))
  1. 重启服务器
  2. 打开pm2 添加自己的nodejs项目就好了 然后git提交就能自动部署了(提示:如果没有重新启动nodejs,可以手动暂停项目后点击启动即可)