最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • WebHook结合GitHub Action与Coding实现博客持续集成部署到个人服务器

    正文概述 掘金(sssgoEasy)   2021-03-16   602

    WebHook结合GitHub Action与Coding实现博客持续集成部署到个人服务器

    前言

    什么是GitHub ActionGitHub Page

    • Github Action 可以帮助您自动完成软件开发周期内的任务,它是事件驱动的,而且已经和GitHub深度整合,可以运行很多GitHub事件,最普遍的是推送到master分支。但是actions并不仅仅只是部署和发布,它们都是容器,毫不夸张地说你可以做任何事情 —— 有着无尽的可能性!你可以用它们压缩合并CSSJavaScript,有人在你的项目仓库里创建issue的时候向你发送信息,以及更多……没有任何限制。

    • GitHub Page 是Github提供的一款免费的~,用于托管个人的静态网站,可以用它来搭建私人博客,也算是省去了购买服务器、域名等等一系列复杂的操作。

      规则:建立一个仓库命名为 用户名.github.io ,官方文档

      使用:仓库下创建一个index.html文件访问网址即可快速查看

    什么是Coding

    • CODING 系腾讯旗下全资子公司, 旗下一站式软件研发管理平台—CODING(coding.net/ )是一站式软件研发管理协作平台,提供 Git/SVN 代码托管、项目协同、测试管理、制品库、CI/CD 等一系列在线工具,帮助研发团队快速落地敏捷开发与 DevOps 开发方式,提升研发管理效率,实现研发效能升级。

    • Coding 想做的就是帮助开发者能够高效的在云端完成软件开发的工作。代码托管,项目管理,演示平台,质量管理等等都是为了帮助开发者在云端完成一系列高难度的软件开发动作。给开发者提供极致的云端开发体验,强调的是私有库,强调团队协作,强调整合体验,强调访问速度。

    • 为什么要用Coding

    什么是Webhook

    • Webhook是一个API概念,术语“网络钩子”,有时也被称为“反向 API”。因为他提供了API规则,你需要设计要使用的APIWebhook将向你的应用发起http请求,典型的是post请求,应用程序由请求驱动。我们能用事件描述的事物越多,webhook的作用范围也就越大。

    • 准确的说webhook是一种web回调或者http的push API,是向APP或者其他应用提供实时信息的一种方式。Webhook在数据产生时立即发送数据,也就是你能实时收到数据。使用 webhooks,您可以在服务器上发生某些事件时获得推送通知。你可以使用 webhooks“订阅”活动。

    需求及场景

    众所周知,GitHub作为全球最大同性交友社区,为了与大家更方便友好积极的交流 ?,我的源码存放地址是存放在GitHub的,内容包括博客的更新、一些测试用例、教程、Demo等。

    因为我的博客是部署在阿里云的个人服务器上,有时博客更新又比较频繁,一开始是通过ssh链接到服务器后然后通过命令git clonegit pullnpm run build 这种操作方法去手动进行更新,这里存在几个问题:

    1. 频繁登录服务器,非常繁琐
    2. GitHub 速度问题,每次更新都要等待很久
    3. 服务器性能问题,对于低配服务器执行 npm run build 打包很吃力

    思路及流程图

    思路

    1. 本地电脑通过git提交到GitHub仓库
    2. GitHub Action监听到push event事件触发ci.yml执行脚本
    3. build打包生成部署文件推送到GitHub gh-pages分支与Coding master分支
    4. Coding设置webhook监听push event事件触发webhook钩子
    5. webhook钩子通信到个人服务器内启动的http server,验证身份与仓库,执行webhook.sh脚本
    6. webhook.sh脚本cd进入nginx下的博客部署目录,进行git pull更新操作
    7. 根据结果生成日志,或添加邮件通知功能(结合Nodemailer库实现)

    流程图

    WebHook结合GitHub Action与Coding实现博客持续集成部署到个人服务器

    创建个人访问令牌 Access Token

    接下来自动化部署与持续集成会用到以https方式提交代码到仓库的方案,这里需要配置下access token个人访问令牌作为环境变量提供给Action与脚本使用。

    GitHub Token

    第一步,按照官方文档 ,生成一个github token (令牌)。

    第二步,将这个密钥储存到当前仓库的Settings/Secrets里面。

    Coding Token

    第一步,按照官方文档 ,生成一个coding token (令牌)。

    第二步,同 GitHub

    几种方案

    :::tip 这里示例几种我尝试过的方案,下面会仔细分析介绍每种方案的优劣,以及我逐渐改进与尝试的方法,和最终实现。 :::

    scp 命令直接部署到服务器

    主要思路

    通过使用scp命令直接把本地部署文件拷贝至远程服务器

    1. 本地进行npm run build打包编译,获得部署文件

    2. 直接通过上传替换源文件进行更新

      # 1. 该命令会把当前目录下的dist文件遍历上传到blog目录下:/blog/dist
      scp -r ./dist root@ip/usr/local/app/blog/
      # 2. 输入服务器密码,等待传输完成即可
      # 当然也可以通过ssh的方式无密码上传,但这并不能达到我的最终目的,这里不再赘述
      

    最终效果

    • 服务器编译的性能问题已解决
    • GitHub更新拉取速度慢的问题已解决
    • 每次更新执行打包编译、登录操作等步骤依旧繁琐

    GitHub Action Pages

    主要思路

    通过使用GitHub提供的PageAction服务实现gh-pages持续集成与部署

    通过动态生成gh-pages分支并推送到github仓库实现多地址部署

    如我的博客的GitHub地址:JS-banana.github.io/vuepress

    脚本编写

    1. 根目录下创建 .github>workflows>ci.yml

    2. ci.yml文件

      jobs: # 工作流
        build: # 自定义名称
        runs-on: ubuntu-latest #运行在虚拟机环境ubuntu-latest
      
        strategy:
          matrix:
          node-version: [14.x]
      
        steps: # 步骤
          - name: Checkout # 步骤1
          uses: actions/checkout@v1 # 使用的动作。格式:userName/repoName。
          #作用:检出仓库,获取源码。 官方actions库:https://github.com/actions
          - name: Use Node.js ${{ matrix.node-version }} # 步骤2
          uses: actions/setup-node@v1 # 作用:安装nodejs
          with:
            node-version: ${{ matrix.node-version }} # 版本
          - name: Deploy # 步骤3 部署到github gh-pages
          env: # 设置环境变量
            GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} # token私密变量
          run: |
            npm install
            npm run build
            cd ./dist
            git init
            git config user.name "name"
            git config user.email "email"
            git add .
            git commit -m "$(date) Update from Action"
            git push --force --quiet "https://JS-banana:${GITHUB_TOKEN}@github.com/JS-banana/vuepress.git" master:gh-pages
      
    3. 执行 echo 'ssscode.com' > CNAME 命令,生成 CNAME 文件,然后把CNAME文件放到生成的dist目录下,这一步可以通过bash脚本处理

    4. 我们再把上面的脚本调整下

      jobs: # 工作流
        build: # 自定义名称
        runs-on: ubuntu-latest #运行在虚拟机环境ubuntu-latest
      
        strategy:
          matrix:
          node-version: [14.x]
      
        steps: # 步骤
          - name: Checkout # 步骤1
          uses: actions/checkout@v1 # 使用的动作。格式:userName/repoName。
          #作用:检出仓库,获取源码。 官方actions库:https://github.com/actions
          - name: Use Node.js ${{ matrix.node-version }} # 步骤2
          uses: actions/setup-node@v1 # 作用:安装nodejs
          with:
            node-version: ${{ matrix.node-version }} # 版本
          - name: Deploy # 步骤3 部署到github gh-pages
          env: # 设置环境变量
            GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} # token私密变量
          run: npm install && npm run deploy
      
    5. 创建deploy.sh文件,并在package.json字段scripts下添加"deploy": "bash deploy.sh"命令

      #!/usr/bin/env sh
      
      # 确保脚本抛出遇到的错误
      set -e
      
      # date
      nowDate=$(date "+%Y-%m-%d %H:%M:%S")
      
      # 生成静态文件
      npm run build
      
      # 进入生成的文件夹
      cd ./dist
      
      # CNAME
      echo 'www.ssscode.com\ssscode.com' > CNAME  # 自定义域名
      
      # github url
      githubUrl=https://JS-banana:${GITHUB_TOKEN}@github.com/JS-banana/vuepress.git
      
      # 配置 git 用户信息
      git config --global user.name "JS-banana"
      git config --global user.email "sss213018@163.com"
      
      # commit
      git init
      git add -A
      git commit -m "deploy.sh===>update:${nowDate}"
      git push -f $githubUrl master:gh-pages # 推送到github
      
      cd - # 退回开始所在目录
      rm -rf ./dist
      
    • 到这一步,我们已经完成通过GitHub Action实现持续集成,打包生成部署文件并推送到gh-pages分支。

    Coding与GitHub同步部署

    这一步其实原理和上面GitHub Action Pages做法一样,而我们要做的最重要的一步,就是把Codingtoken也配置到GitHub仓库下的Settings/Secrets里面。即新增一个环境变量CODING_TOKEN,该方法同样适用于Gitee,想要使用Gitee的小伙伴也可以亲自尝试。

    ci.yml文件增加

    env: # 设置环境变量
      GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} # github token 私密变量
    + CODING_TOKEN: ${{ secrets.CODING_TOKEN }} # coding token 私密变量
    

    deploy.sh文件调整为

      # github url
      githubUrl=https://JS-banana:${GITHUB_TOKEN}@github.com/JS-banana/vuepress.git
    
    + # coding url
    + #注意!!!这里需要使用coding提供的个人令牌的用户名和token (https://[name]:[token]@e.coding.net/xx)
    + codingUrl=https://ptzv1yuleer1:${CODING_TOKEN}@e.coding.net/ssscode/blog/vuepress.git 
    
      git push -f $githubUrl master:gh-pages # 推送到github
    
    - cd - # 退回开始所在目录
    - rm -rf ./dist
      
    + git push -f $codingUrl master # 推送到coding
    
    + cd - # 退回开始所在目录
    + rm -rf ./dist
    

    Webhook与Coding实现持续部署

    实现思路

    首先,实现一个 nodejs http server用于接收请求,即 webhook.js钩子服务,这里我建议域名解析一个二级域名供webhook专门使用,如:webhook.ssscode.com,当然,直接在当前项目下以 /webhook 路径作为触发路由也可以。这里我们以第一种方案为例,使用nodejspm2守护程序启动webhook.js,然后再通过nginx反向代理本地启动的服务映射到 webhook.ssscode.com 即可。

    创建 webhook.js

    主要使用了NodeJs模块http(创建server) 与 child_process (执行bash脚本)

    废话不多说,直接上代码

    // webhook.js
    const server = require('http');
    const { spawn } = require('child_process');
    
    server
      .createServer((req, res) => {
        // accept request
        console.log(`accept request:${new Date()}`);
        // 接收POST请求
        if (req.method === 'POST') {
          //TODO: secret 验证
    
          let data = '';
    
          req.on('data', chunk => {
            data += chunk;
          });
    
          req.on('end', () => {
            // console.log(JSON.parse(data));
            try {
              const reqData = JSON.parse(data);
              // 确定身份
              if (reqData.pusher.username !== 'xxx') { // coding 个人访问令牌 Access Token 用户名
                res.writeHead(400);
                res.end('noooo!');
                return;
              }
              // 确定分支 master
              if (reqData.ref === 'refs/heads/master') {
                // 确定仓库
                const repository_name = reqData.repository.name;
                runCommand('sh', [`${repository_name}.sh`], console.log);
              }
              // response
              res.writeHead(200);
              res.end('ok');
            } catch (error) {
              console.log('error:', error);
              res.writeHead(500);
              res.end('error!');
            }
          });
        } else {
          res.writeHead(404);
          res.end('no info!');
        }
      })
      .listen(3010); // 端口
    
    // run command
    function runCommand(cmd, args, callback) {
      let response = '';
      const child = spawn(cmd, args);
      child.stdout.on('data', buffer => {
        response += buffer.toString();
      });
      child.stdout.on('end', () => callback(response));
    }
    

    核心代码是 runCommand 函数,server服务接收请求参数验证身份与仓库信息,满足条件执行对应脚本。这里没有像 github-webhook-handler 包一样对密匙进行处理验证,只是简单的验证了身份和条件。(github、coding等配置webhook时可以设置验证秘钥)

    接下来编写我们的bash脚本,这里之后可以优化成执行对应项目下的对应脚本(即 如果存在多个项目或博客,相关脚本在对应项目下创建,由bash执行)。

    创建bash脚本

    vuepress.sh核心代码

    #!/usr/bin/env sh
    # 确保脚本抛出遇到的错误
    set -e
    
    cd /usr/local/app/vuepress-blog/dist
    
    echo 'start===>git'
    
    # 覆盖更新
    git fetch --all
    git reset --hard origin/master
    # git clean -f
    # git pull
    
    cd - # 退回开始所在目录
    

    为了方便记录和查看以及拓展通知消息等,这里增加异常判断处理及日志输出

    - cd - # 退回开始所在目录
    
    + function log_info (){
    +   DATE_N=`date "+%Y-%m-%d %H:%M:%S"`
    +   USER_N=`whoami`
    +   echo "${DATE_N} ${USER_N} execute $0 [INFO] $@" >> /usr/local/app/webhook/logInfo.txt #执行成功日志打印路径
    + }
    
    + function log_error (){
    +   DATE_N=`date "+%Y-%m-%d %H:%M:%S"`
    +   USER_N=`whoami`
    +   echo -e "\033[41;37m ${DATE_N} ${USER_N} execute $0 [ERROR] $@ \033[0m"  >> /usr/local/app/webhook/logError.txt #执行失败日志打印路径
    + }
    
    + if [  $? -eq 0  ]
    + then
    +   log_info "$@ sucessed."
    +   echo -e "\033[32m $@ sucessed. \033[0m"
    + else
    +   log_error "$@ failed."
    +   echo -e "\033[41;37m $@ failed. \033[0m"
    +   exit 1
    + fi
    
    + trap 'fn_log "DO NOT SEND CTR + C WHEN EXECUTE SCRIPT !!!! "'  2
    
    + cd - # 退回开始所在目录
    

    创建nginx配置

    nginx配置

    server {
      #外网
      listen 80;
      server_name webhook.ssscode.com; #域名
    
      # 监听本地服务
      location / {
        # 开启反向代理
        proxy_pass http://127.0.0.1:3010/;
      }
    }
    

    执行 node ./webhook.js 即可启动测试~

    pm2

    为了更方便的管理NodeJs程序以及监控,这里推荐使用 pm2 start webhook.js 启动服务

    Github或Gitee结合webhook

    因为我采用的是Coding结合webhook的方式,如果有小伙伴对其他方式感兴趣,也可以自行搭建,原理类似,目前GithubGitee也有开源的npm包提供快速搭建webhook通信服务。github-webhook-handler、gitee-webhook-handler

    结语

    大功告成~

    总的来说就是反复尝试了很多方法,摸索找思路,再不断的改进,最终也是实现了当初的想法,不过也确实走了不少弯路。在此,把整个过程记录下来,供自己参考也为了加深理解,希望能帮到有需要的小伙伴,少走些弯路~

    如果自己全部配置各种服务与代码业务逻辑,也确实挺花费时间和精力的,涉及的技术点也比较杂,很多地方只能达到勉强使用,还差得远,整个过程也是边学习便尝试。不过,全部弄完之后,对于自己的技术成长与业务理解也是很有帮助的~

    类似Hexo这样的快速搭建博客的框架用起来倒是可以省不少事,感兴趣的可以尝试下,这个我也有在弄,不过还没达到我的预期效果,看看之后有没有可写的东西再分享分享吧

    之后对于Docker也是很有必要深入学习一番了~

    参考


    起源地下载网 » WebHook结合GitHub Action与Coding实现博客持续集成部署到个人服务器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元