[Nodejs principle source & Appreciation (9)] to achieve lightweight automated deployment with node-ssh

Sample code is hosted: http://www.github.com/dashnowords/blogs

Blog Park address: "the history of living in the big front-end" original blog directory

Huawei cloud community Address: [you want the front Daguai upgrade guide]

I. Description of Requirement

After the front-end engineering package implements a simple automated deployment.

II. Preliminaries

Construction site can use any familiar framework of three frame has its own official Clitool, compiled from the code can be used to generate a production environment deployment package has a basic command automation, various packaging tools is also zero configuration make the pursuit of a lot of work. This blog entry began to get the package from a production environment after the relevant knowledge of site deployment of some description.

First you need a Web server, common are:

  • Nginx
  • Tomcat
  • ApacheOr related integrated environment
    • XAMMPApache+MySQL+PHP+PERL
    • LAMPLinux+Apache+MySQL+PHP
  • nodejsOr relevant framework + daemon
    • Express
    • Koa2

Any of the above after running on a server can serve Web server role, but with extended functionality and application scenarios are different, Nginxbasically the preferred solution for the deployment of a formal environment. The basic common deployment scenarios are as follows:

IP + port access

Use access, direct access to the corresponding port services, deployment is relatively simple:

Domain names

When using a domain name, is typically used to parse A record, it can only be mapped to port 80 (https when mapped to 443), then you will need to use a reverse proxy 80distribution request to a different local port to access the corresponding internal port service:

Used in this example 域名+IPembodiment will be deployed.

III. Nodejs manual deployment of applications

In Expressan example, the following steps:

  1. First through yarn global add express-generatoror npm install express-generator -ginstall scaffolding global
  2. Upon completion of the working directory from the command line express mydemo --ejsto generate a use ejsas a template rendering engine expressproject
  3. Command line input cd mydemo && yarnor cd mydemo && npm installmounted reliance
  4. In /bin/wwwmodifying the port number in the desired port number (port 80 is automatically generated), e.g.3001
  5. The front-end engineering build an overall package copy and paste into the /publicdirectory
  6. Now enter in the root directory of the local project npm start, the browser http://localhost:3001can access the site
  7. Use the FTP tool (e.g., FlashFxpor FileZilla Clientthe like) is connected to the deployment machine, the mydemodirectory is compressed zipafter the package uploaded to the server specified directory.
  8. Using SSH tools (such as Xshellor MobaXter) log on the remote machine, assuming linuxthe system, enter unzip mydemo.zipextracting archive, and then cd mydemoenter the server project, the input npm startto turn Web service on the server, through ip地址:3001to access to the site.
  9. 但是如果此时SSH工具断开连接,就会发现express应用无法继续访问了,所以还需要一个守护进程来维持应用的启动状态,在服务端通过npm install pm2 -g来安装nodejs应用的部署管理模块,它可以实现多应用管理、Hook更新、自动重启等等许多常用功能,详细信息可以访问 【PM2官方网站】
  10. 最后,在工程根目录输入pm2 start ./bin/www即可以后台模式运行应用。

四. 基于nodejs的自动部署

4.1 package.json中的scripts

了解了手动部署的过程后,就可以通过自动化脚本来实现后续的更新和部署。nodejs工程的自动化是依赖于package.json文件中的scripts配置项来实现的,例如使用vue-cli搭建的工程中就会带有:

{
    ...
    "scripts": {
        "serve": "vue-cli-service serve",
        "build": "vue-cli-service build",
        "lint": "vue-cli-service lint"
      },
    ...
}

在项目根目录下打开命令行,输入npm run [script-key]或者yarn [script-key][script-key]指上面示例中的serve,build,lint这些键名),就会执行对应的scripts[key]对应的命令。我们先添加一条用于自动部署的脚本指令:

{
    ...
    "scripts": {
        "build": "vue-cli-service build",
        "deploy" "node ./scripts/deploy/deploy.js"
      },
    ...
}

当输入npm run deployyarn deploy时,实际上就相当于用node去执行./scripts/deploy/deploy.js这个脚本,其中就编写了自动化发布的指令。scripts还提供了生命周期钩子,比如你对接的是一个测试环境,希望每次build后自动发布,就可以使用post钩子来实现:

{
    ...
    "scripts": {
        "build": "vue-cli-service build",
        "postbuild":"npm run deploy",
        "deploy" "node ./scripts/deploy/deploy.js"
      },
    ...
}

这样每次build执行完毕后,就会自动执行npm run deploy,也就是运行发布的脚本。

4.2 自动化发布脚本deploy.js

自动化发布脚本需要完成这样几个任务:

  • 将打包出的dist压缩为zip
  • 使用SSH连接部署服务器,将zip包发上去
  • 上传完毕后,启动事先写好后续任务并放在服务器上的shell脚本来完成剩余的工作

涉及的几个模块包括实现SSH连接的node-ssh模块(底层是ssh2模块,这个模块是一个Promise封装),用于制作zip压缩包的archiver模块。node-ssh提供了上传本地目录的方法,但实际使用过程中发现并不稳定,从告警信息来看是node-stream模块在传送时将不同格式的文件转换为流时可能会出现异常,实测大约有一半概率触发,尝试修改了一些配置参数并未解决,所以采用archiver模块先压缩为单个文件后再进行上传。

参考代码如下:

const path = require('path');
const archiver =require('archiver');
const fs = require('fs');
const node_ssh = require('node-ssh');
const ssh = new node_ssh();
const srcPath = path.resolve(__dirname,'../../dist');
const configs = require('./config');

console.log('开始压缩dist目录...');
startZip();

//压缩dist目录为public.zip
function startZip() {
    var archive = archiver('zip', {
        zlib: { level: 5 } //递归扫描最多5层
    }).on('error', function(err) {
        throw err;//压缩过程中如果有错误则抛出
    });
    
    var output = fs.createWriteStream(__dirname + '/public.zip')
     .on('close', function(err) {
         /*压缩结束时会触发close事件,然后才能开始上传,
           否则会上传一个内容不全且无法使用的zip包*/
         if (err) {
            console.log('关闭archiver异常:',err);
            return;
         }
         console.log('已生成zip包');
         console.log('开始上传public.zip至远程机器...');
         uploadFile();
     });

    archive.pipe(output);//典型的node流用法
    archive.directory(srcPath,'/public');//将srcPach路径对应的内容添加到zip包中/public路径
    archive.finalize();
}

//将dist目录上传至正式环境
function uploadFile() {
    ssh.connect({ //configs存放的是连接远程机器的信息
        host: configs.host,
        username: configs.user,
        password: configs.password,
        port:22 //SSH连接默认在22端口
    }).then(function () {
        //上传网站的发布包至configs中配置的远程服务器的指定地址
        ssh.putFile(__dirname + '/public.zip', configs.path).then(function(status) {
                console.log('上传文件成功');
                console.log('开始执行远端脚本');
                startRemoteShell();//上传成功后触发远端脚本
          }).catch(err=>{
             console.log('文件传输异常:',err);
             process.exit(0);
          });
    }).catch(err=>{
        console.log('ssh连接失败:',err);
        process.exit(0);
    });
}

//执行远端部署脚本
function startRemoteShell() {
    //在服务器上cwd配置的路径下执行sh deploy.sh脚本来实现发布
    ssh.execCommand('sh deploy.sh', { cwd:'/usr/bin/XXXXX' }).then(function(result) {
        console.log('远程STDOUT输出: ' + result.stdout)
        console.log('远程STDERR输出: ' + result.stderr)
        if (!result.stderr){
            console.log('发布成功!');
            process.exit(0);
        }
    });
}

4.3 远端脚本deploy.sh

当发布包上传至远程服务器后,剩余的工作在远端来完成就可以了,你只需要将后续的工作写进shell脚本并放在对应的目录里就可以了,本例中deploy.sh放在了服务端项目目录/mydemo中。示例如下(由于是自用系统,不考虑灰度发布等,直接暴力删除静态目录public,然后替换为新的包):

#!/bin/bash
cd /usr1/AAA/mydemo
#删除原静态资源目录
rm -rf public
cd /usr1/AAA
#解压新的包
unzip public.zip
#将解压出的public目录移动到服务端程序目录BBB中
mv public ./mydemo

提示:

如果脚本文件是在windows下编写的,请注意将编辑器中的回车换行改为LF,windows下通常默认是CRLF,这可能会导致脚本在linux机器上无法正常执行。

至此,一个简易的自动化部署就做完了。你只需要在本地输入npm run deploy,后续的工作就会自动执行。

五. 小结

本篇只是一个简易的自动化部署流程,由于部署环境没有外网所以暂时无法借助通用的自动化流水线实现全自动的DevOps流程。PM2实际上还有非常多实用的功能,可以管理多个不同的应用实例,以集群模式运行实例,或者预设发布流程,可以直接响应Web Hook并对接指定的代码仓,在根目录下建立ecosystem.config.js配置文件就可以添加更多配置来指定pm2的表现,感兴趣的读者可以研究一下。

Guess you like

Origin www.cnblogs.com/dashnowords/p/11293667.html