Github Actions 尝鲜

介绍

Github Actions是 github 官方推出的一款 CI(持续集成)工具,目前还处于Beta版本,须要申请内测资格才能使用,申请成功以后在本身的代码仓库就能够看到Actions了。node

使用说明

这里简单介绍下 Github Actions中的概念,具体能够参考官方文档linux

术语

  1. workflow
    表示一次持续集成的过程
  2. job
    表示构建任务,每一个 workflow 能够由一个或者多个 job 组成,可支持并发执行 job,全部 job 执行完也就表明着 workflow 结束
  3. step
    每一个 job 由一个或多个 step 组成,按顺序依次执行
  4. action
    每一个 step 由一个或多个 action 组成,按顺序依次执行,这里 action 须要特别说明一下,action 是能够是自定义脚本或引用第三方的脚本,依赖着 github 开源社区,许多 action 均可以直接复用,无需本身编写,github 已经提供了一个action 市场,能够搜索到各类第三方 actions,而且官方也提供了许多 actions。

构建环境

每一个 job 均可以指定对应的操做系统,支持Windows、Linux、macOS,github 会提供一个虚拟机来执行对应的 job。git

硬件规格:github

  • 双核 CPU
  • 7GB 内存
  • 14GB 固态硬盘

使用限制:golang

  • 每一个仓库只能同时支持 20 个 workflow 并行
  • 每小时能够调用 1000 次 github API
  • 每一个 job 最多能够执行 6 个小时
  • 免费版的用户最大支持 20 个 job 并发执行,macOS 系统的话最大只支持 5 个

能够看到这个配置下,普通的项目持续集成确定没什么问题的。docker

构建记录

经过仓库中的Actions选项卡,能够看到项目中的 workflow 构建记录:
express

点击一条记录能够进入详情页面,能够实时查看每个action的控制台输出,方便调试:
npm

实例

前面大概介绍了一下基本的概念,下面就直接经过几个实例看看 Github Actions是如何使用的。ubuntu

自动部署 Hexo 博客到 Github Page

首先第一个想到能用到Github Actions的就是个人博客了,项目托管在https://github.com/monkeyWie/monkeywie.github.io,目前项目有两个分支,master分支用于存放 hexo 编译以后的静态文件,另外一个hexo分支用于存放 hexo 项目环境和 markdown 文章,master分支经过Github Page配置以后能够经过monkeywie.github.io域名访问。
windows

以前写完博客以后都是须要手动执行一遍命令进行部署:

hexo clean&&hexo d

而后再把hexo分支代码推送到 github 上

git push

在使用Github Actions以后,只须要把hexo分支代码推送到 github 上,剩下的所有交给Github Actions便可,在此以前咱们须要生成一对公私钥个用于 hexo 的部署操做,由于 hexo 自带的部署命令hexo d须要有 git 远程仓库读写权限。

ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:XG1vkchp5b27tteZASx6ZrPRtTayGYmacRdjjRxR1Y0 root@8fe85d51123b
The key's randomart image is:
+---[RSA 2048]----+
|             .+o=|
|           o *Eoo|
|          . X B .|
|       . . + X +.|
|        S . = O..|
|         o O B =.|
|          O = *.*|
|         o . o ++|
|              .oo|
+----[SHA256]-----+

先把~/.ssh/id_rsa.pub中的公钥添加到 Github 对应仓库的Deploye keys中:

再将~/.ssh/id_rsa中的私钥添加到 Github 对应仓库的Secrets中,Name 定义为ACTION_DEPLOY_KEY,目的是在构建的时候能够读取该私钥并配添加到虚拟机中,以获取 git 仓库访问权限:

准备工做完成后,接着就按照教程,在hexo分支建立.github/workflows/main.yaml文件用于配置 hexo 部署。

name: CI

on:
  push:
    branches:
      - hexo
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v1
        with:
          ref: hexo
      - name: Use Node.js ${{ matrix.node_version }}
        uses: actions/setup-node@v1
        with:
          version: ${{ matrix.node_version }}
      - name: Setup hexo
        env:
          ACTION_DEPLOY_KEY: ${{ secrets.ACTION_DEPLOY_KEY }}
        run: |
          mkdir -p ~/.ssh/
          echo "$ACTION_DEPLOY_KEY" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan github.com >> ~/.ssh/known_hosts
          git config --global user.email "liwei2633@163.com"
          git config --global user.name "monkeyWie"
          npm install hexo-cli -g
          npm install
      - name: Hexo deploy
        run: |
          hexo clean
          hexo d

具体的配置语法这里就不详细说明了,能够自行在官方文档中查阅。

构建流程以下:

  1. 监听hexo分支的 push 操做
  2. 运行一个 job,在ubuntu虚拟机环境下
  3. 使用官方提供的actions/checkout@v1来拉取源码
  4. 使用官方提供的actions/setup-node@v1来安装 node 环境
  5. 使用 ${{ secrets.ACTION_DEPLOY_KEY }}读取刚刚生成的私钥,并设置成环境变量,${{ exp }}写法为 actions 内置的表达式语法,详细文档参考:contexts-and-expression-syntax-for-github-actions
  6. 将私钥写入到~/.ssh/id_rsa文件中,并把github.com域名加入到~/.ssh/known_hosts文件中,以避免第一次 ssh 访问时弹出交互式命令。
  7. 配置 git 用户信息
  8. 安装 hexo 命令行工具和项目的依赖
  9. 调用 hexo 命令进行部署

hexo分支代码推到 github 上触发 workflow ,经过Actions选项卡进入就能够看到项目的构建状况了。

至此改造完成,之后只须要写完文章直接提交代码就能够自动部署了,甚至均可以不装 node 环境进行写做简直不要太方便。

自动建立项目 Release

有些项目在发布新版本时,通常都会建立一个Github Release,而且把对应编译好以后的文件上传到Release的资源列表中,例如:

若是这个使用手动操做的话,不只步骤重复又繁琐(每次都要编译出各个操做系统对应的发行包再进行上传),并且最蛋疼的是对于国内的网络环境来讲,上传文件速度简直不能忍,好不容易上传了一大半搞很差就由于网络缘由又要从新上传,相信用过的人都深有体会。

我就在想若是能用Github Actions来建立Release,而且作对应的编译和上传,那上面的问题均可以迎刃而解了,因而在官方市场搜索了一下Release关键字,果真已经有提供对应的actions了:

接着建立一个Github仓库,我测试的仓库地址是https://github.com/monkeyWie/github-actions-demo,项目用 go 语言写的,代码很是简单就是两个 hello world 级别的代码,里面包含了普通的 go 程序和 cgo 程序。

项目的构建流程是在项目git push --tags的时候,触发 workflow,经过Github Actions编译出来Windows、Linux、macOS三个操做系统对应的 64 位可执行文件,再根据tag nametag message来建立对应的Github Release,并将编译好的文件上传。

一样的建立一个.github/workflows/main.yml文件,内容以下:

name: CI

on:
  push:
    # Sequence of patterns matched against refs/tags
    tags:
      - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v1
      - name: Use Golang
        uses: actions/setup-go@v1
        with:
          go-version: "1.13.x"
      - name: Build normal
        run: |
          CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o normal-windows-x64.exe cmd/normal/main.go
          CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o normal-linux-x64 cmd/normal/main.go
          CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o normal-darwin-x64 cmd/normal/main.go
          zip normal-windows-x64.zip normal-windows-x64.exe
          zip normal-linux-x64.zip normal-linux-x64
          zip normal-darwin-x64.zip normal-darwin-x64
      - name: Build cgo
        run: |
          go get github.com/monkeyWie/xgo
          ~/go/bin/xgo -targets=windows/amd64,linux/amd64,darwin/amd64 -ldflags="-w -s" -pkg=cmd/cgo/main.go -out=cgo .
          mv cgo-windows-* cgo-windows-x64.exe
          mv cgo-linux-* cgo-linux-x64
          mv cgo-darwin-* cgo-darwin-x64
          zip cgo-windows-x64.zip cgo-windows-x64.exe
          zip cgo-linux-x64.zip cgo-linux-x64
          zip cgo-darwin-x64.zip cgo-darwin-x64
      - name: Create Release
        id: create_release
        uses: monkeyWie/create-release@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false

      - name: Upload Release normal windows
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
          asset_path: ./normal-windows-x64.zip
          asset_name: normal-${{ steps.create_release.outputs.tag }}-windows-x64.zip
          asset_content_type: application/zip
      - name: Upload Release normal linux
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
          asset_path: ./normal-linux-x64.zip
          asset_name: normal-${{ steps.create_release.outputs.tag }}-linux-x64.zip
          asset_content_type: application/zip
      - name: Upload Release normal darwin
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
          asset_path: ./normal-darwin-x64.zip
          asset_name: normal-${{ steps.create_release.outputs.tag }}-darwin-x64.zip
          asset_content_type: application/zip

      - name: Upload Release cgo windows
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
          asset_path: ./cgo-windows-x64.zip
          asset_name: cgo-${{ steps.create_release.outputs.tag }}-windows-x64.zip
          asset_content_type: application/zip
      - name: Upload Release cgo linux
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
          asset_path: ./cgo-linux-x64.zip
          asset_name: cgo-${{ steps.create_release.outputs.tag }}-linux-x64.zip
          asset_content_type: application/zip
      - name: Upload Release cgo darwin
        uses: actions/upload-release-asset@v1.0.1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
          asset_path: ./cgo-darwin-x64.zip
          asset_name: cgo-${{ steps.create_release.outputs.tag }}-darwin-x64.zip
          asset_content_type: application/zip

构建流程以下:

  1. 监听 tag name 为v开头的 push
  2. 运行一个 job,在ubuntu虚拟机环境下
  3. 拉取源码,安装golang 1.13.x环境
  4. 使用go build交叉编译出不一样操做系统下 64 位可执行文件,并使用 zip 压缩
  5. 使用xgo交叉编译出不一样操做系统下 64 位可执行文件,并使用 zip 压缩
  6. 使用monkeyWie/create-release@master建立 Release,其中会用到${{ secrets.GITHUB_TOKEN }},这是Github Actions内置的一个秘钥,用于受权访问你本身的 github 存储库,原理就是使用这个TOKEN调用Github API来进行建立 release,还有一个${{ github.ref }}也是Github Actions内置的一个变量,而后经过 action 的with进行参数传递。
  7. 使用actions/upload-release-asset@v1.0.1上传文件,这里使用了两个表达式${{ steps.create_release.outputs.upload_url }}${{ steps.create_release.outputs.tag }},能够获取到指定action的输出,第一个是获取建立好的 release 对应的上传地址,第二个是获取对应的 tag(例如:v1.0.0),这样就能够在把上传的文件带上版本号。由于这个action不支持多个文件上传,因此就写了多个 action 进行上传。

接下来在项目打个tag,而后push上去看看效果:

# 建立tag名为v1.0.8,并添加描述
git tag -a "v1.0.8" -m '发布v1.0.8版本
修复了如下bug:
1. xxxxx
2. xxxxx'
# 把tag推到github上
git push --tags

而后就能够看到已经有一个新的workflow正在运行了:

运行完成后在Releases页面查看结果:

完美!和预想的结果一致。

注:因为官方的 create-release有点不能知足需求,因而我本身 fork了一份 create-release代码,就是把 tag name给输出来了,这里是相关的 PR,还没被合并,因此上面的建立 Release 的 action 是用的我本身的仓库 monkeyWie/create-release@master,还有关于 go 交叉编译的知识,有兴趣能够看看个人这篇博客: go-cross-compile

自动构建和部署 docker 镜像

Github Actions提供的虚拟机中,已经内置了docker,而恰好我有一个项目由于国内的网络缘由构建docker镜像很是的慢,这是我fork的一个用于 go 项目交叉编译的项目,仓库地址https://github.com/monkeyWie/xgo,这个项目的主要工做原理就是经过 docker 里内置好各类交叉编译的工具链,而后对外提供 go 项目交叉编译功能,下面节选一点Dockerfile内容:

看这大量的apt-get install,就知道在本地构建有多慢了,下面就改用Github Actions来帮忙构建和部署镜像。

因为要将镜像推送到docker hub官方镜像仓库上,须要验证帐号信息,
这里我把本身的用户密码配置到了Secrets中,以便在 workflow 配置文件中能够访问到:

编写构建文件.github/workflows/main.yml

name: CI

on:
  push:
    branches:
      - master
    paths:
      - "docker/base/*"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source
        uses: actions/checkout@v1
      - name: Docker login
        run: docker login -u liwei2633 -p ${{ secrets.DOCKER_HUB_PWD }}
      - name: Docker build base
        run: |
          docker pull liwei2633/xgo:base
          docker build --cache-from=liwei2633/xgo:base -t liwei2633/xgo:base ./docker/base
          docker push liwei2633/xgo:base
      - name: Docker build other
        run: |
          docker build -t liwei2633/xgo:go-1.12.10 ./docker/go-1.12.10
          docker push liwei2633/xgo:go-1.12.10
          docker build -t liwei2633/xgo:go-1.12.x ./docker/go-1.12.x
          docker push liwei2633/xgo:go-1.12.x
          docker build -t liwei2633/xgo:go-1.13.1 ./docker/go-1.13.1
          docker push liwei2633/xgo:go-1.13.1
          docker build -t liwei2633/xgo:go-1.13.x ./docker/go-1.13.x
          docker push liwei2633/xgo:go-1.13.x
          docker build -t liwei2633/xgo:go-latest ./docker/go-latest
          docker push liwei2633/xgo:go-latest

构建流程以下:

  1. 监听 master 分支的 push 操做,而且docker/base目录下文件有修改才进行构建,这样作的目的是在其它与 docker 构建无关的文件改动了不会去触发 workflow
  2. 运行一个 job,在ubuntu虚拟机环境下
  3. 拉取源码
  4. 登陆 docker hub,经过以前配置的${{ secrets.DOCKER_HUB_PWD }},这里不用担忧控制台输出会暴露密码,经过secrets访问的变量在控制台输出时都会打上马赛克
  5. 构建镜像,这里使用了一个小技巧--cache-from=liwei2633/xgo:base,预先下载好以前的镜像liwei2633/xgo:base,而后可使用docker的缓存机制加快构建速度
  6. 推送镜像并编译和推送不一样 go 版本的镜像

这样经过Github Actions就把构建镜像和部署时间的缩小了到了13分钟

虽然仍是挺慢的可是跟本地构建比起来快了不是一个量级,有次本地构建等了一个多小时,由于网络缘由致使一个软件源安装失败直接没了又要重头开始构建,因此高下立判,Github Actions真香!!

后记

经过上面三个实例项目,能够看得出Github Actions为咱们节省大量的时间和重复的操做,且经过官方的 actions 市场很方便的就能够实现大部分编排功能,真是一个能够吹爆的良心产品,因此赶忙一块儿来尝鲜啊。

相关文章
相关标签/搜索