使用 Drone Pipeline 自動構建 Docker 鏡像

本文是 Drone 系列文章的第二篇,在第一篇文章中我們介紹了 ,並且用 給 Drone 應用做了自動化 HTTPS。

本文我們將創建一個簡單的 Golang 應用,通過 Drone 的 Pipeline 來自動化構建 Docker 鏡像。

使用 Drone Pipeline 自動構建 Docker 鏡像

Drone Shot of a bridge over a river

Go 項目

我們這裡使用 Go 語言中流行的 web 框架 gin 創建一個簡單的 web 服務,在 GitHub 上創建一個名為 drone-k8s-demo 的代碼倉庫,Clone 到本地,添加名為 main.go 的文件,內容如下:

package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
func main() {
r := gin.Default()
r.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H {
"health": true,
})
})
if err := r.Run(":8080"); err != nil {
logrus.WithError(err).Fatal("Couldn't listen")
}
}

該服務監聽在 8080 端口,提供了一個簡單的/health路由,返回一個簡單的 JSON 消息表示應用狀態狀態,本地我們使用的是 go1.11.4 版本,所以可以通過 Go Modules 來管理應用的依賴,在項目目錄下面執行 mod init:

$ go mod init dronek8s

如果你對 Go Modules 的使用還不是很熟悉,可以查看我們前面的文章 。

項目完整代碼可以在 GitHub 上獲得:https://github.com/cnych/drone-k8s-demo

Docker 鏡像

現在我們需要為項目添加用於 Docker 鏡像構建的 Dockerfile 文件,當然我們可以使用多階段構建來將項目的構建和打包工作放在同一個 Dockerfile 文件中,我們這裡為了演示 Drone 的 Pipeline 使用就將這兩個步驟分開,在項目根目錄下面創建 Dockerfile 文件,內容如下:

FROM alpine
WORKDIR /home
# 修改alpine源為阿里雲
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \\
apk update && \\
apk upgrade && \\
apk add ca-certificates && update-ca-certificates && \\
apk add --update tzdata && \\
rm -rf /var/cache/apk/*
COPY demo-app /home/
ENV TZ=Asia/Shanghai
EXPOSE 8080
ENTRYPOINT ./demo-app

可以看到我們這裡是通過將 demo-app 文件拷貝到鏡像中去執行來構建鏡像的,那麼我們就得在項目中將應用構建成一個名為 demo-app 的應用,在根目錄下面執行 go build 命令:

$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o demo-app
$ ls
Dockerfile README.md demo-app go.mod go.sum main.go

這個時候我們就可以在本地來構建 Docker 鏡像了:

$ docker build -t cnych/drone-k8s-demo .
...
Successfully built 85a88c8e944a
$ docker images
cnych/drone-k8s-demo latest 85a88c8e944a 43 hours ago 31.1MB

這樣我們就將 Golang 項目打包成 Docker 鏡像了,然後可以在本地運行容器來驗證:

$ docker run --rm --name drone-k8s-demo -p 8080:8080 cnych/drone-k8s-demo
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env:\texport GIN_MODE=release
- using code:\tgin.SetMode(gin.ReleaseMode)
[GIN-debug] GET /health --> main.main.func1 (3 handlers)
[GIN-debug] Listening and serving HTTP on 127.0.0.1:8080

訪問 health 接口:

$ curl http://127.0.0.1:8080/health
{"health":true}

看到這裡就證明我們的 Docker 鏡像構建成功了。

Pipeline

上面我們用手動的方法實現了 Golang 項目打包成 Docker 鏡像的過程,如果到這裡就結束了的話似乎就和 Drone 沒有什麼關係了,那麼我們可以利用 Drone 來做什麼呢?簡單來說就是將上面我們手動的過程自動化。Drone 的工作方式和 Travis CI、GitLab CI 都比較類似,我們需要在項目根目錄下面創建一個名為.drone.yml的文件,我們需要在該文件中來編寫用於自動化打包鏡像的 Pipeline,內容如下:

kind: pipeline
name: default
steps:
- name: linter
image: golang:latest
environment:
GOPROXY: https://mirrors.aliyun.com/goproxy/
commands:
- go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
- golangci-lint run

- name: build
image: golang:latest
environment:
GOPROXY: https://mirrors.aliyun.com/goproxy/
commands:
- CGO_ENABLED=0 go build -o demo-app

- name: docker
image: plugins/docker
settings:
repo: cnych/drone-k8s-demo
use_cache: true
username:
from_secret: docker_username
password:
from_secret: docker_password
tags:
- latest
when:
event: push
branch: master

我們定義了一個 pipeline,其中構建過程有3個步驟,linter、build、docker,當然對於一般的項目來說應該還需要有單元測試的步驟,在每一個步驟中都是通過一個鏡像去進行任務構建的,比如 linter 和 build 都是在一個golang:latest的鏡像中執行任務,在 build 階段中就是執行上面我們手動的 go build 命令,然後在 docker 階段是使用的是plugins/docker這個官方插件,在該鏡像中可以指定 Dockerfile 的路徑,鏡像的 tag,以及鏡像倉庫的用戶名和密碼。

我們這裡的 username 和 password 並沒有名為提供,而是通過 secret 的方式,username.from_secret=docker_username,password.from_secret=docker_password。這兩個 secret 我們可以通過 drone cli 來創建,也可以直接通過 Drone 的網頁來進行配置。

將項目推送到 GitHub,然後在 Drone 頁面上啟用項目,在項目設置項下面添加 Pipeline 中需要使用到的 Secret:

使用 Drone Pipeline 自動構建 Docker 鏡像

drone add secret

這樣用於構建的 Drone Pipeline 就編寫完成了,這個時候我們只需要將.drone.yml文件推送到 GitHub 倉庫中去,正常就會觸發自動構建了:

使用 Drone Pipeline 自動構建 Docker 鏡像

drone pipeline

在 Drone 的頁面中可以看到我們在 Pipeline 中定義的每一個步驟的構建日誌以及時長,如果出現了錯誤就可以對應的去排查即可。

此外,由於我們的 Drone 是部署在 Kubernetes 集群中,而且我們沒有啟動 Agent,所以當 Drone 有任務需要構建的時候會自動的啟動一個 Job 對象來構建:

$ kubectl get job -n kube-ops
NAME COMPLETIONS DURATION AGE
......
drone-job-26-lo6kxn8f4dde6t8n5 1/1 7m1s 22h
drone-job-27-aibtb6jahfq8dg88t 1/1 6m14s 11m
drone-job-28-lgwtvdybpxwwgxwxl 0/1 12s 12s
$ kubectl get pods -n kube-ops
......
drone-job-28-lgwtvdybpxwwgxwxl-hs28f 1/1 Running 0 2m3s
drone-job-26-lo6kxn8f4dde6t8n5-bbw8t 0/1 Completed 0 22h
drone-job-27-aibtb6jahfq8dg88t-qkmn5 0/1 Completed 0 12m

Job 在 Drone 的任務構建完成後並不會自動銷燬,Pod 的狀態只會變成 Completed 狀態,所以需要我們手動的去刪除這些已經構建完成的 Job 資源對象。

如果想要自動刪除這些完成的 Job 資源對象的話,我們可以在 APIServer 中啟用 TTLAfterFinished 這個 Feature Gates 也是可以的。

到這裡我們就實現了使用 Drone Pipeline 來自動將我們的項目打包成 Docker 鏡像,並推送到了 DockerHub,下篇文章我們再來和大家學習如何使用 Helm 將應用部署到 Kubernetes 集群中去。

"


分享到:


相關文章: