Golang基于GitLab CI/CD部署方案

栏目: Go · 发布时间: 8年前

内容简介:持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。持续部署(Continuous Deployment)是通过自动化的构建、测试和部署循环来快速交付高质量的产品。某种程度上代表了一个开发团队工程化的程度,毕竟快速运转的互联网公司人力成本会高于机器,投资机器优化开发流程化相对也提高了人的效率,让 e

持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

持续部署(Continuous Deployment)是通过自动化的构建、测试和部署循环来快速交付高质量的产品。某种程度上代表了一个开发团队工程化的程度,毕竟快速运转的互联网公司人力成本会高于机器,投资机器优化开发流程化相对也提高了人的效率,让 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.2

USER root

Install golint

ENV GOPATH /go

ENV PATH ${GOPATH}/bin:$PATH

RUN mkdir -p /go/src/golang.org/x

RUN mkdir -p /go/src/github.com/golang

COPY 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 docker

RUN 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 expect

RUN apt-get update

RUN 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/bash

echo "提取构建镜像时需要的文件"

source_path="source"

mkdir -p $source_path/golang.org

mkdir -p $source_path/github.com

cp -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.com

echo "构建镜像"

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 settings

Please enter the gitlab-ci description for this runner:

# 示例:demo-test

Please enter the gitlab-ci tags for this runner (comma separated):

# 示例:demo

Whether to run untagged builds [true/false]:

# true

Please enter the executor: docker, parallels, shell, kubernetes, docker-ssh, ssh, virtualbox, docker+machine, docker-ssh+machine:

# docker

Please enter the default Docker image (e.g. ruby:2.1):

# go-tools:1.9.2(之前自己制作的镜像)

Golang基于GitLab CI/CD部署方案

成功后,可以看到GitL ab->你的项目->Settings -> CI/CD ->Runners settings页面下面有以下内容:

Golang基于GitLab CI/CD部署方案

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,其中所有的启动参数都会在[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常见的集成命令。

包列表,正如在官方文档中所描述的那样,Go项目是包的集合。下面介绍的大多数工具都将使用这些包,因此我们需要的第一个命令是列出包的方法。我们可以用go list子命令来完成:

go list ./...

请注意,如果我们要避免将我们的工具应用于外部资源,并将其限制在我们的代码中。 那么我们需要去除vendor目录,命令如下:

go list ./... | grep -v /vendor/

单元测试,这些是您可以在代码中运行的最常见的测试。每个.go文件需要一个能支持单元测试的_test.go文件。可以使用以下命令运行所有包的测试:

go test -short $(go list ./... | grep -v /vendor/)

数据竞争,这通常是一个难以逃避解决的问题,Go工具默认具有(但只能在Linux/amd64、FreeBSD/amd64、Darwin/amd64和Windows/amd64上使用):

go test -race -short $(go list . /…| grep - v /vendor/)

代码覆盖,这是评估代码的质量的必备工具,并能显示哪部分代码进行了单元测试,哪部分没有。

要计算代码覆盖率,需要运行以下脚本:

PKG_LIST=$(go list ./... | grep -v /vendor/)

for package in ${PKG_LIST}; do

go test -covermode=count -coverprofile "cover/${package##*/}.cov" "$package" ;

done

tail -q -n +2 cover/*.cov >> cover/coverage.cov

go tool cover -func=cover/coverage.cov

如果我们想要获得HTML格式的覆盖率报告,我们需要添加以下命令:

go tool cover -html=cover/coverage.cov -o coverage.html

构建,最后一旦代码经过了完全测试,我们要对代码进行编译,从而构建可以执行的二进制文件。

go build .

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.2

stages: 

- build

- test

- deploy

before_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/demo

unit_tests:

stage: test

script: 

- make test

tags: 

- demo

race_detector:

stage: test

script:

- make race

tags: 

- demo

code_coverage:

stage: test

script:

- make coverage

tags: 

- demo

code_coverage_report:

stage: test

script:

- make coverhtml

only:

- master

tags: 

- demo

lint_code:

stage: test

script:

- make lint    

build:

stage: build

script:

- pwd

- go build .

tags:

- demo

build_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 generation

COVERAGE_DIR="${COVERAGE_DIR:-coverage}"

PKG_LIST=$(go list ./... | grep -v /vendor/)

# Create the coverage files directory

mkdir -p "$COVERAGE_DIR";

# Create a coverage file for each package

for package in ${PKG_LIST}; do

go test -covermode=count -coverprofile "${COVERAGE_DIR}/${package##*/}.cov" "$package" ;

done ;

# Merge the coverage profile files

echo 'mode: count' > "${COVERAGE_DIR}"/coverage.cov ;

tail -q -n +2 "${COVERAGE_DIR}"/*.cov >> "${COVERAGE_DIR}"/coverage.cov ;

# Display the global code coverage

go tool cover -func="${COVERAGE_DIR}"/coverage.cov ;

# If needed, generate HTML report

if [ "$1" == "html" ]; then

go tool cover -html="${COVERAGE_DIR}"/coverage.cov -o coverage.html ;

fi

# Remove the coverage files directory

rm -rf "$COVERAGE_DIR";

3.3.4. buildDockerImage.sh

#!/bin/bash

#检测GOPATH

echo "检测GOPATH"

if [ -z "$GOPATH" ];then

echo "GOPATH 未设定"

exit 1

else

echo "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 $path

go build -o $app_name

echo "检测 $app_name 应用"

FILE="$path/$app_name"

if [ -f "$FILE" ];then

echo "$FILE 已就绪"

else

echo "$FILE 应用不存在"

exit 1

fi

#docker构建镜像 禁止在构建上下文之外的路径 添加复制文件

#所以在此可以用命令把需要的文件cp到 dockerfile 同目录内 ,构建完成后再用命令删除

cd $path/scripts

echo "提取构建时需要的文件"

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_name

rm -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_version

echo "auto deploy"

./automationDeployment.sh $new_version $old_version

3.3.5. automationDeployment.sh

#!/usr/bin/expect

#指定shebang

#设定超时时间为3秒

set ip xxx.xxx.xxx.xxx

set password "xxxxxxx"

set new_version [lindex $argv 0]

set old_version [lindex $argv 1]

spawn ssh root@$ip

expect {

"*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/Shanghai

ADD application /go/src/demo/

WORKDIR /go/src/demo

ADD run_application.sh /root/

RUN chmod 755 /root/run_application.sh

CMD sh /root/run_application.sh

EXPOSE 8080

3.3.7. run_application.sh

#!/bin/bash

#映射ip

cp /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime

cd /go/src/demo/

./application

4. 结果

以下为部署成功后的截图:

Golang基于GitLab CI/CD部署方案

原文链接: http://www.chairis.cn/blog/article/96


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

The Black Box Society

The Black Box Society

Frank Pasquale / Harvard University Press / 2015-1-5 / USD 35.00

Every day, corporations are connecting the dots about our personal behavior—silently scrutinizing clues left behind by our work habits and Internet use. The data compiled and portraits created are inc......一起来看看 《The Black Box Society》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

html转js在线工具
html转js在线工具

html转js在线工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具