Node.js 使用 SCP SSH 部署项目

背景

在项目部署上线的过程中,正常流程是在生成环境 Git 拉取最新代码来进行更新。但是某些极端情况下,由于内网管控的封闭性,生产环境无法拉取 GitLab 端所存储的代码,此时便只能通过 SCP 和 SSH 来曲线救国了。

解决方案

借助 scp2ssh2 这两个 NPM 包,实现项目代码的上传和启动。

npm i scp2 ssh2 -D

deploy.example.js

// 服务器信息
const host = '127.0.0.1';
const username = 'root';
const password = 'password';
const port = 22;
const projectName = 'example-web';
const path = `/root/web/${projectName}/`;

// 上传
async function upload () {
  const client = require('scp2');
  const remoteAddress = `${username}:${password}@${host}`;
  return new Promise((resolve, reject) => {
    client.scp(`../${projectName}`, `${remoteAddress}:${path}`, err => {
      if (err) {
        reject(`Fail: 1 ${err.message}`);
        return;
      }
      resolve('upload success!');
    })
  });
}

// 重启
async function restart () {
  var Client = require('ssh2').Client;
  var conn = new Client();
  return new Promise((resolve, reject) => {
    conn.on('ready', function() {
      console.log('Client :: ready');
      conn.exec(`cd ${path};pwd;npm i;npm run restart;`, function(err, stream) {
        if (err) throw err;
        stream.on('close', function(code, signal) {
          console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
          conn.end();
          resolve('restart success!');
        }).on('data', function(data) {
          console.log('STDOUT: ' + data);
        }).stderr.on('data', function(data) {
          console.log('STDERR: ' + data);
        });
      });
    }).connect({
      host,
      port,
      username,
      password,
    });
  });
}

// 启动任务
;(async () => {
  // 上传
  const uploadResult = await upload().catch(console.error);
  console.log(uploadResult);
  // 重启
  const restartResult = await restart().catch(console.error);
  console.log(restartResult);
})();

此时已经可以在本地进行部署了。但是使用 GitLab CICD 进行部署的时候会遇到问题,就是 GitLab 容器环境中并没有 scp2ssh2 这两个 NPM 包,我们可以借助 Webpack 将以上脚本打包成 Node 容器环境可直接运行的脚本。

webpack.config.deploy.example.js

const path = require('path');

module.exports = {
  entry: './deploy.example.js',
  mode: 'production',
  output: {
    filename: 'deploy.example.bin.js',
    path: path.resolve(__dirname, './'),
  },
  target: 'node',
  node: {
    dgram: 'empty',
    child_process: 'empty',
    fs: 'empty'
  }
};

package.json

{
  // ...
  "node": {
    "http": false,
    "https": false,
    "net": false,
    "path": false,
    "stream": false,
    "tls": false,
    "fs": "empty"
  }
}

npx webpack --config webpack.config.deploy.example.js

发表评论

您的电子邮箱地址不会被公开。