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 市場很方便的就能夠實現大部分編排功能,真是一個能夠吹爆的良心產品,因此趕忙一塊兒來嚐鮮啊。

相關文章
相關標籤/搜索