Github Actions 還能做這些事
本文轉(zhuǎn)載自微信公眾號「crossoverJie」,作者crossoverJie。轉(zhuǎn)載本文請聯(lián)系crossoverJie公眾號。
前言
最近公司內(nèi)部項(xiàng)目的發(fā)布流程接入了 GitHub Actions,整個體驗(yàn)過程還是比較美好的;本文主要目的是對于沒有還接觸過 GitHub Actions的新手,能夠利用它快速構(gòu)建自動測試及打包推送 Docker 鏡像等自動化流程。
創(chuàng)建項(xiàng)目
本文主要以 Go 語言為例,當(dāng)然其他語言也是類似的,與語言本身關(guān)系不大。
這里我們首先在 GitHub 上創(chuàng)建一個項(xiàng)目,編寫了幾段簡單的代碼 main.go:
- var version = "0.0.1"
- func GetVersion() string {
- return version
- }
- func main() {
- fmt.Println(GetVersion())
- }
內(nèi)容非常簡單,只是打印了了版本號;同時配套了一個單元測試 main_test.go:
- func TestGetVersion1(t *testing.T) {
- tests := []struct {
- name string
- want string
- }{
- {name: "test1", want: "0.0.1"},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := GetVersion(); got != tt.want {
- t.Errorf("GetVersion() = %v, want %v", got, tt.want)
- }
- })
- }
- }
我們可以執(zhí)行 go test 運(yùn)行該單元測試。
- $ go test
- PASS
- ok github.com/crossoverJie/go-docker 1.729s
自動測試
當(dāng)然以上流程完全可以利用 Actions 自動化搞定。
首選我們需要在項(xiàng)目根路徑創(chuàng)建一個 .github/workflows/*.yml 的配置文件,新增如下內(nèi)容:
- name: go-docker
- on: push
- jobs:
- test:
- runs-on: ubuntu-latest
- if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags')
- steps:
- - uses: actions/checkout@v2
- - name: Run Unit Tests
- run: go test
簡單解釋下:
- name 不必多說,是為當(dāng)前工作流創(chuàng)建一個名詞。
- on 指在什么事件下觸發(fā),這里指代碼發(fā)生 push 時觸發(fā),更多事件定義可以參考官方文檔:
Events that trigger workflows
- jobs 則是定義任務(wù),這里只有一個名為 test 的任務(wù)。
該任務(wù)是運(yùn)行在 ubuntu-latest 的環(huán)境下,只有在 main 分支有推送或是有 tag 推送時運(yùn)行。
運(yùn)行時會使用 actions/checkout@v2 這個由他人封裝好的 Action,當(dāng)然這里使用的是由官方提供的拉取代碼 Action。
- 基于這個邏輯,我們可以靈活的分享和使用他人的 Action 來簡化流程,這點(diǎn)也是 GitHub Action擴(kuò)展性非常強(qiáng)的地方。
最后的 run 則是運(yùn)行自己命令,這里自然就是觸發(fā)單元測試了。
- 如果是 Java 便可改為 mvn test.
之后一旦我們在 main 分支上推送代碼,或者有其他分支的代碼合并過來時都會自動運(yùn)行單元測試,非常方便。
與我們本地運(yùn)行效果一致。
自動發(fā)布
接下來考慮自動打包 Docker 鏡像,同時上傳到 Docker Hub;為此首先創(chuàng)建 Dockerfile :
- FROM golang:1.15 AS builder
- ARG VERSION=0.0.10
- WORKDIR /go/src/app
- COPY main.go .
- RUN go build -o main -ldflags="-X 'main.version=${VERSION}'" main.go
- FROM debian:stable-slim
- COPY --from=builder /go/src/app/main /go/bin/main
- ENV PATH="/go/bin:${PATH}"
- CMD ["main"]
這里利用 ldflags 可在編譯期間將一些參數(shù)傳遞進(jìn)打包程序中,比如打包時間、go 版本、git 版本等。
這里只是將 VERSION 傳入了 main.version 變量中,這樣在運(yùn)行時就便能取到了。
- docker build -t go-docker:last .
- docker run --rm go-docker:0.0.10
- 0.0.10
接著繼續(xù)編寫 docker.yml 新增自動打包 Docker 以及推送到 docker hub 中。
- deploy:
- runs-on: ubuntu-latest
- needs: test
- if: startsWith(github.ref, 'refs/tags')
- steps:
- - name: Extract Version
- id: version_step
- run: |
- echo "##[set-output name=version;]VERSION=${GITHUB_REF#$"refs/tags/v"}"
- echo "##[set-output name=version_tag;]$GITHUB_REPOSITORY:${GITHUB_REF#$"refs/tags/v"}"
- echo "##[set-output name=latest_tag;]$GITHUB_REPOSITORY:latest"
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v1
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v1
- - name: Login to DockerHub
- uses: docker/login-action@v1
- with:
- username: ${{ secrets.DOCKER_USER_NAME }}
- password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
- - name: PrepareReg Names
- id: read-docker-image-identifiers
- run: |
- echo VERSION_TAG=$(echo ${{ steps.version_step.outputs.version_tag }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
- echo LASTEST_TAG=$(echo ${{ steps.version_step.outputs.latest_tag }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
- - name: Build and push Docker images
- id: docker_build
- uses: docker/build-push-action@v2.3.0
- with:
- push: true
- tags: |
- ${{env.VERSION_TAG}}
- ${{env.LASTEST_TAG}}
- build-args: |
- ${{steps.version_step.outputs.version}}
新增了一個 deploy 的 job。
- needs: test
- if: startsWith(github.ref, 'refs/tags')
運(yùn)行的條件是上一步的單測流程跑通,同時有新的 tag 生成時才會觸發(fā)后續(xù)的 steps。
name: Login to DockerHub
在這一步中我們需要登錄到 DockerHub,所以首先需要在 GitHub 項(xiàng)目中配置 hub 的 user_name 以及 access_token.
配置好后便能在 action 中使用該變量了。
這里使用的是由 docker 官方提供的登錄 action(docker/login-action)。
有一點(diǎn)要非常注意,我們需要將鏡像名稱改為小寫,不然會上傳失敗,比如我的名稱中 J 字母是大寫的,直接上傳時就會報錯。
所以在上傳之前先要執(zhí)行該步驟轉(zhuǎn)換為小寫。
最后再用這兩個變量上傳到 Docker Hub。
今后只要我們打上 tag 時,Action 就會自動執(zhí)行單測、構(gòu)建、上傳的流程。
總結(jié)
GitHub Actions 非常靈活,你所需要的大部分功能都能在 marketplace找到現(xiàn)成的直接使用,
比如可以利用 ssh 登錄自己的服務(wù)器,執(zhí)行一些命令或腳本,這樣想象空間就很大了。
使用起來就像是搭積木一樣,可以很靈活的完成自己的需求。
參考鏈接:
How to Build a CI/CD Pipeline with Go, GitHub Actions and Docker