多项目下CI管理方案的设计与实现

2,021 阅读5分钟

前言

本文原创,著作权归WGrape所有,未经授权,严禁转载

一、背景介绍

在团队开发中,工作并不只是分而治之,而是分、治以及集成。基于CI可以实现强大且深度定制的服务自动化,现在已经越来越多的团队开始重视并投入到CI建设的工作中。

大部分公司的CI建设是基于Gitlab CI,在项目根目录下创建.gitlab-ci.yml文件即可简单快速的实现,项目结构如下所示

- .gitlab
-    check_code.sh
-    unit_test.sh
- cmd
-    app
- api
-    define
- service
-    AService
-    BService
- .gitignore
- .gitlab-ci.yml

在单体架构下,上面这种基于单项目下的CI建设没有任何问题。但是在微服务架构下,就会遇到非常棘手的多项目下CI管理的问题。

由于微服务架构下,一套代码被划分到多个代码库中,多个代码库下都有自己的CI代码,一旦CI中任意一个流程有变动,那么所有项目都需要配合修改,造成的整体联动调整过大。

所以本文会设计并实现一种简单易用的方式,以解决微服务架构下多项目的CI管理问题。

二、设计方案

1、本地管理

本地管理的设计思想是基于快拷贝。即仍然使用单项目下的CI代码,但是远程的一个仓库中会存储所有项目通用的CI代码。

image

当每次需要变动的时候,都会把远程通用的CI代码拷贝到本地各个单项目中,然后本地的各个项目再单独修改并提交,完成CI的执行。

image

2、远程管理

远程管理的设计思想是基于WORA,即write once, run anywhere(一次编写,到处运行)

image

(1) 一次编写

只维护一套通用的CI代码CIManager

(2) 到处运行

每个代码库只需要有自己的一个.gitlab-ci.yml文件,且这个文件内容会保持精简而通用,如下所示

image: golang:1.17
variables:
  PROJECT_NAME: {{PROJECT_NAME}}

before_script:
  - echo '====== CI Start Running ========='
  - cd /temp && git clone git.xxx.com/xxx/CIManager && cd CIManager && cp -r . /yourproject && cd /yourproject && bash remote_mgr.sh runci

after_script:
  - echo '====== CI Stopped Successfully ========='

当提交代码时,在远程的Runner机器上,会自动拉取CIManager代码库并运行start.sh脚本,完成CI的执行。

三、通用CI的设计

多项目下CI管理方案的一个重要思想,就是设计一个通用的CI逻辑。这个CI逻辑寄托在一个叫做CIManager的代码库中。

image

1、目录结构

CIManager代码库的目录结构如下所示

  • .gitlab目录 :存放与CI相关的脚本逻辑
  • .gitlab/hook目录 :存放与git相关的钩子
  • .gitlab/include目录 :存放需要引入的脚本
  • .gitlab/apidoc_gen.sh文件 :文档自动生成脚本
  • .gitlab/check_code.sh文件 :代码检查脚本
  • .gitlab/config_check.sh文件 :配置检查脚本
  • .gitlab/godep_check.sh文件 :依赖检查脚本
  • .gitlab/unit_test.sh文件 :单元测试脚本
  • .gitlab/pre_install.sh文件 :预安装脚本
  • .gitlab/print_env.sh文件 :打印环境和本地变量脚本
  • .gitlab/mock_ci.sh文件 :本地CI模拟执行脚本
  • .golangci.yml文件 :代码检查的配置文件
  • .gitlab-ci.yml文件 :gitlab CI配置文件

2、接入Web Hook

CIManager项目内部接入了不同的Web Hook,通过接入Web Hook实现各种场景需求,如钉钉消息通知。

curl -H 'Content-type: application/json' -d "{"msgtype":"text", "text": {"content":"${MESSAGE}"}}" "https://oapi.dingtalk.com/robot/send?access_token=${DING_ACCESS_TOKEN}"

3、消息通知

为了方便知道CI的内部执行过程,在CI中的任何一个过程,如果出现失败,都会发出详细的失败通知。包括失败原因、操作人等。基于这个场景需求,在CIManger内部定义了一个简单的CI消息通知,其字段结构和含义如下所示

字段含义
操作-根据分支不同,生成不同的操作名,如请求合并到主分支
项目${CI_PROJECT_NAME}项目的名称
操作人${GITLAB_USER_EMAIL}提交这个请求的操作人
失败原因${FAILURE_REASON}执行CI失败的原因
查看详情 ${CI_PIPELINE_URL}执行Pipeline的地址

实现原理是通过Gitlab系统变量和自定义变量实现脚本间信息的传递。

四、如何实现

1、本地管理的实现

在项目根目录下有一个local_mgr.sh脚本,它会提供一系列的命令实现对多个项目的管理。它的.gitlab-ci.yml配置内容如下 :

# could not use go:1.13
# Using Docker executor with image go:1.13 ...
# Pulling docker image go:1.13 ...
# ERROR: Job failed: Error response from daemon: pull access denied for go, repository does not exist or may require 'docker login': denied: requested access to the resource is denied (executor_docker.go:188:3s)
# Variables: https://docs.gitlab.com/ee/ci/variables/index.html
image: golang:1.17
variables:
  GOPATH: /go
  PROJECT_NAME: {{PROJECT_NAME}}
  PROJECT_ID: {{PROJECT_ID}}
  PROJECT_PATH: {{PROJECT_PATH}}
  DING_NOTICE_KEYWORD: {{DING_NOTICE_KEYWORD}}
  GITLAB_API_TOKEN: {{GITLAB_API_TOKEN}}
  GITLAB_HOST: {{GITLAB_HOST}}
  DING_ACCESS_TOKEN: {{DING_ACCESS_TOKEN}}

before_script:
  - echo '====== CI Stage Start Running ========='
  - bash .gitlab/print_env.sh

after_script:
  - echo '====== CI Stage Stopped Successfully ========='

stages:
  - detect_project
  - godep_check
  - config_check
  - apidoc_gen

detect_project:
  stage: detect_project
  script:
    - bash .gitlab/pre_install.sh
    - bash .gitlab/check_code.sh
    - bash .gitlab/unit_test.sh
  only:
    - merge_requests
    - master
    - test

godep_check:
  stage: godep_check
  script:
    - bash .gitlab/godep_check.sh
  only:
    - merge_requests
    - master
    - test

config_check:
  stage: config_check
  script:
    - bash .gitlab/config_check.sh
  only:
    - merge_requests
    - master
    - test

apidoc_gen:
  stage: apidoc_gen
  script:
    - bash .gitlab/pre_install.sh
    - bash .gitlab/apidoc_gen.sh
  only:
    - merge_requests
    - test

(1) fastcopy命令

bash local_mgr.sh fastcopy ${sourceDir} ${targetDir} 

实现原理是先将远程通用的CI代码拉到本地,然后全量覆盖到本地项目内。这一系列操作被封装集成在fastcopy命令中。

2、远程管理的实现

在项目根目录下有一个remote_mgr.sh脚本,它会提供一系列的命令实现对多个项目的管理。

(1) runci命令

注意事项 :此命令只允许Runner调用和执行

实现原理是每一个项目都有一个自己的.gitlab-ci.yml配置文件,当提交代码触发CI后,在Runner机器上执行before_script中的脚本,完成在Runner机器上执行CIManager中通用的CI逻辑。

3、开源项目CIManager

开源项目CIManager正是基于远程管理方式实现的多项目CI管理框架,更多请查看原项目。

4、使用CIManager的项目例子

基于CIManager项目构建的apimock-example,轻松实现更加快速高效的CI管理方案,在这里查看Pipline运行示例。

五、总结

对于多项目下的CI管理方案,本文设计并实现了本地管理和远程管理者两种方案。根据自己的需要选择合适的方案即可,不过无论使用哪种方案,都可以简单高效解决我们的问题。