1. 程式人生 > >基於 Gogs,以 Golang 為例

基於 Gogs,以 Golang 為例

實際的 DevOps 專案中,在 pipeline 流水線中包含下載程式碼、測試、構建、釋出、部署、通知等步驟。基本流程如下,當然不同的語言或不同的需求下流程會有所差異:

clone -> test -> build -> publish -> deploy -> notify

包含開發的完整流程為:

  1. 開發專案程式碼,包括 .drone.yml 檔案和 Dockerfile 檔案
  2. 上傳程式碼至 Gogs,通過 Gogs 的 webhook 觸發 Drone 的 Pipeline
  3. Drone 開始 Pipeline 的執行
    1. clone 程式碼至容器
    2. 測試
    3. 編譯程式碼,構建可執行檔案(Java、Golang 等編譯型語言需要,PHP 之類的指令碼語言則不需要)
    4. 將專案和執行環境打包成映象,釋出到 Registry(當然也可以使用 rsync 將編譯後的檔案(Golang 等)或原始碼(PHP 等)部署到伺服器,此時需要在目標伺服器提前安裝執行環境)
    5. 部署至生產環境
    6. 傳送郵件等通知資訊

Drone 的文件挺差勁,不過 Drone 用起來還是挺簡單的,比 Jenkins 簡單到無法描述。

打通 Gogs 和 Drone

建立 Git 專案

登入 Gogs 後,從 Web 頁面建立專案。我的 Gogs 專案地址是 https://gogs.kikakika.com

建立完成後,可以在 Web 頁面新增檔案,但是比較麻煩。這裡把倉庫新增到本地:

git clone https://gogs.kikakika.com/lihongfeng/first.git

然後,在倉庫中建立 .drone.ymlhello.gohello_test.go 三個檔案。

編寫 .drone.yml 檔案

workspace:
  base: /go
  path: src/gogs.kikakika.com/lihongfeng/first

pipeline:
  build:
    image: golang:1.10.2
    commands:
      - go test
      - go build 

其中,workspace 定義了可以在構建步驟之間共享的 volume 和工作目錄。建議設定 workspace 以使用所需的 GOPATH。其中:

  • base 定義了一個可用於所有 pipeline 步驟的共享的 volume。這可確保原始碼、依賴項和編譯的二進位制檔案在步驟之間持久儲存和共享。
  • path 定義了用於構建的工作目錄。程式碼會克隆到這個位置,並且構建過程中每個步驟都會使用這個工作目錄作為預設的工作目錄。path 必須是相對路徑,並且可以與 base 相結合。

編寫 Golang 程式碼

main.go

package main

import (
    "fmt"
)

func main() {
    fmt.Printf("hello world");
}

func hello() string {
    return "hello world";
}

main_test.go

package main

import "testing"

func TestHello(t *testing.T) {
    if hello() != "hello world" {
        t.Error("Testing error")
    }
}

提交程式碼

$ git add ./
$ git commit -m "try drone with golang demo"
[master f8a6927] try drone with golang demo
 3 files changed, 33 insertions(+)
 create mode 100644 .drone.yml
 create mode 100644 main.go
 create mode 100644 main_test.go
$ git push
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 696 bytes | 696.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To https://gogs.kikakika.com/lihongfeng/first.git
   b8c5bdd..f8a6927  master -> master

檢視 Drone 的 web 端是否成功觸發

可以看到成功觸發了 CI。具體頁面截圖如下。

  • 專案主頁:
    這裡寫圖片描述
  • clone 階段:
    這裡寫圖片描述
+ git init
Initialized empty Git repository in /go/src/gogs.kikakika.com/lihongfeng/first/.git/
+ git remote add origin https://gogs.kikakika.com/lihongfeng/first.git
+ git fetch --no-tags origin +refs/heads/master:
From https://gogs.kikakika.com/lihongfeng/first
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> origin/master
+ git reset --hard -q fbcf4d02a0294c943269634edd517c977ea03cfb
+ git submodule update --init --recursive
  • build 階段:
+ go test
PASS
ok      gogs.kikakika.com/lihongfeng/first  0.002s
+ go build

實現 CI/CD

上面的例子只是構建專案及執行測試,並沒有構建映象及將映象釋出到 Registry,更沒有操作生產環境伺服器更新映象。

通過更新上面的 .drone.yml 檔案實現這幾個步驟:

workspace:
  base: /go
  path: src/gogs.kikakika.com/lihongfeng/first

pipeline:
  test:
    image: golang:1.10.2
    commands:
      - go test
  build:
    image: golang:1.10.2
    commands:
      - go build
  publish:
    image: plugins/docker
    repo: kikajack/first
    dockerfile: ./Dockerfile
    tags: latest
    # registry: https://harbor.kikakika.com # 如果使用自建的映象倉庫,例如 Harbor,這裡可以通過 registry 指定
    secrets: [ docker_username, docker_password ] # 這裡的使用者名稱和密碼在 web 介面指定

    # 如果需要自動部署容器到伺服器,可以開啟下面這部分程式碼
  # deploy:
  #   image: appleboy/drone-ssh # 用於連線伺服器
  #   host:
  #     - your_host
  #   username: your_name
  #   password: your_pass
  #   port: 22
  #   command_timeout: 300 # ssh命令列執行超時時間,300#   script:
  #     - docker pull repo_url:latest
  #     - docker rm -f docker-demo || true # 這裡這樣是因為如果不存在docker-demo,rm會報錯
  #     - docker run -d -p 8065:8065 --name docker-demo repo_url

其中 secrets: [ docker_username, docker_password ] 中指定的使用者名稱密碼,需要在 Drone 的 Web 頁面設定。這樣可以避免在配置檔案中出現密碼,安全。

Dockerfile 檔案

需要在專案根目錄中建立 Dockerfile 檔案,用於構建映象。可以參考 通過 Docker 部署 Go 伺服器,這裡有完整的示例。這個檔案支援兩種方式構建映象:容器外編譯後複製二進位制檔案到容器,或複製原始碼到容器後在容器中編譯得到二進位制檔案。

複製原始碼到容器後在容器內編譯:

# 官方的 Golang 映象基於 Debian,且 workspace(GOPATH)配置為 /go
FROM golang:1.10.2

# 將本地的 Go 檔案複製到容器中的 workspace
ADD . /go/src/gogs.kikakika.com/lihongfeng/first

# 在容器內編譯構建應用。可以在這裡獲取或管理依賴關係,可以手動或使用諸如“godep”之類的工具
RUN go install gogs.kikakika.com/lihongfeng/first

# 容器啟動時,預設執行 first 應用
ENTRYPOINT /go/bin/first

# 監聽 8080 埠
EXPOSE 8080

容器外編譯後複製二進位制檔案到容器

可以參考 這個例子

  • Dockerfile 檔案:
FROM plugins/base:multiarch

LABEL maintainer="Bo-Yi Wu <[email protected]>" \
  org.label-schema.name="Drone Workshop" \
  org.label-schema.vendor="Bo-Yi Wu" \
  org.label-schema.schema-version="1.0"

ADD release/linux/amd64/helloworld /bin/

HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 CMD [ "/bin/helloworld", "-ping" ]

ENTRYPOINT ["/bin/helloworld"]
  • .drone.yml 檔案:
workspace:
  base: /go
  path: src/github.com/go-training/drone-golang-example

clone:
  git:
    image: plugins/git
    depth: 50
    tags: true

pipeline:
  testing:
    image: golang:1.10.0
    commands:
      - go test -v .
      - go vet

  build_linux_amd64:
    image: golang:1.10.0
    group: build
    commands:
      - make build_linux_amd64

  build_linux_i386:
    image: golang:1.10.0
    group: build
    commands:
      - make build_linux_i386

  publish_linux_amd64:
    image: plugins/docker:17.05
    pull: true
    secrets: [ docker_username, docker_password ]
    group: release
    repo: appleboy/test
    auto_tag: true
    dockerfile: Dockerfile
    when:
      event: [ push, tag ]
      local: false

  publish_alpine:
    image: plugins/docker
    group: release
    pull: true
    dockerfile: Dockerfile.alpine
    secrets: [ docker_username, docker_password ]
    default_tags: true
    default_suffix: alpine
    repo: appleboy/test
    when:
      event: [ push, tag ]
      local: false

驗證映象是否上傳成功

  • 登入官方映象倉庫 https://hub.docker.com/r/kikajack/first,可以看到映象上傳成功了。
    這裡寫圖片描述
  • 執行一下,會成功的輸出“hello world”:
[root@VM_139_74_centos ~]# docker run kikajack/first
Unable to find image 'kikajack/first:latest' locally
latest: Pulling from kikajack/first
cc1a78bfd46b: Already exists 
6861473222a6: Already exists 
7e0b9c3b5ae0: Already exists 
3ec98735f56f: Already exists 
32ecd1fcfe1a: Already exists 
9889d58a42e5: Already exists 
337bad6698be: Already exists 
831eeb459358: Pull complete 
d4438c00f9db: Pull complete 
Digest: sha256:9caf567d796deead445606f56892f843f8869aef92d27bb8ff20985cd8a82169
Status: Downloaded newer image for kikajack/first:latest
hello world[root@VM_139_74_centos ~]#