ssh2.js+Shell 一套组合拳下来,一年要花 2080 分钟做的工作竟然节省到 52 分钟~…

  • Post author:
  • Post category:其他


8963cd03a6148dc8da84f4e2781ab067.png

前端Q

我是winty,专注分享前端知识和各类前端资源,乐于分享各种有趣的事,关注我,一起做个有趣的人~

公众号

点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群

关于本文,作者:凌览

https://juejin.cn/post/7194340178939347000

前言

团队被分配了新的工作内容——每周巡检。

巡检工作简单,但需要人工重复性地登陆远程服务器、输入重复的命令,然后将命令的结果记录下来。每做一次估计花

40

分钟,但要每周做,一年52周,一年下来就要花

40*52=2080

分钟,这仅仅是团队一个人一年要花的时间。

不能这么玩呀,纯纯工具人,所以我一直在思考如何用程序帮我自动巡检掉。这篇文章的出现,说明我的想法方向是正确的,收益可观一年要花

2080分钟

,被我减到

52 分钟

如果再扩展程序帮助到团队,这个公式将从

40*52*团队人数

变成

1*52*团队人数

,时间等于金钱。

未自动巡检:

40114d1751805d1293077c990691a5ca.jpeg

手动连接登陆远程服务器,再输入相应的命令获取结果,然后人工依据结果判断是否异常,相当麻烦,而且我要执行的命令不止一条。

自动巡检:

9ae10cb765d5749e3272754ed72d3b42.gif

运行macOS笔记本创建好的快捷指令,它会自动巡检服务器,并且巡检完成后直接打开巡检结果表格。当然没有macOS依然可以,但就是没有快捷指令这步,需要自己执行程序。

完整源码:https://github.com/CatsAndMice/blog/tree/main/ssh

实现

实现难点

自动化巡检思路简单,思路如下:

本地程序连接登陆远程服务器→本地shell命令远程执行→本地程序获取命令结果→结果数据整理成表格

实现过程中主要有以下两个难点:

  • Node.js本地运行程序如何连接登陆远程服务器

  • 登陆远程服务器帐号权限不足,在使用

    sudo

    命令时,如何自动输入密码

实现细节

解决Node.js本地运行程序如何连接登陆远程服务器:

社区已有的方案

ssh2

,它是用纯JavaScript为Node.js编写的SSH2客户端和服务器模块。可以使用它连接到远程服务器,并且

ssh2

提供了方法可以执行shell命令。

ssh2地址:https://github.com/mscdex/ssh2


ssh2

官方案例:

//...
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
  console.log('Client :: ready');
  //执行uptime
  conn.exec('uptime', (err, stream) => {
    if (err) throw err;
    stream.on('close', (code, signal) => {
      console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
      conn.end();
    }).on('data', (data) => {
      //监听数据
      console.log('STDOUT: ' + data);
    }).stderr.on('data', (data) => {
      console.log('STDERR: ' + data);
    });
  });
})
//...

官方案例仅执行一条shell命令,当按照顺序依次执行一条以上的命令,官方的这个写法会非常麻烦。例如:首先执行

docker ps \-a \-q

获取所有docker容器

id

,然后再

docker logs \--tail 200 id

//...
 // 获取docker所有容器ID
 conn.exec('docker ps -a -q', (err, stream) => {
    if (err) throw err;
    stream.on('close', (code, signal) => {
      /**
        docker ps -a -q命令执行完成
        再执行docker logs -f --tail 200 id
      */
      conn.exec(`docker logs  --tail 200 ${id}`,(err,stream)=>{
         if (err) throw err;
          stream.on('close', () => {
          //如果命令再复杂点,还需要继续这样写下去
          
          }).on('data', (data) => {
            console.log( data);
          }).stderr.on('data', (data) => {
            console.log(data);
          });
      })
      
    }).on('data', (data) => {
      console.log('STDOUT: ' + data);
    }).stderr.on('data', (data) => {
      console.log('STDERR: ' + data);
    });
  });
 //...

要想写法整洁点,我们需要再给

exec

方法用

Promise

包一层。


execFn.js:

module.exports = (c = conn) => {
    return (command) => {
        return new Promise((resolve, reject) => {
            c.exec(command, (err, stream) => {
                if (err) {
                    reject(err)
                    return
                }
                let result = ''
                stream.on('close', () => {
                    resolve(String(result))
                }).on('data', (data) => {
                    //data数据是Buffer类型,需要转化成字符串
                    result += data
                })
            })
        })
    }
}

包一层后,再执行命令:

const execFn = require('./execFn.js')

module.exports = (config, conn) => {
    conn.on('ready',async ()=>{
      const exec = execFn(conn)
      const result = await exec('docker ps -a -q')
      //...
      exec(`docker logs --tail 200 ${id}`)
    })
    //...
}

这样代码会显得更整洁点,使用也更方便。

解决登陆远程服务器帐号权限不足,在使用

sudo

命令时,如何自动输入密码,可行方案有两种:

  • 简单粗暴,直接使用

    root

    帐号密码进行登陆,这样即可不用考虑如何跳过密码输入的交互

  • 使用shell管道命令

    echo '密码' | sudo -S 命令


root

帐号密码团队不能给到我,所以我采用了后者来解决。

shell实现自动输入密码方法不只有使用管道命令

echo '密码' | sudo \-S 命令

,还有其他的方法,但它在自动巡检的场景中是最合适的,它不需要额外要求服务器下载其他工具包,像

expect

指令它就需要安装expect包。巡检不只巡检一台服务器,如果每台都安装expect包,这工作量也烦人。

未自动输入密码:

302b4e5621b052c8f24bce3feb597116.jpeg

自动输入密码:

1574c50cc42406b7764400d09623da7c.jpeg

至此,自动化巡检难点之处已解决,下面的工作就是以执行shell命令返回的结果判断服务器状态是否正常,如:团队巡检文档规定当执行

docker info |grep \-A 5 "WARNING"

时,如果有返回结果则为异常。

//...
const before = `echo "${config.password}" | sudo -S `
exec(before + 'docker info |grep -A 5 "WARNING"').then((content) => {
    if (content) {
        rol[2] = '异常'
    }
})
//...

该部分逻辑以团队巡检文档内容为准,不过多赘述,该部分代码在

sshServer.js

文件。

sshServer.js地址:

https://github.com/CatsAndMice/blog/blob/main/ssh/sshServer.js

为了做到巡检多台服务器的目的,巡检相关的逻辑代码使用函数进行包裹并从

sshServer.js

文件中导出。


sshServer.js:

const execFn = require('./execFn.js')
//...
module.exports = (config, conn) => {
    return new Promise((resolve, reject) => {
        const exec = execFn(conn)
        conn.on('ready', async (err) => {
            if (err) reject(err)
            console.log('连接成功');
            //省略
            
        }).connect({
            ...config,
            readyTimeout: 5000
        });
    })

}

所有的服务器帐号密码均放置在

config.json

文件中:

[
    {
        "host": "xx",
        "port": "xx",
        "username": "xx",
        "password": "xx"
    }
    //...
]



config.json

文件涉及到服务器信息需要保密,

config.json

文件不会被提交至仓库。

目录结构如下:

cc6b5573b5a62ca2b0ed133df3a7071a.jpeg

最后,将巡检的结果数据整理成表格

思路是一样的。


index.js

const { Client } = require('ssh2');
const configs = require('./config.json')
const sshServer = require('./sshServer.js');
const fs = require('fs');
const path = require('path');
const nodeXlsx = require('node-xlsx')

const promises = []

//表格数据 二维数组
const tables = [
    ['服务器ip', 'docker是否正常运行', 'docker远程访问', 'Docker日志是否有报错信息']
]

configs.forEach((config) => {
    const conn = new Client();
    promises.push(sshServer(config, conn))
})

Promise.all(promises).then((data) => {
    data.forEach((d) => {
        if (Array.isArray(d)) {
            tables.push(d)
        }
    })
    //生成xlsx表格
    const buffer = nodeXlsx.build([{ name: '巡检', data: tables }])
    const file = path.join(__dirname, '/server.xlsx')
    fs.writeFileSync(file, buffer, 'utf-8')
})

巡检结果统一暂存于

tables

数组中,以便导出。

实现快捷指令巡检

使用命令行巡检还是太累了。最好是鼠标点下自动触发自动巡检。

我们可以借助Mac快捷指令自定义再简化下。

848c2b0062e3e41cfe42a6d3cf3b89ac.jpeg

快捷指令可以运行Shell。这样只需要编写一个名字叫做【巡检服务器】的快捷指令。

7aecd513449862e3ca8a5ef964d9c37b.jpeg

运行Shell后,以WPS打开

server.xlsx

文件。

3bef8caf338cf9ddc7d9418f8d6fea0f.jpeg
0eef5cbba210e07a0df06ebec6807a1a.jpeg

快捷指令添加至访达。

5181978fdcff66befc92be57b4fa4979.jpeg

这样就可以轻松实现自动巡检服务器功能了。

总结

文章灵感来源于工作,通过使用Node.js+Shell+ssh2做到自动连接登陆远程服务器,运行相关Shell命令,检查服务器程序运行是否正常等情况。

对于程序员来说,懒,才是第一生产力!!!

d12930bdf075fe2a11697a9c5c70cf7e.png

往期推荐


仿义务购App(Vue3+Pinia+Koa+Three.js 全栈项目)

fd40a281a221373d866cf08f6e94e2fe.png


wangEditor开源库作者:教你如何写出眼前一亮 简历

3c71f992ed3703ebfedffd3168fb48a1.png


前端跨平台框架对比分析,看这篇就够了

3279ef856b7ef299bd0c70b1b56e0609.png


最后

  • 欢迎加我微信,拉你进技术群,长期交流学习…

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人…

1f00a4c9f423a943e9802ce104dee272.png

前端Q

本公众号主要分享一些技术圈(前端圈为主)相关的技术文章、工具资源、学习资料、招聘信息及其他有趣的东西…

公众号

3e566a1208ce762cd807742991f2c609.jpeg

de4d452fcad87b70687f4c617bddd5a4.png

点个

在看

支持我吧

2f622fda3d1f44b5790cb77c60d60636.gif