对Golang项目进行CI/CD化和容器化 (DaoCloud大法好!)

持续集成 Continuous Integration(CI)和持续交付 Continuous Delivery(CD),在当前 DevOps 的趋势下,具有支柱性地位。

软件交付管道以快速、自动化和可重复的方式从源代码生成发布版本,就类似于工厂里的装配线以快速、自动化、可重复的方式从原材料生产出消费品,完成这项工作的总体设计我们就称之为持续交付,启动装配线的过程我们称之为持续集成

CI/CD的好处:提升开发效率,加速开发周期,及时发现开发过程中的错误,简化部署和运维过程。

为什么选择 DaoCloud:一条🐲服务

本文基于 DaoCloud, 描述如何将自己的Golang项目进行 容器化CI/CD 化。

注册DaoCloud

https://www.daocloud.io/

登陆 — 选择github登陆—授予权限—账户名和密码

定义项目(服务)

这里使用 gin 生成一个hello world 服务,提供一个/ping接口,绑定在8082端口

/hello_dao_cloud/main.go:

package main

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

func HelloHandler(c *gin.Context)  {
	c.JSON(200, gin.H{
		"msg": "hello dao cloud",
	})
}

func main() {
	r := gin.Default()
	r.GET("/ping", HelloHandler)
	r.Run(":8082")
}

使用 go.mod(推荐)

//  go.mod
module hello_dao_cloud

go 1.14

require github.com/gin-gonic/gin v1.6.3

本地运行

$ go run main.go
$ curl http://localhost:8082/ping
{"msg":"hello dao cloud"}
# 也可以直接到浏览器访问

创建仓库

github(注册时绑定的那个)创建一个 repo,作为代码仓库。项目代码 push 到这个仓库,CI 工具会从这里面拉取再执行启动脚本。

项目和仓库绑定

到项目目录下:

echo "# hello_dao_cloud" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin git@xxxxxxxxxx/hello_dao_cloud.git # 这里改成自己的项目地址
git push -u origin master

如果显示没有权限,则需要去设置 ssh 或 自己用账号密码登陆

再把所有项目代码 push上去

$ git add .
$ git commit -m "project init"
$ git push

刷新项目页面,发现项目文件已经上传到了项目路径下

.idea文件是 goland 的配置信息,可以在 .gitignore里声明 .idea,没有则无视)

创建DaoCloud项目

创建项目

项目 — 选择项目 — 项目名称 — 设置代码源(自己的仓库内找到repo)—创建项目

新创建的项目内选择:流程定义,这里会列出三个阶段:测试阶段构建阶段发布阶段,需要分别配置

测试阶段

如果给代码加上了单元测试,则需要配置:

  • 运行脚本内填入:go test -v
  • 基础镜像填入:golang1.14
  • 保存

构建阶段

自定义dockerfile

DaoCloud是基于docker的,构建镜像后将自动发布到镜像仓库。

所以需要把自己的项目构建为 docker 镜像,需要创建Dockerfile文件:(注意首字母大写)

# 基础镜像
FROM golang:latest as builder
# go mod
ENV GO111MODULE on
ENV CGO_ENABLED=0
ENV GOPROXY https://goproxy.io

# 工作目录
WORKDIR /app
COPY . .
# 这里将Golang依赖定义相关文件的copy放到最前面
COPY go.mod go.sum ./
RUN go mod download

# 编译 (注意 hello_dao_cloud 在 docker 容器里编译,并没有在宿主机现场编译)
RUN go build -o main .

FROM alpine:latest
WORKDIR /app/
# alpine镜像没有ca-certificates,需要进行安装
RUN apk update && apk --no-cache add ca-certificates
# 从builder stage的镜像里将二进制文件copy过来
COPY --from=builder /app/main .

# 声明运行时容器提供服务端口
EXPOSE 8082
CMD ["./main"]

镜像内运行

本地构建镜像来验证

# 构建镜像:
$ docker build -t hello_dao_cloud .
# 验证镜像:
$ docker images
hello_dao_cloud     latest              4f43350f6377        About a minute ago   22.8MB
# 创建并运行一个新容器:
$ docker run -p 8082:8082 hello_dao_cloud
$ curl http://localhost:8082/ping
{"msg":"hello dao cloud"}

依然,需要push到仓库里面

$ git add .
$ git commit -m "Dockerfile"
$ git push

DaoCloud构建阶段

dockerfile创建完后,到 DaoCloud 控制台的 构建阶段

默认构建任务 > 使用本地dockerfile > 保存

这时可以到执行记录里面发现正在进行编译了

构建日志:

clone 仓库的代码 然后执行build流程,对应dockerfile内到每一行命令

docker build过程完成后,会将镜像 Push 到 DaoClouod 的公共仓库内

发布阶段

这一步构建完成后,可以到自己的机器上 docker pull然后 docker run,显然这是不够自动化的

绑定主机

集群管理 > 导入主机 > 选择对应操作系统

这时候到自己的机器上运行这个脚本(前提是机器上已经安装了docker)

$ curl -sSL https://get.daocloud.io/daomonit/install.sh | sh -s bxxxxxxxxxxxxxxxxxx6

运行完成后,等待连接… 会变为 恭喜接入成功

机器管理界面以可视化的方式展示了机器上的docker的容器(docker ps)、镜像(docker image)和网络等信息。

项目发布

测试和构建其实相当于 CI 阶段,发布阶段即为 CD

创建应用

应用 > 创建应用 > 应用名称、选择主机 > 下一步

应用设置界面就相当于配置 docker run的参数,设置端口映射、存储映射和环境变量等

立即部署后,可以看到日志显示部署完成:

2020-05-06 12:08:16:[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
2020-05-06 12:08:16: - using env: export GIN_MODE=release
2020-05-06 12:08:16: - using code: gin.SetMode(gin.ReleaseMode)
2020-05-06 12:08:16:
2020-05-06 12:08:16:[GIN-debug] GET /ping --> main.HelloHandler (3 handlers)
2020-05-06 12:08:16:[GIN-debug] Listening and serving HTTP on :8082
运行(机器内的docker)

浏览器或 postman测试一下接口(使用自己机器的IP,阿里云或腾讯云的安全组内要设置8082端口对外):

$ curl http://yourhost:8082/ping
{"msg":"hello dao cloud"}
# 也可以直接到浏览器访问
云隧道

如果自己的机器未接入公网(自己的电脑),DaoCloud也提供了内网穿透功能

应用 > 云隧道 > 创建

隧道生效后,会给出云地址,访问这个地址,即可以成功访问

回到项目本身

项目 > 流程定义 > 发布阶段 > 添加并行任务 > 发布 > 发布到自有主机 > 选择应用名称 > 创建任务

这样一来,整个CI/CD流程部署完成,

持续集成

这样整个持续集成流程就搭建起来啦!

简述一个交付的过程:更改项目push到仓库自动执行CI/CD流程查看结果

这样一来我们的注意力会集中到业务开发上,开发完成推到仓库,后续过程就不用管啦!

比如我们再加一个接口:

func ByeHandler(c *gin.Context)  {
	name := c.Query("name")
	if name == "" {
		name = "friend"
	}
	c.JSON(200, gin.H{
		"msg": "Bye " + name + " !",
	})
}

// 绑定到 /bye 接口下
r.GET("/bye", ByeHandler)

初次发布耗时较长,后面的发布,由于缓存了部分依赖镜像,速度会提升

image-20200506174218873

运行

$ curl http://yourhost:8082/bye?name=Aris
{"msg":"Bye Aris !"}

邮件提醒

相应的,每次交付,都会收到一封邮件(CI/CD任何一环出现错误,邮件内也会声明出来)

总结

借助DaoCloud这个CI/CD产品,进行开发的持续交付,实现自动化的交付流程。

这个过程用时序图描述为:

末尾再回顾一下整个部署过程:

  1. 使用Github注册DaoCLoud
  2. 开发自己的项目
    • 配置好DockerFile
    • 发布到仓库
  3. 创建DaoCloud项目
    • 选择仓库,创建项目
    • 定义测试阶段
    • 定义构建阶段,选择DockerFIle,查看构建结果
    • 定义发布阶段
      • 绑定主机
      • 创建应用
      • 添加发布任务到主机
  4. 进行持续集成

分享: