利用 GitHub Action 自動發佈 Docker

前言

最近公司內部項目的發佈流程接入了 GitHub Actions,整個體驗過程仍是比較美好的;本文主要目的是對於沒有還接觸過 GitHub Actions的新手,可以利用它快速構建自動測試及打包推送 Docker 鏡像等自動化流程。git

建立項目

本文主要以 Go 語言爲例,固然其餘語言也是相似的,與語言自己關係不大。github

這裏咱們首先在 GitHub 上建立一個項目,編寫了幾段簡單的代碼 main.gogolang

var version = "0.0.1"

func GetVersion() string {
	return version
}

func main() {
	fmt.Println(GetVersion())
}
複製代碼

內容很是簡單,只是打印了了版本號;同時配套了一個單元測試 main_test.godocker

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 運行該單元測試。ubuntu

$ go test                          
PASS
ok      github.com/crossoverJie/go-docker       1.729s
複製代碼

自動測試

固然以上流程徹底能夠利用 Actions 自動化搞定。bash

首選咱們須要在項目根路徑建立一個 .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
複製代碼

簡單解釋下:markdown

  • name 沒必要多說,是爲當前工做流建立一個名詞。
  • on 指在什麼事件下觸發,這裏指代碼發生 push 時觸發,更多事件定義能夠參考官方文檔:

Events that trigger workflowsapp

  • jobs 則是定義任務,這裏只有一個名爲 test 的任務。

該任務是運行在 ubuntu-latest 的環境下,只有在 main 分支有推送或是有 tag 推送時運行。ssh

運行時會使用 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

相關文章
相關標籤/搜索