Golang釋出遇到的問題
對於golang的釋出,之前一直沒有一套規範的釋出流程,來看看之前釋出流程:
方案一
-
開發者本地環境需要將環境變數檔案改為正式環境配置
-
編譯成可執行檔案
-
傳送給運維
-
(運維)將檔案覆蓋為線上
-
(運維)重啟程式
(可謂“又臭又長”)
方案二
-
開發者講程式碼commit到gitlab上交給運維同學
-
(運維)pull程式碼
-
(運維)編譯成可執行檔案
-
(運維)覆蓋線上檔案
-
(運維)重啟程式
這種對於運維屬於重度依賴,而運維同學又需要去關心程式碼的編譯,增加了運維同學的工作了。
以上兩種方案都是之前專案中發生過的,對於發版來說可謂是一種“噩夢”,易出錯,流程長,運維要是不在根本無法操作。
解決方案
為了解決上面提到的兩種釋出問題,目前我們做了如下的設計方案:
-
開發者提交程式碼到GitLab伺服器
-
新增一個Tag觸發構建(.gitlab-ci.yml+makefile)
-
將構建後的檔案打包新增上版本號(1.0.0+)後推送到版本伺服器
-
在Jenkins選擇對應的版本號釋出到指定Web Server上
釋出時,開發只需要編寫“.gitlab-ci.yml”以及makefile對專案進行構建,而運維只需要配置jenkins,將檔案釋出到Web Server上即可,完成了開發和運維的解耦。
什麼是GitLab-CI
GitLab CI
是 GitLab Continuous Integration
(Gitlab 持續整合)的簡稱。從 GitLab
的 8.0 版本開始,GitLab
就全面整合了 Gitlab-CI
,並且對所有專案預設開啟。只要在專案倉庫的根目錄新增 .gitlab-ci.yml
檔案,並且配置了 Runner
(執行器),那麼每此新增新的tag
都會觸發 CI pipeline
。
一些概念
在介紹 GitLab CI 之前,我們先看看一些持續整合相關的概念。
Pipeline
一次 Pipeline 其實相當於一次構建任務,裡面可以包含多個流程,如安裝依賴、執行測試、編譯、部署測試伺服器、部署生產伺服器等流程。 任何提交或者 Merge Request 的合併都可以觸發 Pipeline,如下圖所示:
+------------------+ +----------------+ | | trigger | | | Commit / MR +---------->+ Pipeline | | | | | +------------------+ +----------------+
Stages
Stages 表示構建階段,說白了就是上面提到的流程。 我們可以在一次 Pipeline 中定義多個 Stages,這些 Stages 會有以下特點:
-
所有 Stages 會按照順序執行,即當一個 Stage 完成後,下一個 Stage 才會開始
-
只有當所有 Stages 完成後,該構建任務 (Pipeline) 才會成功
-
如果任何一個 Stage 失敗,那麼後面的 Stages 不會執行,該構建任務 (Pipeline) 失敗
因此,Stages 和 Pipeline 的關係就是:
+--------------------------------------------------------+ | | | Pipeline | | | | +-----------+ +------------+ +------------+ | | | Stage 1 |---->| Stage 2 |----->| Stage 3 | | | +-----------+ +------------+ +------------+ | | | +--------------------------------------------------------+
Jobs
Jobs 表示構建工作,表示某個 Stage 裡面執行的工作。 我們可以在 Stages 裡面定義多個 Jobs,這些 Jobs 會有以下特點:
-
相同 Stage 中的 Jobs 會並行執行
-
相同 Stage 中的 Jobs 都執行成功時,該 Stage 才會成功
-
如果任何一個 Job 失敗,那麼該 Stage 失敗,即該構建任務 (Pipeline) 失敗
所以,Jobs 和 Stage 的關係圖就是:
+------------------------------------------+ | | | Stage 1 | | | | +---------+ +---------+ +---------+ | | | Job 1 | | Job 2 | | Job 3 | | | +---------+ +---------+ +---------+ | | | +------------------------------------------+
什麼是MakeFile
Makefile檔案的作用是告訴make工具需要如何去編譯和連結程式,在需要編譯工程時只需要一個make命令即可,避免了每次編譯都要重新輸入完整命令的麻煩,大大提高了效率,也減少了出錯率。
基本介紹
我們平常很多時候都是直接在命令列輸入go build進行編譯的:
go build .
或者測試使用go run執行專案:
go run main.go
我看有很多大型開源專案都是如下方式 :
make build # 或者 make install
我們打包執行這個過程,還有一個更加貼切的詞語叫做構建專案。
案例
我們先建立一個新的工程,目錄如下:
-
main.go
-
Makefile
make.go原始碼:
package main import "fmt" func main() { fmt.Println("hi, pang pang.") }
就多了一個Makefile檔案,如果要使用Makefile去構建你專案,就需要在你的專案裡面新建這個Makefile檔案。
這裡我貼一個簡單的Makefile
檔案的原始碼:
BINARY_NAME=hello build: go build -o $(BINARY_NAME) -v ./$(BINARY_NAME)
解釋下上面各行的意思:
-
第一行,宣告瞭一個變數
BINARY_NAME
他的值是hello
,方便後面使用 -
第二行,宣告一個
target
,其實你可以理解成一個對外的方法 -
第三行,這就是這個
target
被呼叫時執行的指令碼,這行就是build這個專案,編譯後的二進位制檔案放在當前工程目錄下,名字是變數BINARY_NAME
的值 -
第四行,這一行就是直接執行當前目錄下的二進位制檔案
構建
我們開啟我們的終端,直接執行:
make build
將生成一個可執行檔案hello
,這就是對Makefile的簡單介紹,具體命令推薦 阮一鋒的Makefile教程
部署流程
前面大致介紹了構建自動化構建的用到的一些概念和工具,那麼我們就可以開始我們的部署了。
GitLab Runner
瞭解上面了基本的概念後,那由何人來執行這些任務呢?那就是 GitLab Runner(執行器)
安裝
安裝 GitLab Runner 太簡單了,按照著 官方文件 的教程來就好拉! 下面是 Debian/Ubuntu/CentOS 的安裝方法,其他系統去參考官方文件:
# For Debian/Ubuntu $ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash $ sudo apt-get install gitlab-ci-multi-runner # For CentOS $ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash $ sudo yum install gitlab-ci-multi-runner
註冊 Runner
安裝好 GitLab Runner 之後,我們只要啟動 Runner 然後和 CI 繫結就可以了:
-
開啟你 GitLab 中的專案頁面,在專案設定中找到 runners
-
執行
sudo gitlab-ci-multi-runner register
-
輸入 CI URL
-
輸入 Token
-
輸入 Runner 的名字
-
選擇 Runner 的型別,簡單起見還是選 Shell 吧
-
完成
當註冊好 Runner 之後,可以用 sudo gitlab-ci-multi-runner list
命令來檢視各個 Runner 的狀態:
$ sudo gitlab-runner list Listing configured runners ConfigFile=/etc/gitlab-runner/config.toml my-runner Executor=shell Token=cd1cd7cf243afb47094677855aacd3 URL=http://mygitlab.com/ci
.gitlab-ci.yml編寫
before_script: - export GOPATH=$GOPATH:/usr/local/${CI_PROJECT_NAME} - export # 引入環境變數 - cd /usr/local/${CI_PROJECT_NAME}/src/${CI_PROJECT_NAME} - export VERSION=`echo ${CI_COMMIT_TAG} | awk -F"_" '{print $1}'` # stages stages: - build - deploy # jobs build-tags: stage: build script: ## 執行makefile檔案 - make ENV="prod" VERSION=${VERSION} - if [ ! -d "/data/code/project_name/tags/${VERSION}" ]; then mkdir -p "/data/code/project_name/tags/${VERSION}/"; fi - cd compiler/ - mv -f project_name.tar.gz /data/code/project_name/tags/${VERSION}/ only: - tags deploy-tags: stage: deploy script: - cd /data/code/project_name/tags/ - svn add ${VERSION} - svn commit -m "add ${CI_COMMIT_TAG}" only: - tags
Makefile編寫
export VERSION=1.0.0 export ENV=prod export PROJECT=project_name TOPDIR=$(shell pwd) OBJ_DIR=$(OUTPUT)/$(PROJECT) SOURCE_BINARY_DIR=$(TOPDIR)/bin SOURCE_BINARY_FILE=$(SOURCE_BINARY_DIR)/$(PROJECT) SOURCE_MAIN_FILE=main.go BUILD_TIME=`date +%Y%m%d%H%M%S` BUILD_FLAG=-ldflags "-X main.version=$(VERSION) -X main.buildTime=$(BUILD_TIME)" OBJTAR=$(OBJ_DIR).tar.gz all: build pack @echo "\n\rALL DONE" @echo "Program: " $(PROJECT) @echo "Version: " $(VERSION) @echo "Env: " $(ENV) build: @echo "start go build...." @rm -rf $(SOURCE_BINARY_DIR)/* @go build $(BUILD_FLAG) -o $(SOURCE_BINARY_FILE) $(SOURCE_MAIN_FILE) pack: @echo "\n\rpacking...." @tar czvf $(OBJTAR) -C $(OBJ_DIR) .
執行
完成的部署流程(其實很簡單),然後每次要構建只需要執行:
git commit -a -m "我準備打tag測試啦" git push ## 打tag git tag -a "1.0.0" -m"1.0.0" git push origin 1.0.0
那麼在GitLab就會看到:
大功告成,以上!~
總結
其實發布流程有無數種,每一個團隊都有合適自己的釋出流程,如果專案小,團隊小,也許手動釋出就足夠了,而對於專案有一定規模的團隊,或許需要更加規範的釋出流程來保障專案的穩定發版。