还不会自动化构建和部署?node来实现

502 阅读2分钟

       最近在开发中,经常接触到gitlab的自动化构建和部署。gitlab是如何实现这种自动化?自己能不能实现呢?带着这种思想,一步一步探索。

  • 喜欢的可以点赞和star噢,欢迎issuePR
  • 完整代码
  • 注意:不要在windows运行,-exec会报错

实现思路

  1. 监听文件变化
  2. 读取项目配置文件
  3. 执行项目配置命令,并替换变量

其中执行项目命令包括:

  1. 查找文件,替换特定字符串
  2. 安装依赖包
  3. 构建项目
  4. 复制私钥,使用scp免密上传,把构建文件上传到服务器
  5. 删除复制私钥
  1. 执行成功输出success, 失败删除私钥

开发准备

  • node.js: 使用child_process模块中的exec方法执行common, 使用fs模块中的readFile方法读取配置文件。
  • chokidar: 监听文件变动
  • lodash: 使用debounce 实现防抖
  • pm2:管理node项目
  • 服务器一台

服务器scp免密传输配置

  1. 安装ssh: yum install -y openssl openssh-server
  2. 开启ssh服务:

启动ssh的服务:
systemctl start sshd.service
设置开机自动启动ssh服务
systemctl enable sshd.service

  1. node代码运行终端上,生成私钥和秘钥ssh-keygen -t rsa -C "xxxxx@xxxxx.com"
  2. 把公钥内容放到服务器的/root/.ssh/authorized_keys文件中。

正式开发

1. 初始化chokidar 实现文件监听

// 初始化watcher
const watcher = chokidar.watch(watchPath,{
  awaitWriteFinish: {
    stabilityThreshold: 2000,
    pollInterval: 100
  },
  // 忽略的文件
  ignored: /node_modules|build|dist|\.pem|\.sed/,
  ignoreInitial: true, // 初始化不执行文件事件
  cwd: '.', // 表示当前目录
});

忽略监听 node_modulesbuilddist 文件的原因是:当执行安装依赖和构建的时候,会生成文件,从而触发文件监听事件。
.pem.sed是生成私钥文件和替换文件,所以也要被忽略。

2. 获取项目配置(类似gitlab的ci文件)

const getProjectConf = (path)=>{
  return new Promise((resolve, reject)=>{
    fs.readFile(path,(err, data)=>{
      let conf = {};
      if (err){
        log('yellow', `${path} file not find, use default conf`);
      }else {
        conf = JSON.parse(data);
      }
      resolve(conf);
    })
  })
};

// 获取配置
global.projectConf =  await getConf.getProjectConf(`${config.WATCH_PATH}/${config.PROJECT_CONF_NAME}`);

3. 执行项目配置命令

  • 在执行命令之前,我们需要把特定字符串替换的。格式为${your_string}
function commonReplaceString(common){
  const match = common.match(/\$\{([^]+?)\}/g);
  if (match){
    match.forEach(o=>{
      const current = o.replace(/\${|\}/g, '');
      try {
        const val  = config.REPLACE_STRINGS[current];
        if (val){
          o.replace(current,config.REPLACE_STRINGS[current]);
          common = common.replace(o,config.REPLACE_STRINGS[current]);
        }
      }catch (e) {
        console.log(e);
      }
    })
  }
  return common;
}
  • 正式执行命令
const commons = global.projectConf.commons;

// 不要用forEach 配合await执行命令,这样执行顺序不会如你所愿
for (const common of commons){
   await utils.execFn(utils.commonReplaceString(common))
}

看起来高大尚,其实使用node这部分核心代码就这点儿。

项目配置

{
  "commons": [
    "echo --- Replace string ---",
    "echo s/___TEST_STRING___/${TEST_STRING}/g > pattern.sed ",
    "find .  \\( -path \"./dist\" -o -path \"./node_modules\" \\)   -prune -o -type f   \\( -iname \"*.js\" -o -iname \"*.html\" -o -iname \"*.vue\" \\)  -print  -exec sed -i -f pattern.sed {} \\;",
    "rm -rf pattern.sed",
    "echo Replace success",
    "echo --- Install dependent ---",
    "yarn install",
    "echo --- Start build project ---",
    "npm run build",
    "echo --- Get primary key ---",
    "cat ${PRIVATE_KEY} > ${PRIVATE_KEY_FILE_NAME}",
    "chmod 600 ${PRIVATE_KEY_FILE_NAME}",
    "echo --- Start use scp upload files ---",
    "scp  -o StrictHostKeyChecking=no -i ${PRIVATE_KEY_FILE_NAME} -r dist/* ${SERVICE_USER}@${SERVICE_IP}:${SERVICE_PROJECT_PATH}",
    "rm -rf ${PRIVATE_KEY_FILE_NAME}",
    "echo --- Deploy success ---"
  ]
}
  • 以上命令因为是写在json文件仲,括号和”都需要转义

命令:"find . \\( -path \"./dist\" -o -path \"./node_modules\" \\) -prune -o -type f \\( -iname \"*.js\" -o -iname \"*.html\" -o -iname \"*.vue\" \\) -print -exec sed -i -f pattern.sed {} \\;"
大概意思是查找当前目录,忽略distnode_modules目录的所有jshtmlvue文件 并执行替换操作。

命令:cat ${PRIVATE_KEY} > ${PRIVATE_KEY_FILE_NAME}: 把私钥写入凭证文件
命令:scp -o StrictHostKeyChecking=no -i ${PRIVATE_KEY_FILE_NAME} -r dist/* ${SERVICE_USER}@${SERVICE_IP}:${SERVICE_PROJECT_PATH}: scp免密传输,关闭严格密钥检查,带上凭证文件,实现不需要用户确认直接登录,从而上传文件

总结

在很多人看来,现阶段都有gitlab-runnerjenkins那么成熟的工具,为什么还要去弄一个这样的东西。 在我看来,熟练的工具只是用,明其理才是自己的东西。主要的目的还是把别人的东西变成自己的!

最后附上一张结果图: