• 利用 Github 网络钩子实现自动化部署


    GitHub 的网络钩子(webhook)功能,可以很方便的实现自动化部署。本文记录了使用 Node.js 的开发部署过程,当项目的 master 分支被推时,将在服务器进行自动部署,完整代码见 GitHub

    添加网络钩子

    1. 在 GitHub 的相应项目首页,点击右上角菜单 Setting, 点击左侧菜单 Webhooks,点击右上角按钮 Add webhook

    2. 设置 Payload URL 为接收事件的地址,Content type 建议选择 applicaiton/jsonSecret 可选填任意字符串,Which events would you like to trigger this webhook? 设为 Just the push event.,勾选 Active,点击下方的 Add webhook 按钮

    开发处理请求

    接收请求

    使用 Node.js 建立一个 http 服务器,接收 POST 请求并处理其提交数据

    const { createServer } = require('http');
    const port = process.env.GITHUB_WEBHOOK_PORT || '3000';
    
    const server = createServer((req, res) => {
      if('POST' === req.method){
        let body = '';
        req.on('data', chunk => {
          body += chunk.toString();
        });
        req.on('end', () => {
        });
      }
    })
    
    server.listen(port, () => {
      console.log(`Listening on ${port}`);
    });
    

    如果需要更改默认端口 3000,可以先运行以下命令添加环境变量(NUMBER 为任意端口)

    export GITHUB_WEBHOOK_PORT=NUMBER

    解析 Body

    在 req 的 end 事件处理器中,把字符串 body 解析成对象

        req.on('end', () => {
          try{
            body = JSON.parse(decodeURIComponent(body).replace(/^payload=/, ''));
          }catch(e){
            console.log(e)
          }
    

    如果 Content type 设置为 applicaiton/json,只需要 body = JSON.parse(body) 即可,以上代码兼容了 Content type 设置为 application/x-www-form-urlencoded 的情况

    拉取更新

    根据 body 的 push 负载,提取项目和分支信息,如果是 master 分支,则执行进入对应项目,拉取分支的命令

          if('object' === typeof body){
            if('refs/heads/master' === body.ref){
              const { exec } = require('child_process');
              const command = `cd ../${body.repository.name} && git pull origin master`;
              exec(command, (error, stdout, stderr) => {
              });
    

    注意这里的项目所在的目录,与此应用所在的目录,是在同一个父目录下的,如果不是可以相应调整命令的进入路径

    验证密钥

    以上步骤已经实现了自动拉取更新,不过存在安全性的问题,因为不仅仅 GitHub 可以发送这样的请求,所以最好设置 Secret 以进行安全验证

    const secret = process.env.GITHUB_WEBHOOK_SECRET || '';
    ...
        req.on('end', () => {
          if('' !== secret){
            const { createHmac } = require('crypto');
            let signature = createHmac('sha1', secret).update(body).digest('hex');
            if(req.headers['x-hub-signature'] !== `sha1=${signature}`){
              console.log('Signature Error');
              res.statusCode = 403;
              res.end();
              return;
            }
          }
    

    运行应用前,先运行以下命令增加密钥变量(STRING 为任意字符串)

    export GITHUB_WEBHOOK_SECRET=STRING

    • 设置了 Secret 后,GitHub 在发送请求时,会在请求头增加 x-hub-signature 为 sha1=SIGNATURE, 其中 SIGNATURE 为 body 的 密钥为 Secret,算法为 sha1 的 HMAC 16 进制值
    • 通过对 Secret 的检验,可以确保只有知道了 Secret,才能发送正确的带 x-hub-signature 头的请求,否则将拒绝请求
    • 以上代码兼容了不设置 Secret 的情况,即如果没有增加变量 GITHUB_WEBHOOK_SECRET,则按原有逻辑处理,不会进行检验

    本地钩子构建

    如果项目在拉取更新后需要构建,那么可以 command 变量后面加上构建命令,例如 && npm run build,但是不同项目的构建命令有可能是不一样的,而且有的项目的构建命令可能还比较复杂,这些情况下可以通过设置 git 的本地钩子进行处理

    cd /PATH/TO/PROJECT/.git/hooks
    nano post-merge

    #!/bin/sh
    SHELL_SCRIPT
    

    chmod +x post-merge

    • 其中 /PATH/TO/PROJECT/ 为项目的目录位置,SHELL_SCRIPT 可以为任意 Shell 脚本
    • 因为 git pull 是 git fetch 和 git merge 的组合,所以拉取更新会触发 post-merge 钩子
    • 默认新增的文件是没有执行权限的,所以需要通过 chmod 增加 x

    部署应用上线

    应用部署上线需要实现持久化和自动化,即项目应该一直在运行,如果服务器重启,项目应该自动启动

    变量自动创建

    /etc/profile.d/ 里的变量创建脚本会在服务器重启时自动运行,所以添加一个设置脚本进去

    nono /etc/profile.d/github-webhook.sh

    export GITHUB_WEBHOOK_PORT=NUMBER
    export GITHUB_WEBHOOK_SECRET=STRING
    

    运行以下命令可以使变量创建马上生效

    source /etc/profile

    pm2 运行应用

    pm2 可以确保 Node 应用的持续运行,并可通过配置实现监控和热更新等功能

    npm install pm2 -g
    pm2 start app.js --name github-webhook

    重启自动运行

    pm2 还内置支持配置自启动原有应用,通过以下命令实现

    pm2 startup
    pm2 save

    pm2 startup 会创建并开启开机自动运行的服务, pm2 save 会保存当前的 pm2 运行应用,作为重启后的恢复内容

    总结

    在基于 GitHub webhook 的自动化部署中,主要使用了以下技术:

    • Node.js 的 http,child_process 和 crypto 模块
    • Git 的 post-merge Shell 钩子
    • profile 的自动变量设置和 pm2 工具
  • 相关阅读:
    Firefox for macOS 标签关闭按钮设置在左侧
    Nginx 非编译安装 stream 模块实现四层负载均衡
    苹果手机卡死,强制关机方法
    Git安装完成,文件夹下右键菜单不出现出现Git Bash Here 和Git UI Here问题
    AESUtil
    若依框架清空select2选择
    RSAUtils
    springboot 延时任务
    Mqtt的坑,真的坑
    springboot 支付宝支付业务网页端扫码
  • 原文地址:https://www.cnblogs.com/chanvin/p/automatically-deploy-by-github-webhook.html
Copyright © 2020-2023  润新知