NodeJS运行Shell的方式及搭建运维平台

2021-04-13 16:06:17 浏览数 (1)

常用的方式

child_process(原生)

Nodejs下引入模块child_process实现调用shell

调用的两种方式

代码语言:javascript复制
child_process.exec(command[, options][, callback])
child_process.execFile(file[, args][, options][, callback])

Nodejs中通过 exec执行shell脚本,并打印查询到的信息

代码语言:javascript复制
var child = require('child_process');

child.exec('ls', function(err, sto) {
    console.log(sto);//sto才是真正的输出,要不要打印到控制台,由你自己啊
})

执行文件

代码语言:javascript复制
const exec = require('child_process').execSync
exec('bash ./shell/shell1.sh hello')

对应的shell文件

代码语言:javascript复制
#!/bin/bash
# This is our first script.
echo "$1" > log.txt

示例

代码语言:javascript复制
const util = require('util');
const path = require('path');
const child_process = require('child_process');
// 调用util.promisify方法,返回一个promise,如const { stdout, stderr } = await exec('rm -rf build')
const exec = util.promisify(child_process.exec);
const appPath = path.join(__dirname, 'app');

const runClean = async function () {
  // cwd指定子进程的当前工作目录 这里的rm -rf build为删除指定目录下的一个文件夹
  await exec(`rm -rf build`, {
    cwd: appPath
  });
  await exec(`rm -rf test`, {
    cwd: appPath
  });
}
runClean();

注意

util.promisify是在node.js 8.x版本中新增的一个工具,用于将老式的Error first callback转换为Promise对象,让老项目改造变得更为轻松。

shelljs(三方)

shelljs是j基于nodeAPI的一个扩展,要引入插件:(npm地址);

它比原生的child_process的兼容性更好,使用更灵活,这个插件的使用率很高。

安装

代码语言:javascript复制
npm install shelljs

和child_process同样的调用方式

代码语言:javascript复制
var shell = require('shelljs');
var version = shell.exec('node --version', {
  silent: true
}).stdout;
console.info("version", version);

var child = shell.exec('pwd', {
  async: true
});

child.stdout.on('data', function (data) {
  console.log('data:', data);
});

shell.exec('pwd', function (code, stdout, stderr) {
  console.log('Exit code:', code);
  console.log('Program output:', stdout);
  console.log('Program stderr:', stderr);
});

这个插件不仅可以调用exec执行shell命令,也封装了一些快捷操作指令,具体使用文档请参考github地址。

代码语言:javascript复制
var shell = require('shelljs');
// cat 返回文件内容
const mdres = shell.cat(' * .md')

// pwd 获取当前目录
const res = shell.pwd();

// 查找文件
shell.find('src', 'lib');
shell.find(['src', 'lib']); // same as above
shell.find('.').filter(function (file) {
  return file.match(/.js$/);
});

// 创建目录
shell.mkdir('-p', '/tmp/a / b / c / d', '/tmp/e / f / g');
shell.mkdir('-p', ['/tmp/a / b / c / d', '/tmp/e / f / g']);

// 复制
shell.cp('file1', 'dir1');
shell.cp('-R', 'path/to/dir/', '~/newCopy/');
shell.cp('-Rf', '/tmp/*', '/usr/local/*', '/home/tmp');
shell.cp('-Rf', ['/tmp/*', '/usr/local/*'], '/home/tmp'); // same as above

官方示例

代码语言:javascript复制
var shell = require('shelljs');
if (!shell.which('git')) {
  shell.echo('Sorry, this script requires git');
  shell.exit(1);
}
 
// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');
 
// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
  shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
  shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
  shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*n/, shell.cat('macro.js'), file);
});
shell.cd('..');
 
// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
  shell.echo('Error: Git commit failed');
  shell.exit(1);
}

simple-git(GIT)

执行shell脚本操作git,其实对于复杂的git命令语句,写起来还是很不方便,最后介绍一个专为git设计的插件:simple-git(npm地址)

  1. 在项目中引入插件后,调用simple-git/promise可执行异步git操作,方便结合async/await使用
  2. 它封装并支持了很多git的方法,比如clone、commit、status、pull等等,将cmd命令和参数,传入即可
  3. 甚至可以用git.raw(),解析前端输入的git命令

安装

代码语言:javascript复制
npm install simple-git

示例

代码语言:javascript复制
const simpleGit = require('simple-git/promise');
const path = require('path');

async function gitinit() {
  const projectPath = path.join(__dirname);
  const cmd = "init";
  const args = "";
  const git = simpleGit(projectPath);

  try {
    const res = await git[cmd](args);
    console.info("res:", res);
  } catch (e) {
    console.error('执行 simple-git 命令时发生错误', {
      projectPath,
      cmd,
      args
    }, e);
    throw e;
  }
}

gitinit();

总结

这里总结了几种基于node的方式:

  1. child_process 原生nodeAPI,需根据需要选型
  2. shelljs Node的一个扩展插件、兼容性好,推荐使用
  3. simple-git 专为git命令打造的插件,轻量好用

常用的命令

NodeJS获取系统信息

http://nodejs.cn/api/os.html

操作系统类型

代码语言:javascript复制
const os = require('os');
var platform=os.platform();
console.log(platform);

返回值有

  • darwin
  • freebsd
  • linux
  • sunos
  • win32

操作系统版本

代码语言:javascript复制
const os = require('os');
var release=os.release();
console.log(release);

负载

代码语言:javascript复制
const os = require('os');
var loadavg = os.loadavg();
console.log(loadavg);

os.loadavg() 方法返回一个数组,包含 1、5 和 15 分钟平均负载。

平均负载是系统活动的测量,由操作系统计算得出,表达为一个分数。 一般来说,平均负载应该理想地比系统的逻辑 CPU 的数目要少。

平均负载是 UNIX 相关的概念,在 Windows 平台上没有对应的概念。 在 Windows 上,其返回值总是 [0, 0, 0]

CPU和内存

代码语言:javascript复制
const os = require('os');
console.log('剩余内存(M):'   parseInt(os.freemem() / 1024 / 1024));
console.log('总内存(M):'   parseInt(os.totalmem() / 1024 / 1024));
console.log('CPU 架构:'   os.arch());
var cpus = os.cpus();
console.log('CPU:'   cpus.length   '核 '   cpus[0].speed   'mHz');

网卡信息

代码语言:javascript复制
const os = require('os');
console.log('网卡:', os.networkInterfaces());

分配的网络地址的对象上可用的属性包括:

  • address分配的 IPv4 或 IPv6 地址。
  • netmask IPv4 或 IPv6 的子网掩码。
  • family IPv4IPv6
  • mac 网络接口的 MAC 地址。
  • internal 如果网络接口是不可远程访问的环回接口或类似接口,则为 true,否则为 false
  • scopeid 数值型的 IPv6 作用域 ID(仅当 familyIPv6 时指定)。
  • cidr 以 CIDR 表示法分配的带有路由前缀的 IPv4 或 IPv6 地址。如果 netmask 无效,则此属性会被设为 null

硬盘

添加依赖

代码语言:javascript复制
npm i diskinfo

查看硬盘

代码语言:javascript复制
var diskinfo = require('diskinfo');
//获得所有磁盘空间
diskinfo.getDrives(function (err, aDrives) {
  //遍历所有磁盘信息
  for (var i = 0; i < aDrives.length; i  ) {
    //盘符号
    var mounted = 'mounted '   aDrives[i].mounted;
    //总量
    var total = 'total '   (aDrives[i].blocks / 1024 / 1024 / 1024).toFixed(1)   "gb";
    //已使用
    var used = 'used '   (aDrives[i].used / 1024 / 1024 / 1024).toFixed(1)   "gb";
    //可用
    var available = 'available '   (aDrives[i].available / 1024 / 1024 / 1024).toFixed(1)   "gb";
    //使用率
    var capacity = 'capacity '   aDrives[i].capacity;
    console.log(mounted   "rn"   total   "rn"   used   "rn"   available   "rn"   capacity);
    console.log("==================================================================");
  }
});

解析Nginx配置

安装依赖

代码语言:javascript复制
npm install nginx-conf

说明文档:https://www.npmjs.com/package/nginx-conf

生成静态项目配置

代码语言:javascript复制
const NginxConfFile = require('nginx-conf').NginxConfFile;
var fs = require('fs');

//配置项
let conf_path = `${__dirname}/nginx/`;
let server_name = "test.psvmc.cn";
let cert_pem = "/etc/nginx/cert/xhkjedu.pem";
let cert_key = "/etc/nginx/cert/xhkjedu.key";
let root_path = "/data/web_front/psvmc.com";
let useSSL = true;

const filename = `${conf_path}${server_name}.conf`;

fs.access(filename, fs.constants.F_OK, (err) => {
  if (!err) {
    fs.unlinkSync(filename);
  }
  fs.writeFile(filename, '', {
    'flag': 'a'
  }, function (err) {
    if (err) {
      throw err;
    }
    readconf();
  });
});

function readconf() {
  let server_name = "www.psvmc.cn";
  NginxConfFile.create(filename, function (err, conf) {
    if (err || !conf) {
      console.log(err);
      return;
    }

    // server
    conf.nginx._add('server');

    conf.nginx.server[0]._add('listen', '80');
    conf.nginx.server[0].listen[0]._comments.push('http');
    conf.nginx.server[0]._add('server_name', server_name);
    conf.nginx.server[0]._add('client_max_body_size', '200m');

    if (useSSL) {
      // SSL
      conf.nginx.server[0]._add('listen', '443');
      conf.nginx.server[0].listen[1]._comments.push('https');
      conf.nginx.server[0]._add('ssl', 'on');
      conf.nginx.server[0]._add('ssl_certificate', cert_pem);
      conf.nginx.server[0]._add('ssl_certificate_key', cert_key);
      conf.nginx.server[0]._add('ssl_session_timeout', '5m');
      conf.nginx.server[0]._add('ssl_ciphers', 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4');
      conf.nginx.server[0]._add('ssl_protocols', 'TLSv1 TLSv1.1 TLSv1.2');
      conf.nginx.server[0]._add('ssl_prefer_server_ciphers', 'on');
    }


    // location
    conf.nginx.server[0]._add('location', '/');
    conf.nginx.server[0].location[0]._comments.push('location');
    conf.nginx.server[0].location[0]._add('root', root_path);
    conf.nginx.server[0].location[0]._add('index', 'index.html');

    console.info("server_name", conf.nginx.server[0].server_name[0]._value);
  });
}

生成反向代理配置

代码语言:javascript复制
const NginxConfFile = require('nginx-conf').NginxConfFile;
var fs = require('fs');

//配置项
let conf_path = `${__dirname}/nginx/`;
let server_name = "test.psvmc.cn";
let upstream_name = server_name.split(".").join("_");
let server_arr = ['110.110.110.110:8080', '120.120.120.120:8080'];
let cert_pem = "/etc/nginx/cert/xhkjedu.pem";
let cert_key = "/etc/nginx/cert/xhkjedu.key";
let useSSL = true;

const filename = `${conf_path}${server_name}.conf`;

fs.access(filename, fs.constants.F_OK, (err) => {
  if (!err) {
    fs.unlinkSync(filename);
  }
  fs.writeFile(filename, '', {
    'flag': 'a'
  }, function (err) {
    if (err) {
      throw err;
    }
    readconf();
  });
});

function readconf() {
  NginxConfFile.create(filename, function (err, conf) {
    if (err || !conf) {
      console.log(err);
      return;
    }

    // upstream
    conf.nginx._add('upstream', upstream_name);
    for (const server_item of server_arr) {
      conf.nginx.upstream[0]._add('server', server_item);
    }

    // server
    conf.nginx._add('server');

    conf.nginx.server[0]._add('listen', '80');
    conf.nginx.server[0].listen[0]._comments.push('http');
    conf.nginx.server[0]._add('server_name', server_name);
    conf.nginx.server[0]._add('client_max_body_size', '200m');

    if (useSSL) {
      // SSL
      conf.nginx.server[0]._add('listen', '443');
      conf.nginx.server[0].listen[1]._comments.push('https');
      conf.nginx.server[0]._add('ssl', 'on');
      conf.nginx.server[0]._add('ssl_certificate', cert_pem);
      conf.nginx.server[0]._add('ssl_certificate_key', cert_key);
      conf.nginx.server[0]._add('ssl_session_timeout', '5m');
      conf.nginx.server[0]._add('ssl_ciphers', 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4');
      conf.nginx.server[0]._add('ssl_protocols', 'TLSv1 TLSv1.1 TLSv1.2');
      conf.nginx.server[0]._add('ssl_prefer_server_ciphers', 'on');
    }


    // location
    conf.nginx.server[0]._add('location', '/');
    conf.nginx.server[0].location[0]._comments.push('location');
    conf.nginx.server[0].location[0]._add('proxy_pass', 'http://'   upstream_name   '/');
    conf.nginx.server[0].location[0]._add('proxy_cookie_path', '/ /');
    conf.nginx.server[0].location[0]._add('proxy_redirect', '/ /');
    conf.nginx.server[0].location[0]._add('proxy_set_header', 'Host $host');
    conf.nginx.server[0].location[0]._add('proxy_set_header', 'X-Real-IP $remote_addr');
    conf.nginx.server[0].location[0]._add('proxy_set_header', 'X-Forwarded-For $proxy_add_x_forwarded_for');
    conf.nginx.server[0].location[0]._add('client_max_body_size', '200 m');
    conf.nginx.server[0].location[0]._add('client_body_buffer_size', '128k');
    conf.nginx.server[0].location[0]._add('proxy_connect_timeout', '300s');
    conf.nginx.server[0].location[0]._add('proxy_send_timeout', '300s');
    conf.nginx.server[0].location[0]._add('proxy_read_timeout', '300s');
    conf.nginx.server[0].location[0]._add('proxy_busy_buffers_size', '64k');
    conf.nginx.server[0].location[0]._add('proxy_temp_file_write_size', '64k');
    conf.nginx.server[0].location[0]._add('proxy_buffer_size', '64k');
    conf.nginx.server[0].location[0]._add('proxy_buffers', '8 64k');
    conf.nginx.server[0].location[0]._add('fastcgi_buffer_size', '128k');
    conf.nginx.server[0].location[0]._add('fastcgi_buffers', '4 128k');
    conf.nginx.server[0].location[0]._add('send_timeout', '60');
    console.info("server_name", conf.nginx.server[0].server_name[0]._value);
  });
}

注意

所有添加的属性都要以数组的方式来获取 比如 conf.nginx.server[0].server_name[0]._value

修改配置

代码语言:javascript复制
// 当配置改变时不写到磁盘中
conf.die('/etc/nginx.conf');
// 将内存中的配置写到另一个文件中
conf.live('/etc/nginx.conf.bak');
// 修改内存中的值
conf.nginx.events.connections[0]._value = 2000; //change remains local, not in /etc/nginx.conf
// 强行将内存中的配置刷到磁盘中
conf.flush();

0 人点赞