这是前端自动化部署方案一windows系统的姊妹篇Linux系统自动化部署解决方案,不得不说,Linux在这里的优势显而易见。

服务端

更新并升级安装源,安装ssh服务

1
2
3
sudo apt update
sudo apt upgrade
sudo apt-get install openssh-server

启动服务后,需要设置用户名密码

1
2
3
4
sudo service ssh start  启动服务
sudo service ssh stop 关闭服务
sudo service sshd reload [停止进程后重启] ==> 推荐
sudo service sshd restart [干掉进程后重启] ==> 不推荐

客户端

利用node-ssh进行SSH连接、文件传输、远程执行shell脚本,利用archiver执行文件压缩操作。

1.导入模块

1
2
3
4
const path = require('path');
const fs = require('fs');
const archiver = require('archiver');
const {NodeSSH} = require('node-ssh');

2.初始化ssh和配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const ssh = new NodeSSH();

const config = {
/**路径 */
path: {
romotePath: '/home/dalao/Projects/www',
localPath: './build'
},
/**压缩文件名 */
compressName: 'Compression.zip',
/**远程连接配置 */
romote: {
host: '10.0.0.87',
port: 22,
username: 'dalao',
password: '123456',
}
}

3.压缩文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const createZip = async () => {
try {
console.log('压缩中...')
return await new Promise((resolve, reject) => {
// 创建最终打包文件的输出流
const output = fs.createWriteStream(`${process.cwd()}/Compression.zip`)
// 生成archiver对象,打包类型为zip
const archive = archiver('zip', {
zlib: { level: 9 } // Sets the compression level.
});
output.on('close', (e) => {
if (e) {
console.log('压缩失败:' + e)
reject(e)
process.exit(1)
} else {
console.log('Compression.zip 打包成功')
resolve({code: 1, msg: '开始装载上传...'})
}
})
// 将打包对象与输出流关联
archive.pipe(output)
// 从子目录追加文件,将其内容放在archive的根目录
archive.directory(config.path.localPath, false)
// 结束archive
archive.finalize()
})
} catch (e) {
console.log('压缩失败:' + e)
process.exit(1)
}
}

4.远程部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/** 远程连接 */
const remoteConnect = () => {
return new Promise((resolve, reject) => {
ssh.connect(config.romote).then((result) => {
resolve({ code: 1})
}).catch((err) => {
reject(err)
});
})
}

/** 清除服务器缓存 */
const clearServer = () => {
return new Promise((resolve, reject) => {
ssh.execCommand(`rm -rf ${config.path.romotePath}/*`).then((result) => {
resolve({ code: 1})
}).catch((err) => {
reject(err)
});
})
}

/**上传文件夹(不用压缩包)*/
const uploadDir = () => {
return new Promise((resolve, reject) => {
ssh.putDirectory(config.path.localPath, config.path.romotePath).then((result) => {
resolve({ code: 1 })
}).catch((err) => {
reject(err)
});
})
}

/**上传压缩包 解压并删除压缩包 */
const uploadFileAndUnzip = (localPath, remotePath) => {
return new Promise((resolve, reject) => {
ssh.putFile(localPath, remotePath).then((result) => {
//@ 这里也可用用执行远程shell脚本替代
// #!/bin/bash
// cd /usr1/AAA/mydemo
// #删除原静态资源目录
// rm -rf public
// cd /usr1/AAA
// #解压新的包
// unzip public.zip
// #将解压出的public目录移动到服务端程序目录BBB中
// mv public ./mydemo
ssh.execCommand(`unzip ${config.compressName}; rm -rf ${config.compressName}`, { cwd: config.path.romotePath }).then((result) => {
resolve({ code: 1 })
}).catch((err) => {
reject(err)
});
}).catch((err) => {
reject(err)
});
})
}


async function main() {
const res = await createZip()
if(res['code'] === 1) {
const connectRes = await remoteConnect()
await clearServer()
console.log('远程连接中...')
if(connectRes['code'] === 1) {
console.log('连接成功,文件上传中...')
// const uploadRes = await uploadDir()
const uploadRes = await uploadFileAndUnzip(`./${config.compressName}`, `${config.path.romotePath}/${config.compressName}`)
if(uploadRes['code'] === 1) {
console.log('文件上传成功')
process.exit(1)
}
}
}
}
/** 执行主函数 */
main()