前言
最近公司內部專案的釋出流程接入了 GitHub Actions
,整個體驗過程還是比較美好的;本文主要目的是對於沒有還接觸過 GitHub Actions
的新手,能夠利用它快速構建自動測試及打包推送 Docker
映象等自動化流程。
建立專案
本文主要以 Go
語言為例,當然其他語言也是類似的,與語言本身關係不大。
這裡我們首先在 GitHub
上建立一個專案,編寫了幾段簡單的程式碼 main.go
:
var version = "0.0.1"
func GetVersion() string {
return version
}
func main() {
fmt.Println(GetVersion())
}
內容非常簡單,只是列印了了版本號;同時配套了一個單元測試 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)
}
})
}
}
我們可以執行 go test
執行該單元測試。
$ go test
PASS
ok github.com/crossoverJie/go-docker 1.729s
自動測試
當然以上流程完全可以利用 Actions
自動化搞定。
首選我們需要在專案根路徑建立一個 .github/workflows/*.yml
的配置檔案,新增如下內容:
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
不必多說,是為當前工作流建立一個名詞。on
指在什麼事件下觸發,這裡指程式碼發生push
時觸發,更多事件定義可以參考官方文件:
jobs
則是定義任務,這裡只有一個名為test
的任務。
該任務是執行在 ubuntu-latest
的環境下,只有在 main
分支有推送或是有 tag
推送時執行。
執行時會使用 actions/checkout@v2
這個由他人封裝好的 Action
,當然這裡使用的是由官方提供的拉取程式碼 Action
。
- 基於這個邏輯,我們可以靈活的分享和使用他人的
Action
來簡化流程,這點也是GitHub Action
擴充套件性非常強的地方。
最後的 run
則是執行自己命令,這裡自然就是觸發單元測試了。
- 如果是 Java 便可改為
mvn test
.
之後一旦我們在 main
分支上推送程式碼,或者有其他分支的程式碼合併過來時都會自動執行單元測試,非常方便。
與我們本地執行效果一致。
自動釋出
接下來考慮自動打包 Docker
映象,同時上傳到 Docker Hub
;為此首先建立 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
可在編譯期間將一些引數傳遞進打包程式中,比如打包時間、go 版本、git 版本等。
這裡只是將 VERSION
傳入了 main.version
變數中,這樣在執行時就便能取到了。
docker build -t go-docker:last .
docker run --rm go-docker:0.0.10
0.0.10
接著繼續編寫 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')
執行的條件是上一步的單測流程跑通,同時有新的 tag
生成時才會觸發後續的 steps
。
name: Login to DockerHub
在這一步中我們需要登入到 DockerHub
,所以首先需要在 GitHub 專案中配置 hub 的 user_name
以及 access_token
.
配置好後便能在 action 中使用該變數了。
這裡使用的是由 docker 官方提供的登入 action(docker/login-action
)。
有一點要非常注意,我們需要將映象名稱改為小寫,不然會上傳失敗,比如我的名稱中 J
字母是大寫的,直接上傳時就會報錯。
所以在上傳之前先要執行該步驟轉換為小寫。
最後再用這兩個變數上傳到 Docker Hub。
今後只要我們打上 tag
時,Action
就會自動執行單測、構建、上傳的流程。
總結
GitHub Actions
非常靈活,你所需要的大部分功能都能在 marketplace
找到現成的直接使用,
比如可以利用 ssh
登入自己的伺服器,執行一些命令或指令碼,這樣想象空間就很大了。
使用起來就像是搭積木一樣,可以很靈活的完成自己的需求。
參考連結:
How to Build a CI/CD Pipeline with Go, GitHub Actions and Docker