前言

在公司幫忙弄 Jenkins + Gerrit 的 Infra 一陣子了,現在對於 CI/CD 頗有心得

延伸閱讀:What is CI/CD By ATLASSIAN

從去年開始我就一直想試試看 Github 的 CI/CD 新功能,可是手上的 repo 並沒有什麼需要做 CI/CD 的範例,唯一能想到的只有這個 GitHub Action 自動部署 Hexo 😁

差不多在過年前,被朋友找去幫忙一個 Web 的 Side project,興起了乾脆在他的 Github Repo 導入 Github Actions 玩看看的念頭,順便改善一下整體的 Infra flow

這篇只會簡單介紹怎麼啟用跟加入基本的 Linter & Build 範例做 CI

有時間會寫怎麼跟 AWS S3 & Codedeploy 做串接部署到 EC2 instance,也就是後續 CD 的部分

Github Actions - Linter 範例

Github 的官方文件有很好的 Quick start guidance

.github/workflows

首先,在你的 repo 底下建立 .github/workflows folder,用來存放 .yml workflows

廢話不多說,直接用 yml 來介紹我相信對工程師們會更直覺

每當有 New push event 到 Repo,就跑 Linter 去檢查是否有 invalid usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
name: Linter

on:
push:
paths-ignore:
- 'README.md'

jobs:
# Set the job key. The key is displayed as the job name
# when a job name is not provided
lint:
# Name the Job
name: Lint code base
# Set the type of machine to run on
runs-on: ubuntu-latest

steps:
# Checks out a copy of your repository on the ubuntu-latest machine
- name: Checkout code
uses: actions/checkout@v2

# Runs Python Black
- uses: actions/setup-python@v2
- name: Run Python-Black style
uses: psf/black@stable
with:
args: "${{ steps.get_file_changes.outputs.files }} --check"

- name: Install dependencies
working-directory: frontend
run: npm install --save-exact

# Run lint
- name: Frontend lint check
working-directory: frontend
run: npm run lint

P.S. 這邊的 Linter 因案而異,看是要跑什麼樣的檢查,我們是用 eslint 放在 package.json scripts 內

1
2
3
4
"scripts": {
...
"lint": "eslint . --ext .js,.ts,.tsx --quiet"
}

結構簡介

on: 定義由什麼 event 會觸發這個 workflow,在哪個 branch 上執行,default 就是 master/main branch

  • 我是用 push,大部分情形 push 也就夠了

jobs: 這一層定義你有多少個 Jobs 要跑,可以有多個並行或是有依賴關係

  • 我取叫 “lint”

jobs.runs-on: 希望跑在什麼機器上

  • 除非特殊需求,建議選擇跑在 ubuntu linux host,因為比較不會超出 Free Account 的 Limits,詳情可以看我底下分享

steps: 這個 job 需要多少步驟達成

  • 第一步就是要 checkout codes 下來
  • 後續步驟看個人想怎麼組織,如果都是單純跑 command lines,也可以都做 run
  • 我建議除非特殊需求可以 leverage Github Actions Marketplace 上面有的 module,比如後端的 Python Black 我就是直接用 psf/black@stable 這個 public actions,滿符合開源精神,也是 Github Action 的特色之一,如果自己也寫了不錯的 actions 也可以考慮放上面讓大家用

steps.uses: 指定跑某個 action

  • 如同上面說的,這個用法是可以重複使用 action,除了用別人 public 的,你也可以重複利用自己 workflows 底下的 actions

working-directory: 可以指定這個步驟要在哪個 folder 執行

  • 我覺得滿實用的,這樣就不需要還要多寫 cd 跳來跳去搞得很亂XD

steps.run: 就是跑指令

  • 滿直覺的,就不多做解釋,可以利用 pipe | 來串多個 commands

更多詳細介紹可以直接看官方 Syntax 文件

Actions Page

都設置好推到你的 remote repo 後,就會在頁面中的 Actions 裡面列出目前的 workflows,以及它們各自的狀態

每個 Steps 都能看在機器上跑的 outputs,也方便我們 Troubleshoot

Github Actions - Build 範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
name: Build

on:
push:
paths-ignore:
- 'README.md'

jobs:
buildFrontend:
name: CI - Frontend
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ['13.14.x']
steps:
# Checks out a copy of your repository on the ubuntu-latest machine
- name: Checkout code
uses: actions/checkout@v2

# Set up required dev env
- name: Install Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

# Building
- name: Install dependencies
working-directory: frontend
run: npm install --save-exact

- name: Building Frontend
working-directory: frontend
run: npm run build

buildBackend:
name: CI - Backend
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.x']
steps:
# Checks out a copy of your repository on the ubuntu-latest machine
- name: Checkout code
uses: actions/checkout@v2

# Set up required dev env
- name: Set up Python & pip
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

# Building
- name: Building Backend
run: docker-compose build db job backend

Side project 目前是把前端跟後端放在一起,所以在做 Build 這一步,我是前後端一起做檢查

比較需要留心的就是我是分兩個 jobs - buildFrontend & buildBackend,彼此之間沒有依賴,是同時分開跑,如果需要 jobs 之間有依賴關係可以參考 jobs.needs doc

再來就是 jobs.strategy.matrix,方便我們將某些固定的數值或是使用版本集中管理,在後續步驟用環境變數取出 matrix.your-strategy 就能獲取該值

Github Actions 免費上限

目前的官方文件對於免費帳戶的限制算是寬裕

  • GitHub Free: Storage 500 MB, 2,000 mins per month

以個人跟小專案來說是很夠用的,在每次 Commit 跑一些簡單的 CI/CD,一次都在 5 分鐘內會結束,除非一個月內有到 400 commits 量,一般來說都不會超過

要注意的就是 OS 的規則,如果是跑在 Linux 上,分鐘數的權重是一樣的,但如果是跑在 MacOS 上,分鐘數就要都乘上 10,Windows 則是乘 2,所以我上面才會建議盡量都讓 workflows 跑在 ubuntu machines

For example, using 1,000 Windows minutes would consume 2,000 of the minutes included in your account. Using 1,000 macOS minutes, would consume 10,000 minutes included in your account.

後記

要導入基本的 Github Actions 相信對有經驗的工程師都不是太難,如果有比較複雜的 build flow,建議先將自己的環境順好,把一些能夠包裝成 bash script 或是 docker build 之類的都先整理一遍,弄順整個流程,手動 run 一次,再來加入 Github Action CI 會比較快速

其實就是把我們平常在 local 做過的事情,標準化起來讓機器幫我們做

有了簡單的 CI 對於程式碼的基本維護有很大的保障,避免有人 push 會 break build 的 commit 在多人協作是很重要的自動化,畢竟我們不能指望開發者永遠不會犯錯(包含自己) 😆

P.S. 突然要感謝微軟收購,沒收購之前的 Github 根本不可能有這種很吃雲端伺服器的功能吧哈哈