---
# System prepended metadata

title: 17_Go CI WITH Go & Docker on Gitlab
tags: [Go, 2019鐵人賽]

---

17_Go CI WITH Go & Docker on Gitlab
========================
###### tags: `Go` `2019鐵人賽`

往往需求派下來了, 
我們把程式寫完了, 或者Dockerfile(or docker-compose)寫好了.
總要推上版控的,  應該大部分都是Git吧!!
去年開始接觸Gitlab的我, 也開始接觸CI這部份的操作.

# CI - Continuous Integration 持續整合
以前沒有CI的時候,  大家寫完程式, 到開始作整合編譯.
可能都是一兩週後的事情了, 甚至一個月.
因為以前大家只關心自己的部份是否能正常,  並不在意整合在一起是否能正常編譯.
直到很後面才會來煩惱修正. 
![](https://i.imgur.com/IJkSSOi.jpg)

所以Agile文化裡提出CI這概念, 希望程式有變動, 就趕緊作整合, 確保整個系統依然能正常運作, 也就是新增的部份, 並不會影響到原有的部份, 能持續且自動地進行驗證.
這驗證包含了
- 建置 build
- 測試 test
- 程式碼分析 source code analysis
- 其他
**要談敏捷, 果然還是要寫自動測試先!!! 不然都是在打嘴泡**
# [Gitlab-CI](https://docs.gitlab.com/ee/ci/)
> [和艦長一起 30 天玩轉 GitLab ](https://ithelp.ithome.com.tw/users/20120986/ironman/2733), 今年剛好有社團大神寫Gitlab介紹的文
Gitlab有提供CI/CD的功能
![](https://i.imgur.com/1SZoLSM.png)



## .gitlab-ci.yml
寫個簡單的Gin程式, 然後推上gitlab repo.
`main.go`
```go=1
package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run()
}
```
Push成功之後, 先去該專案左側的Settings -> [Runners](https://docs.gitlab.com/runner/install/) 做設定,
這步是讓自己的某台電腦成為Gitlab CI用的build server.
https://docs.gitlab.com/runner/install/

然後, 在專案根目錄下新增`.gitlab-ci.yml`
```yaml=
image: golang:latest

variables:
  ARTIFACTS_DIR: artifacts
  GO_PROJECT: gitlab.com/username/projectname

before_script:
  - go version
  - export GO111MODULE=on
  - mkdir -p ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}
 
stages:
  - build
  - test

gotest:
  stage: test
  script:
    - go test ./...


gobuild:
  stage: build
  script:
    - go build -o  ${CI_PROJECT_DIR}/${ARTIFACTS_DIR}/main
  artifacts:
    paths:
      - ${ARTIFACTS_DIR}
    expire_in: 1h
```
Push 上遠端後, 會看到CI/CD -> Pipelines 跟 Jobs有東西出現了.
![](https://i.imgur.com/GgBDF4I.png)
![](https://i.imgur.com/4ZeEKHY.png)

途中的`a216460a`就是我們剛剛commit的log.
Pipeline就是yml中的stages, 裡面寫的都是各個Job.

接著定義Job的內容
gobuild這job是屬於build stage的job
gotest這job是屬於test stage的job.
一個stage可以定義多個job.
![](https://i.imgur.com/n7pa2xy.png)

接著來說明這`.gitlab-ci.yml`的內容
gitlab-ci就是借助docker的方式來進行編譯.
所以一開始要告訴它編譯的基底image.

然後有些各job要共用的資料我就設定成[variable]

before_script 是用來定義所有job執行前要執行的命令.

script, 就是執行該job的腳本或是命令.
artifacts, 執行成功後, 編譯出來的產出物.
expire_in, 就是設置該artifact被上傳到Gitlab開始的儲存時間.

內容其實就都是我們平常輸入的指令而已
把他們放在對應的階段, 如果是同階段, 不同順序.
yaml內的`-` 表示的是陣列, 就以`-`開頭空一格後, 把指令放後面.

跑完後, 應該會有artifact能下載了, 解壓縮開來會是我們指定平台的Go二進制檔,
這時候就能人工拿去佈署了XD
![](https://i.imgur.com/CIYUUZH.png)


# Gitlab CI + Docker Hub
![](https://i.imgur.com/buraSrR.png)

昨天不是寫好了Dockerfile(或寫的是docker-compose)?
Gitlab一樣能對docker做CI.

## [Docker Hub](https://hub.docker.com/)
先來這裡註冊並且開個repository.
![](https://i.imgur.com/3eI596n.png)
記著自己的username跟repository name .

先來Gitlab 的Settings -> CI/CD -> Variables這裡
設定docker hub帳號
![](https://i.imgur.com/8QepP9x.png)
這裡的變數會被帶到`.gitlab-ci.yml`內.

然後要改一下gitlab-runner的設定, 加入`privileged = true`
```
  [runners.docker]
    privileged = true
```


來改寫`.gitlab-ci.yml`
這裡我使用docker-in-docker (dind)的方式
> [Gitlab Docker Build](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html)
```yaml=
image: docker:latest

variables:
  DOCKER_HOST: tcp://docker:2375/
  DOCKER_DRIVER: overlay2
  # See https://github.com/docker-library/docker/pull/166
  DOCKER_TLS_CERTDIR: ""
  IMAGE_TAG: tedmax100/gitlabtest:latest

services:
    - name: docker:dind
      entrypoint: ["env", "-u", "DOCKER_HOST"]
      command: ["dockerd-entrypoint.sh"]

before_script:
  - echo "${DOCKERHUB_PWD}" | docker login -u "${DOCKERHUB_USER}" --password-stdin
stages:
  - deploy


dockerdeploy:
  stage: deploy
  script:
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG
```
![](https://i.imgur.com/9mwlylO.png)
![](https://i.imgur.com/ghgmdt6.png)
Docker image被成功的推上去了 ！！

接著之後都是Deploy server的事情了XD
未來再提到佈署的部份.

# 結語
從Node轉到來Go花了點時間摸熟依賴包的關係.
還有goroutine跟channel.
畢竟Node主要思維是單執行緒的思考邏輯, 就也沒鎖(Lock)這類的需要作考量.
兩者都很簡單入門, 但為了分散式架構還是讓自己來學Go.
畢竟我在職場上是純後端XD

今年第一次參加鐵人賽, 能完賽真的很有成就感.
短跑比賽結束了, 但長跑比賽還在繼續.
明年打算繼續, 應該會帶著前端專案與Gin有更多串接.
感謝各位的閱讀與支持, 之後有更多文章會分享在[小弟個人網誌](https://tedmax100.github.io)上.
想學的技術太多, 應該會先鎖定在[Pixi](https://www.pixijs.com/)跟[ES](https://www.elastic.co/)上吧.

![](https://i.imgur.com/LxsC1zd.png)
