scp2 简介
一个基于ssh的纯javaScript安全复制程序
优点
可以在每个操作系统上执行,unix、Linux、windows等。
一、创建scp2相关的配置文件
【1】、在项目根目录下创建 deploy 文件夹, 在 deploy 文件夹下创建 config.js 文件用来保存服务器的配置信息。(示例如下:)
const client = require("scp2");
const config = require("../deploy.config.js");
console.log('正在部署,请稍等,host为:' + config.host + ',路径为' + config.serverPath)
client.scp(
config.localPath,
{
host: config.host,
username: config.username,
password: config.password,
path: config.serverPath,
},
function (err) {
if (err) {
console.log("部署失败,请确认账号密码正确", err);
} else {
console.log("部署成功");
}
}
);
在根目录创建 deploy.config.js文件
module.exports = {
host: '47.94.96.226',
username: 'root',
password: 'Liulin1992',
serverPath: '/home/muerdi123/dist',
localPath: 'dist/'
}
二、添加执行命令
在 package.json 中注册执行命令,自定义命令名称:
scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build --report",
"build:deploy": "vue-cli-service build && node deploy/index.js",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src"
},
安装 npm install scp2@0.5.0
"scp2": "^0.5.0",
三 执行打包并上传命令
npm run build:deploy
这种有个弊端就是服务器的地址 和密码是用明文显示的在代码中 容易泄露
第二种方法
升级版 手动输入服务器账号密码
1.在根目录下创建deploy文件夹
首先安装 依赖包
"chalk": "^4.1.2",
"ora": "^5.1.0",
"readline": "^1.3.0",
"scp2": "^0.5.0"
创建 index.js文件和config.js文件
index.js 文件如下
const scpClient = require('scp2')
const config = require('./config.js')
const readline = require('readline') // 输入内容使用
const ora = require('ora') // 执行时打印信息
const chalk = require('chalk') // 打印信息颜色
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
const questions = ['Please input publish environment(test\\prod\\dev(defalut:prod)): ', 'Please input server username: ', 'Please input server password: ']
const linelimit = 3
let inputArr = []
let index = 0
let server = null
// 依次执行命令行交互语句
function runQueLoop() {
if(index === linelimit) {
if(!inputArr[0]) inputArr[0]='prod'
server = config[inputArr[0]]
if(inputArr[1]) server.username = inputArr[1]
if( inputArr[2]) server.password = inputArr[2]
console.log('==========',server)
deployFile()
return
}
rl.question(questions[index], as => {
console.log('输入的内容=====',as)
inputArr[index] = as
index++
runQueLoop()
})
}
runQueLoop()
function deployFile() {
// 将前面的 scp2 上传文件到服务器代码,封装到这里。
const spinner = ora('正在发布到' + server.host + '服务器...')
spinner.start()
scpClient.scp(
'dist/',
{
host: server.host,
port: server.port,
username: server.username,
password: server.password,
path: server.path
},
function (err) {
spinner.stop()
if (err) {
console.log(chalk.red('发布失败.\n',err))
throw err
} else {
console.log(chalk.green('Success! 成功发布到' + server.host + '服务器! \n'))
}
}
)
}
config.js 文件如下
// config.js
/*
*定义多个服务器账号 及 根据 SERVER_ID 导出当前环境服务器账号
*/
const SERVER_LIST = {
dev: {
id: 0,
name: 'A-生产环境',
domain: 'qq.zbc.com', // 网站域名
host: '110.42.130.82', // 服务器ip
port: 22, // 登录服务器端口
username: 'root', // 登录服务器的账号
password: 'prod123456', // 登录服务器的账号
path: '/www/wwwroot/site/dist', // 发布至静态服务器的项目路径
rootPath: '/www/wwwroot/site'
},
prod: {
id: 1,
name: 'B-生产环境',
port: 22,
host: '47.94.98.234',
username: 'root',
password: '123456',
path: '/home/muerdi123/dist',
rootPath: 'dist/',
}
}
module.exports = SERVER_LIST
执行命令 package.json
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build --report",
"build:deploy": "vue-cli-service build && node deploy/index.js",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"deploy:prod": " node ./deploy"
},
先备份在部署
二、上传前备份旧版文件
强烈建议,
在上传文件前对旧版文件进行备份,方便版本回退或部署失败后能够保证生产环境能够正常运行。
对代码进行简单的修改,在上传文件前,使用 ssh 先对原文件进行拷贝,删除,之后再上传文件。
基本实现思路如下:
进入到上传文件的根目录下 — 即 server 配置中的 rootPath 属性 新建一个文件夹用于备份 _backUp/文件名
- 拷贝旧版部署包到备份文件夹下
- 删除旧版部署包
- 上传新版部署包
- 具体实现方案:
- 安装ssh2
npm i ssh2 -D
- 导入ssh2模块,并声明要执行的命令
// ssh2 传输
const ora = require('ora') // 执行时打印信息
const chalk = require('chalk') // 打印信息颜色
const Client = require('ssh2').Client
const conn = new Client()
const server = {
id: 1,
name: 'B-生产环境',
port: 22,
host: '47.945.965.2526',
username: 'root',
password: 'Liu',
}
const rootPath = '/home'
const rootFolder = 'testcopy'
var today = new Date();
// 获取年、月、日、时、分、秒
var year = today.getFullYear();
var month = today.getMonth() + 1; // 月份是从 0 开始计数的,需要加1
var day = today.getDate();
var hours = today.getHours();
var minutes = today.getMinutes();
var seconds = today.getSeconds();
// 格式化输出
var currentTime = year + "-" +
(month < 10 ? "0" : "") + month + "-" +
(day < 10 ? "0" : "") + day + "-" +
(hours < 10 ? "0" : "") + hours + ":" +
(minutes < 10 ? "0" : "") + minutes + ":" +
(seconds < 10 ? "0" : "") + seconds;
console.log(currentTime);
// 声明要执行的命令
let cmd = `cd ${rootPath}\n
mkdir -p ${rootFolder}_${currentTime}\n
cp -r /home/test /home/${rootFolder}_${currentTime}\n
`
conn.on('ready', function () {
conn.exec(cmd, function (err, stream) {
// 备份命令执行后
console.log(chalk.green('已执行备份命令'))
console.log('err====', err)
// console.log('stream====', stream)
if (err) throw err
console.log('123')
// 在执行命令行成功后上传文件到服务器上
stream.on('close', () => {
// 执行部署工作
// deployFile()
console.log('开始部署')
conn.end(); // 执行完部署后要执行这个
})
.on('data', (data) => {
console.log('STDOUT: ' + data);
}).stderr.on('data', (data) => {
console.log('STDERR:====== ' + data);
});
})
})
.on('error', function () {
console.log('chucuole ==========')
})
.connect({
host: server.host,
port: server.port,
username: server.username,
password: server.password
})
执行命令之前
执行命令之后
是把整个文件夹拷贝到新建的文件夹下