Golang基於Gitlab CI/CD部署方案

來源:互聯網
上載者:User

本文為轉載,原文:Golang基於Gitlab CI/CD部署方案

docker

概述

持續整合 (Continuous integration)是一種軟體開發實踐,即團隊開發成員經常整合它們的工作,通過每個成員每天至少整合一次,也就意味著每天可能會發生多次整合。每次整合都通過自動化的構建(包括編譯,發布,自動化測試)來驗證,從而儘早地發現整合錯誤。

持續部署(continuous deployment)是通過自動化的構建、測試和部署迴圈來快速交付高品質的產品。某種程度上代表了一個Team Dev工程化的程度,畢竟快速運轉的互連網公司人力成本會高於機器,投資機器最佳化開發流程化相對也提高了人的效率,讓 engineering productivity 最大化。

1. 環境準備

本次實驗是基於Centos 7.3, docker 17.03.2-ce環境下的。docker的安裝這裡就不贅述了,提供了官方連結吧: Get Docker CE for CentOS

1.1. docker啟動gitlab

啟動命令如下:

docker run --detach \--hostname gitlab.chain.cn \--publish 8443:443 --publish 8080:80 --publish 2222:22 \--name gitlab \--restart always \--volume /Users/zhangzc/gitlab/config:/etc/gitlab \--volume /Users/zhangzc/gitlab/logs:/var/log/gitlab \--volume /Users/zhangzc/gitlab/data:/var/opt/gitlab \gitlab/gitlab-ce

port,hostname, volume根據具體情況具體設定

1.2. docker啟動gitlab-runner

啟動命令如下:

sudo docker run -d /--name gitlab-runner /--restart always /-v /Users/zhangzc/gitlab-runner/config:/etc/gitlab-runner /-v /Users/zhangzc/gitlab-runner/run/docker.sock:/var/run/docker.sock /gitlab/gitlab-runner:latest

volume根據具體情況具體設定

1.3. 用於整合部署的鏡像製作

我們的整合和部署都需要放在一個容器裡面進行,所以,需要製作一個鏡像並安裝一些必要的工具,用於整合和部署相關操作。目前我們的項目都是基於golang 1.9.2的,這裡也就基於golang:1.9.2的鏡像制定一個特定的鏡像。

Dockerfile內容如下:

# Base image: https://hub.docker.com/_/golang/FROM golang:1.9.2USER root# Install golintENV GOPATH /goENV PATH ${GOPATH}/bin:$PATHRUN mkdir -p /go/src/golang.org/xRUN mkdir -p /go/src/github.com/golangCOPY source/golang.org /go/src/golang.org/x/COPY source/github.com /go/src/github.com/golang/RUN go install github.com/golang/lint/golint# install dockerRUN curl -O https://get.docker.com/builds/Linux/x86_64/docker-latest.tgz \    && tar zxvf docker-latest.tgz \    && cp docker/docker /usr/local/bin/ \    && rm -rf docker docker-latest.tgz# install expectRUN apt-get updateRUN apt-get -y install tcl tk expect

其中golint是用於golang代碼風格檢查的工具。
docker是由於需要在容器裡面使用宿主的docker命令,這裡就需要安裝一個docker的可執行檔,然後在啟動容器的時候,將宿主的 /var/run/docker.sock 檔案掛載到容器內的同樣位置。
expect是用於ssh自動登入遠程伺服器的工具,這裡安裝改工具是為了可以實現遠程伺服器端部署應用

另外,在安裝golint的時候,是需要去golang.org下載源碼的,由於牆的關係,go get命令是執行不了的。為了處理這個問題,首先通過其他渠道先下載好相關源碼,放到指定的路徑下,然後copy到鏡像裡,並執行安裝即可。

下面有段指令碼是用於產生鏡像的:

#!/bin/bashecho "提取構建鏡像時需要的檔案"source_path="source"mkdir -p $source_path/golang.orgmkdir -p $source_path/github.comcp -rf $GOPATH/src/golang.org/x/lint $source_path/golang.org/cp -rf $GOPATH/src/golang.org/x/tools $source_path/golang.org/cp -rf $GOPATH/src/github.com/golang/lint $source_path/github.comecho "構建鏡像"docker build -t go-tools:1.9.2 .echo "刪除構建鏡像時需要的檔案"rm -rf $source_path

產生鏡像後,推送到鏡像倉庫,並在gitlab-runner的伺服器上拉取該鏡像

本次實驗的gitlab和gitlab-runner是運行在同一伺服器的docker下的。

2. runner註冊及配置

2.1. 註冊

環境準備好後,在伺服器上執行以下命令,註冊runner:

docker exec -it gitlab-runner gitlab-ci-multi-runner register

按照提示輸入相關資訊

Please enter the gitlab-ci coordinator URL:# gitlab的url, 如:https://gitlab.chain.cn/Please enter the gitlab-ci token for this runner:# gitlab->你的項目->settings -> CI/CD ->Runners settingsPlease enter the gitlab-ci description for this runner:# 樣本:demo-testPlease enter the gitlab-ci tags for this runner (comma separated):# 樣本:demoWhether to run untagged builds [true/false]:# truePlease enter the executor: docker, parallels, shell, kubernetes, docker-ssh, ssh, virtualbox, docker+machine, docker-ssh+machine:# dockerPlease enter the default Docker image (e.g. ruby:2.1):# go-tools:1.9.2 (之前自己製作的鏡像)
token

成功後,可以看到gitlab->你的項目->settings -> CI/CD ->Runners settings 頁面下面有以下內容:

runner註冊成功

2.2. 配置

註冊成功之後,還需要在原有的配置上做一些特定的配置,如下:

[[runners]]  name = "demo-test"  url = "https://gitlab.chain.cn/"  token = "c771fc5feb1734a9d4df4c8108cd4e"  executor = "docker"  [runners.docker]    tls_verify = false    image = "go-tools:1.9.2"    privileged = false    disable_cache = false    volumes = ["/var/run/docker.sock:/var/run/docker.sock"]    extra_hosts = ["gitlab.chain.cn:127.0.0.1"]    network_mode = "host"    pull_policy = "if-not-present"    shm_size = 0  [runners.cache]

這裡先解釋下gitlab-runner的流程吧,gitlab-runner在執行的時候,會根據上面的配置啟動一個容器,即配置中的go-tools:1.9.2,b其中所有的啟動參數都會在[runners.docker]節點下配置好,包括掛載啊,網路啊之類的。容器啟動成功之後,會使用這個容器去gitlab上pull代碼,然後根據自己定義的規則進行檢驗,全部檢測成功之後便是部署了。

volumes: 是為了在容器中可以執行宿主機的docker命令。

extra_hosts: 給gitlab添加個host映射,映射到127.0.0.1

network_mode: 令容器的網路與宿主機一致,只有這樣才能通過127.0.0.1訪問到gitlab。

pull_policy: 當指定的鏡像不存在的話,則通過docker pull拉取

3. 定義規則

在gitlab項目根目錄建立.gitlab-ci.yml檔案,填寫runner規則,具體文法課參考官方文檔:https://docs.gitlab.com/ee/ci/yaml/

3.1. go整合命令

下面介紹幾個golang常見的整合命令

  1. 包列表
    正如在官方文檔中所描述的那樣,go項目是包的集合。下面介紹的大多數工具都將使用這些包,因此我們需要的第一個命令是列出包的方法。我們可以用go list子命令來完成
go list ./...

請注意,如果我們要避免將我們的工具應用於外部資源,並將其限制在我們的代碼中。 那麼我們需要去除vendor 目錄,命令如下:

go list ./... | grep -v /vendor/
  1. 單元測試
    這些是您可以在代碼中啟動並執行最常見的測試。每個.go檔案需要一個能支援單元測試的_test.go檔案。可以使用以下命令運行所有包的測試:
go test -short $(go list ./... | grep -v /vendor/)
  1. 資料競爭
    這通常是一個難以逃避解決的問題,go工具預設具有(但只能在linux / amd64、freebsd / amd64、darwin / amd64和windows / amd64上使用)
go test -race -short $(go list . /…| grep - v /vendor/)
  1. 代碼覆蓋
    這是評估代碼的品質的必備工具,並能顯示哪部分代碼進行了單元測試,哪部分沒有。
    要計算程式碼涵蓋範圍,需要運行以下指令碼:
PKG_LIST=$(go list ./... | grep -v /vendor/)for package in ${PKG_LIST}; do    go test -covermode=count -coverprofile "cover/${package##*/}.cov" "$package" ;donetail -q -n +2 cover/*.cov >> cover/coverage.covgo tool cover -func=cover/coverage.cov

如果我們想要獲得HTML格式的覆蓋率報告,我們需要添加以下命令:

go tool cover -html=cover/coverage.cov -o coverage.html
  1. 構建
    最後一旦代碼經過了完全測試,我們要對代碼進行編譯,從而構建可以執行的二進位檔案。
go build .
  1. linter
    這是我們在代碼中使用的第一個工具:linter。它的作用是檢查代碼風格/錯誤。這聽起來像是一個可選的工具,或者至少是一個“不錯”的工具,但它確實有助於在項目上保持一致的代碼風格。
    linter並不是go本身的一部分,所以如果要使用,你需要手動安裝它(之前的go-tools鏡像我們已經安裝過了)。
    使用方法相當簡單:只需在程式碼封裝上運行它(也可以指向. go檔案):
$ golint -set_exit_status $(go list ./... | grep -v /vendor/)

注意-set_exit_status選項。 預設情況下,golint僅輸出樣式問題,並帶有傳回值(帶有0返回碼),所以CI不認為是出錯。 如果指定了-set_exit_status,則在遇到任何樣式問題時,golint的返回碼將不為0。

3.2. Makefile

如果我們不想在.gitlab-ci.yml檔案中寫的太複雜,那麼我們可以把持續整合環境中使用的所有工具,全部打包在Makefile中,並用統一的方式調用它們。

這樣的話,.gitlab-ci.yml檔案就會更加簡潔了。當然了,Makefile同樣也可以調用*.sh指令檔

3.3. 配置樣本

3.3.1. .gitlab-ci.yml

image: go-tools:1.9.2stages:   - build  - test  - deploybefore_script:  - mkdir -p /go/src/gitlab.chain.cn/ZhangZhongcheng /go/src/_/builds  - cp -r $CI_PROJECT_DIR /go/src/gitlab.chain.cn/ZhangZhongcheng/demo  - ln -s /go/src/gitlab.chain.cn/ZhangZhongcheng /go/src/_/builds/ZhangZhongcheng    - cd /go/src/_/builds/ZhangZhongcheng/demounit_tests:  stage: test  script:     - make test  tags:     - demorace_detector:  stage: test  script:    - make race  tags:     - democode_coverage:  stage: test  script:    - make coverage  tags:     - democode_coverage_report:  stage: test  script:    - make coverhtml  only:  - master  tags:     - demolint_code:  stage: test  script:    - make lint    build:  stage: build  script:    - pwd    - go build .  tags:    - demobuild_image:  stage: deploy  script:    - make build_image  tags:    - demo    

3.3.2. Makefile

PROJECT_NAME := "demo"PKG := "gitlab.chain.cn/ZhangZhongcheng/$(PROJECT_NAME)"PKG_LIST := $(shell go list ./... | grep -v /vendor/)GO_FILES := $(shell find . -name '*.go' | grep -v /vendor/ | grep -v _test.go)test: ## Run unittests    @go test -v ${PKG_LIST}lint: ## Lint the files    @golint ${PKG_LIST} race: ## Run data race detector    @go test -race -short ${PKG_LIST}coverage: ## Generate global code coverage report    ./scripts/coverage.sh;    coverhtml: ## Generate global code coverage report in HTML    ./scripts/coverage.sh html;build_image:    ./scripts/buildDockerImage.sh   

3.3.3. coverage.sh

#!/bin/bash## Code coverage generationCOVERAGE_DIR="${COVERAGE_DIR:-coverage}"PKG_LIST=$(go list ./... | grep -v /vendor/)# Create the coverage files directorymkdir -p "$COVERAGE_DIR";# Create a coverage file for each packagefor package in ${PKG_LIST}; do    go test -covermode=count -coverprofile "${COVERAGE_DIR}/${package##*/}.cov" "$package" ;done ;# Merge the coverage profile filesecho 'mode: count' > "${COVERAGE_DIR}"/coverage.cov ;tail -q -n +2 "${COVERAGE_DIR}"/*.cov >> "${COVERAGE_DIR}"/coverage.cov ;# Display the global code coveragego tool cover -func="${COVERAGE_DIR}"/coverage.cov ;# If needed, generate HTML reportif [ "$1" == "html" ]; then    go tool cover -html="${COVERAGE_DIR}"/coverage.cov -o coverage.html ;fi# Remove the coverage files directoryrm -rf "$COVERAGE_DIR";

3.3.4. buildDockerImage.sh

#!/bin/bash#檢測GOPATHecho "檢測GOPATH"if [ -z "$GOPATH" ];thenecho "GOPATH 未設定"exit 1elseecho "GOPATH=$GOPATH"fi#初始化資料echo "初始化資料"new_version="1.0.0"old_version="1.0.0"golang_version="1.9.2"app_name="application"projust_root="demo"DOCKER_IMAGE_NAME="demo"REGISTRY_HOST="xxx.xxx.xxx.xxx:5000"path="/go/src/_/builds/ZhangZhongcheng/demo"#當前容器更換為舊標籤echo "當前容器更換為舊標籤"docker rmi $REGISTRY_HOST/$DOCKER_IMAGE_NAME:$old_version# 基於golang:1.9.2鏡像啟動的容器執行個體,編譯本項目的二進位可執行程式echo "基於golang:1.9.2鏡像啟動的容器執行個體,編譯本項目的二進位可執行程式"cd $pathgo build -o $app_nameecho "檢測 $app_name 應用"FILE="$path/$app_name"if [ -f "$FILE" ];thenecho "$FILE 已就緒"elseecho "$FILE 應用不存在"exit 1fi#docker構建鏡像 禁止在構建上下文之外的路徑 添加複製檔案#所以在此可以用命令把需要的檔案cp到 dockerfile 同目錄內 ,構建完成後再用命令刪除cd $path/scriptsecho "提取構建時需要的檔案"cp ../$app_name $app_name# 基於目前的目錄下的Dockerfile構建鏡像echo "基於目前的目錄下的Dockerfile構建鏡像"echo "docker build -t $REGISTRY_HOST/$DOCKER_IMAGE_NAME:$new_version ."docker build -t $REGISTRY_HOST/$DOCKER_IMAGE_NAME:$new_version .# 刪除本次產生的可執行檔 以及構建所需要的檔案echo "刪除本次產生的可執行檔 以及構建所需要的檔案"rm -rf $app_namerm -rf ../$app_name#查看鏡像echo "查看鏡像"docker images | grep $DOCKER_IMAGE_NAME#推送鏡像echo "推送鏡像"echo "docker push $REGISTRY_HOST/$DOCKER_IMAGE_NAME:$new_version"docker push $REGISTRY_HOST/$DOCKER_IMAGE_NAME:$new_versionecho "auto deploy"./automationDeployment.sh $new_version $old_version

3.3.5. automationDeployment.sh

#!/usr/bin/expect#指定shebang#設定逾時時間為3秒set ip xxx.xxx.xxx.xxxset password "xxxxxxx"set new_version [lindex $argv 0]set old_version [lindex $argv 1]spawn ssh root@$ipexpect {    "*yes/no" { send "yes\r"; exp_continue}    "*password:" { send "$password\r" }}expect "#*"send "cd /root/demo/\r"send "./docker_run_demo.sh $new_version $old_version\r"expect eof

3.3.6. Dockerfile

FROM golang:1.9.2#定義環境變數 alpine專用#ENV TIME_ZONE Asia/ShanghaiADD application /go/src/demo/WORKDIR /go/src/demoADD run_application.sh /root/RUN chmod 755 /root/run_application.shCMD sh /root/run_application.shEXPOSE 8080

3.3.7. run_application.sh

#!/bin/bash#映射ipcp /usr/share/zoneinfo/Asia/Shanghai  /etc/localtimecd /go/src/demo/./application

4. 結果

以下為部署成功後的:


result

轉載請註明出處: Golang基於Gitlab CI/CD部署方案

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.