yj-deploy 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +67 -1
  2. package/lib/main.js +146 -4
  3. package/package.json +4 -2
package/README.md CHANGED
@@ -11,6 +11,8 @@
11
11
  - ✔ 支持灵活配置dockerfile,upload.sh等脚本内容
12
12
  - ✔ 支持多种方式配置 `镜像仓库` `镜像环境`等参数
13
13
  - ✔ 支持懒上传,仅上传新增部分文件,提升上传效率
14
+ - ✔ 支持失败自动重新上传,支持配置次数,防止网络不稳定可能导致上传失败
15
+ - ✔ 镜像推送成功支持自动重启服务,减少部署流程
14
16
  > 全程不需要连接跳板机做任何操作即可完成镜像推送
15
17
 
16
18
  ## 运行情况
@@ -74,7 +76,12 @@ const deploy = new yjDeploy({
74
76
  'echo "- 镜像环境: $2"',
75
77
  'docker build -t harbor.yunjingtech.cn:30002/$1/$tag .',
76
78
  'docker push harbor.yunjingtech.cn:30002/$1/$tag',
79
+ 'if [ $? -eq 0 ];then',
80
+ 'echo - 推送成功',
77
81
  'echo - 镜像地址: harbor.yunjingtech.cn:30002/$1/$tag',
82
+ 'else',
83
+ 'echo - 镜像推送失败,请重试或联系运维人员,如需查看全部docker日志,请在命令后添加 --allLog查看更多信息',
84
+ 'fi',
78
85
  ]
79
86
  },
80
87
 
@@ -89,9 +96,49 @@ const deploy = new yjDeploy({
89
96
 
90
97
  allLog: false, // 是否打印所有log信息,主要是包含推送镜像阶段的日志,如果报错可以打开此开关
91
98
 
92
- lazyUpload: false // 是否开启懒上传,针对小程序图片等仅需要部署新增部分文件的项目有奇效
99
+ lazyUpload: false, // 是否开启懒上传,针对小程序图片等仅需要部署新增部分文件的项目有奇效
100
+
101
+ rePushNum: 3, // 重新推送次数,为0代表不重新推送
102
+
103
+ // 自动重启服务的rancher配置
104
+ rancherConfig: {
105
+ token: '', // Rancher API 访问令牌 (必填)
106
+ namespace: '', // 服务所在的命名空间 (必填)
107
+ workload: '', // 服务名称 (必填)
108
+
109
+ // 非必填
110
+ baseUrl: '', // Rancher API 基础地址
111
+ clusterId: '', // Rancher 集群 ID
112
+ }
113
+ }
114
+ ```
115
+
116
+
117
+ ## rancher配置说明
118
+ 需要自动重启服务时,必须配置如下内容,然后在命令后加上`--restart`即可启用自动重启功能(因为仅开发环境支持,所以启用命令只能通过加在命令行里)
119
+ ```js
120
+ rancherConfig: {
121
+ token: '', // Rancher API 访问令牌 (必填)
122
+ namespace: '', // 服务所在的命名空间 (必填)
123
+ workload: '', // 服务名称 (必填)
124
+
125
+ // 非必填
126
+ baseUrl: '', // Rancher API 基础地址
127
+ clusterId: '', // Rancher 集群 ID
93
128
  }
94
129
  ```
130
+ ### token
131
+ 需要在rancher主页 -> 个人中心 -> API & Keys 内创建永久key,也可以复制其他已有项目里的token使用
132
+
133
+ ### namespace
134
+ 服务所在的命名空间 (必填)
135
+
136
+ ### workload
137
+ 服务名称 (必填)
138
+ ![服务名称](./img2.png)
139
+
140
+ ### baseUrl clusterId
141
+ 非必填,已默认配置为开发环境地址,除非运维更换rancher地址与集群id,否则不用配置
95
142
 
96
143
  <br />
97
144
 
@@ -248,6 +295,19 @@ node uploader.js --tmpName=test
248
295
  如果小程序修改了相同路径和文件名的文件,会存在无法判断的情况(使用hash值能判断,但是成本过高),这种情况请关掉此选项,或使用 --reset 重置项目
249
296
  :::
250
297
 
298
+ ### --restart
299
+ `--restart` :是否需要自动重启服务,加上此命令,且配置了rancherConfig,将会自动重启服务
300
+ ```javascript
301
+ "scripts": {
302
+ // 开发环境
303
+ "deploy": "vite build --mode development -- --deploy --tmpName=dev --restart"
304
+ }
305
+ ```
306
+
307
+ ::: warning
308
+ 仅对开发环境生效,并且需要先在rancher创建服务后方能成功
309
+ :::
310
+
251
311
 
252
312
  <br />
253
313
 
@@ -260,6 +320,12 @@ node uploader.js --tmpName=test
260
320
 
261
321
  ## 升级日志
262
322
 
323
+ ### v0.0.9
324
+ 支持自动重启服务,上传完后,可以根据配置自动重启rancher服务
325
+
326
+ ### v0.0.8
327
+ 支持判断是否推送成功,如果推送失败,则自动重试三次,可以手动配置重试次数
328
+
263
329
  ### v0.0.6
264
330
  支持懒上传文件,大幅提升上传速度
265
331
 
package/lib/main.js CHANGED
@@ -2,6 +2,8 @@ import { stdout } from 'single-line-log'
2
2
  import fs from 'fs'
3
3
  import path from 'path'
4
4
  import { Client } from 'ssh2'
5
+ import axios from 'axios'
6
+ import https from 'https'
5
7
 
6
8
 
7
9
  export default class yjDeploy {
@@ -39,7 +41,12 @@ export default class yjDeploy {
39
41
  'echo "- 镜像环境: $2"',
40
42
  'docker build -t harbor.yunjingtech.cn:30002/$1/$tag .',
41
43
  'docker push harbor.yunjingtech.cn:30002/$1/$tag',
44
+ 'if [ $? -eq 0 ];then',
45
+ 'echo - 推送成功',
42
46
  'echo - 镜像地址: harbor.yunjingtech.cn:30002/$1/$tag',
47
+ 'else',
48
+ 'echo - 镜像推送失败,请重试或联系运维人员,如需查看全部docker日志,请在命令后添加 --allLog查看更多信息',
49
+ 'fi',
43
50
  ]
44
51
  },
45
52
 
@@ -54,7 +61,16 @@ export default class yjDeploy {
54
61
 
55
62
  allLog: false, // 是否显示全部日志
56
63
 
57
- lazyUpload: false // 是否开启懒上传
64
+ lazyUpload: false, // 是否开启懒上传
65
+
66
+ rePushNum: 3, // 重新推送次数,为0代表不重新推送
67
+
68
+ // 仅能通过命令启用
69
+ rancherConfig: {
70
+ token: '', // Rancher API 访问令牌
71
+ namespace: '', // 服务所在的命名空间
72
+ workload: '', // 工作负载名称
73
+ }
58
74
  }
59
75
 
60
76
  ssh2Conn = null
@@ -280,6 +296,10 @@ export default class yjDeploy {
280
296
  * @param {*} dir
281
297
  */
282
298
  upLoadProject(sftp, dir) {
299
+ let rePushNum = 0 // 如果推送失败,是否开启重新推送,如果大于0 ,代表重新推送次数
300
+ if(typeof this.config.rePushNum === 'number' && this.config.rePushNum > 0) {
301
+ rePushNum = this.config.rePushNum
302
+ }
283
303
  sftp.readdir(dir, async (err) => {
284
304
  if (err) {
285
305
  // 不存在目录
@@ -438,14 +458,42 @@ export default class yjDeploy {
438
458
  const tmpName = this.getArgv('--tmpName') || this.config.tmpName
439
459
  shell += ` ${tmpName}`
440
460
 
441
- const imagePath = await this.onShell(shell) // 推送镜像
442
- console.log(imagePath) // 推送镜像脚本返回输出
443
- console.log('- 镜像推送完成')
461
+ // 判断如果失败,是否需要多次重试
462
+ const pushShellList = Array.from(new Array(rePushNum + 1)).map(() => this.onShell(shell))
463
+ await this.pushMirrorImage(pushShellList, pushShellList.length) // 开始推送镜像
444
464
 
445
465
  this.breakConnect()
446
466
  })
447
467
  }
448
468
 
469
+ // 推送镜像
470
+ async pushMirrorImage(shellList, totalNum) {
471
+ if (shellList.length === 0) {
472
+ console.log('- 镜像推送失败,请添加 --allLog 查看全部日志')
473
+ return null
474
+ }
475
+
476
+ const result = await shellList[0]
477
+
478
+ if(!result.includes('- 镜像推送失败')) {
479
+ // 推送成功
480
+ console.log(result) // 推送镜像脚本返回输出
481
+ console.log('- 镜像推送结束')
482
+
483
+ if(this.getArgv('--restart') !== undefined) {
484
+ await restartService(result, this.config.rancherConfig)
485
+ }
486
+
487
+ return result
488
+ }
489
+
490
+ console.log(result) // 失败日志
491
+ if(shellList.length > 1) {
492
+ console.log(`- 正在尝试第 ${(totalNum - shellList.length) + 1} 次推送...`)
493
+ }
494
+ return this.pushMirrorImage(shellList.slice(1), totalNum)
495
+ }
496
+
449
497
  /**
450
498
  * 获取脚本内容是不是自动创建的脚本
451
499
  * 兼容用户手动根据运维文档创建的推送脚本,因参数不同可能报错的问题
@@ -459,6 +507,11 @@ export default class yjDeploy {
459
507
  }
460
508
 
461
509
  const fileText = data.toString()
510
+
511
+ // 判断脚本是不是最新的支持异常提示脚本,自动重试的脚本
512
+ if(!fileText.includes('- 镜像推送失败')) {
513
+ console.log('\n- warning 检测到当前脚本可能不是最新版本,推送失败可能不会提示,且没有失败自动重试功能,请在命令后添加 --reset 重新生成脚本')
514
+ }
462
515
  resolve(fileText.includes('$2'))
463
516
  })
464
517
  })
@@ -558,3 +611,92 @@ export default class yjDeploy {
558
611
  return result
559
612
  }
560
613
  }
614
+
615
+ const httpsAgent = new https.Agent({
616
+ rejectUnauthorized: false
617
+ })
618
+
619
+ const axiosInstance = axios.create({
620
+ proxy: false
621
+ })
622
+
623
+ async function restartService(imageData, config) {
624
+ try {
625
+ const localConfig = {
626
+ baseUrl: 'https://paas-test.ymygz.com:10443/v3',
627
+ clusterId: 'local:p-r7j28'
628
+ }
629
+
630
+ const rancherConfig = {
631
+ ...localConfig,
632
+ ...config
633
+ }
634
+
635
+ if (!rancherConfig.baseUrl) {
636
+ return console.error('- Rancher API 基础地址未配置,请检查 rancherConfig.baseUrl 是否正确')
637
+ }
638
+ if (!rancherConfig.token) {
639
+ return console.error('- Rancher API 访问令牌未配置,请检查 rancherConfig.token 是否正确')
640
+ }
641
+ if (!rancherConfig.clusterId) {
642
+ return console.error('- Rancher 集群 ID 未配置,请检查 rancherConfig.clusterId 是否正确')
643
+ }
644
+ if (!rancherConfig.namespace) {
645
+ return console.error('- 服务所在的命名空间未配置,请检查 rancherConfig.namespace 是否正确')
646
+ }
647
+ if (!rancherConfig.workload) {
648
+ return console.error('- 工作负载名称未配置,请检查 rancherConfig.workload 是否正确')
649
+ }
650
+ if (!imageData) {
651
+ return console.error('- 内部错误')
652
+ }
653
+
654
+ const match = imageData.match(/- 镜像地址:\s*(.+)/)
655
+ let imageAddress = ''
656
+ if (match && match[1]) {
657
+ imageAddress = match[1].trim()
658
+ } else {
659
+ return console.error('- 未提取到镜像地址')
660
+ }
661
+
662
+ console.log('- 开始调用 Rancher API 更新服务镜像地址')
663
+ const workloadUrl = `${rancherConfig.baseUrl}/projects/${rancherConfig.clusterId}/workloads/deployment:${rancherConfig.namespace}:${rancherConfig.workload}`
664
+ console.log('- 请求的工作负载 URL:', workloadUrl)
665
+
666
+ const response = await axiosInstance.get(workloadUrl, {
667
+ headers: { Authorization: `Bearer ${rancherConfig.token}` },
668
+ httpsAgent
669
+ })
670
+
671
+ if (!response.data || !response.data.containers || response.data.containers.length === 0) {
672
+ return console.error('- 未找到工作负载的容器信息,请检查 namespace 和 workload 是否正确')
673
+ }
674
+
675
+ const workload = response.data
676
+ workload.containers[0].image = imageAddress
677
+
678
+ await axiosInstance.put(workloadUrl, workload, {
679
+ headers: { Authorization: `Bearer ${rancherConfig.token}` },
680
+ httpsAgent
681
+ })
682
+
683
+ console.log('- 镜像地址更新成功,正在重启服务...')
684
+ await axiosInstance.post(
685
+ `${workloadUrl}?action=redeploy`,
686
+ {},
687
+ {
688
+ headers: { Authorization: `Bearer ${rancherConfig.token}` },
689
+ httpsAgent
690
+ }
691
+ )
692
+
693
+ console.log('- 服务重启成功')
694
+ } catch (error) {
695
+ console.error('- 调用 Rancher API 失败,请检查以下信息:')
696
+ console.error(' - 错误代码:', error.code)
697
+ console.error(' - 错误信息:', error.message)
698
+ console.error(' - 请求 URL:', error.config?.url)
699
+ console.error(' - 响应状态:', error.response?.status)
700
+ console.error(' - 响应数据:', error.response?.data)
701
+ }
702
+ }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "yj-deploy",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "ssh sftp",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "vite build"
7
+ "build": "vite build",
8
+ "deploy": "node test.js --restart"
8
9
  },
9
10
  "files": [
10
11
  "lib",
@@ -16,6 +17,7 @@
16
17
  "author": "",
17
18
  "license": "ISC",
18
19
  "dependencies": {
20
+ "axios": "^1.13.5",
19
21
  "single-line-log": "^1.1.2",
20
22
  "ssh2": "^1.15.0"
21
23
  },