持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。
几个概念
- 持续集成(Continuous Integration):频繁地(一天多次)将代码集成到主干。让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。“持续集成并不能消除 Bug,而是让它们非常容易发现和改正。”
- 持续交付(Continuous Delivery):频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的。
- 持续部署(continuous Deployment):代码通过评审以后,自动部署到生产环境。是持续部署是持续交付的下一步,持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。
持续集成工具
[Jenkins](https://www.jenkins.io/)
[GitLab CI](https://docs.gitlab.com/ee/topics/build_your_application.html)
TeamCity
Travis CI
Bamboo
CircleCI
Gitlab CI 工作逻辑框架
GitLab CI/CD 是GitLab Continuous Integration(Gitlab持续集成)的简称。GitLab 自GitLab 8.0开始提供了持续集成的功能,且对所有项目默认开启。只要在项目仓库的根目录添加.gitlab-ci.yml文件,并且配置了Runner(运行器),那么每一次push或者合并请求(Merge Request)都会触发CI Pipeline。
GitLab Runner
GitLab Runner 是一个开源项目,可以运行在 GNU / Linux,macOS 和 Windows 操作系统上。每次push的时候 GitLab CI 会根据.gitlab-ci.yml配置文件运行你流水线(Pipeline)中各个阶段的任务(Job),并将结果发送回 GitLab。GitLab Runner 是基于 Gitlab CI 的 API 进行构建的相互隔离的机器(或虚拟机)。GitLab Runner 不需要和 Gitlab 安装在同一台机器上,且考虑到 GitLab Runner 的资源消耗问题和安全问题,也不建议这两者安装在同一台机器上。
Gitlab Runner 分为三种:
共享Runner(Shared runners)
专享Runner(Specific runners)
分组Runner(Group Runners)
Pipelines
Pipelines 是分阶段(stage)执行的构建任务。如:安装依赖、运行测试、打包、部署开发服务器、部署生产服务器等流程。每一次push或者Merge Request都会触发生成一条新的Pipeline。若一次推送包含了多个提交,则管道与最后那个提交相关联,管道(pipeline)就是一个分成不同阶段(stage)的作业(job)的集合。
下面是流水线示例图:
Stages
Stages 表示构建阶段,可以理解为上面所说“安装依赖”、“运行测试”等环节的流程。我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:
- 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始(当然可以在.gitlab-ci.yml文件中配置上一阶段失败时下一阶段也执行)
- 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功
- 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败
下面是一个流水线内的阶段任务示例图:
Jobs
Jobs 表示构建的作业(或称之为任务),表示某个 Stage 里面执行的具体任务。我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:
- 相同 Stage 中的 Jobs 无执行顺序要求,会并行执行
- 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功
- 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 也失败(可以在.gitlab-ci.yml文件中配置允许某 Job 可以失败,也算该 Stage 成功)
.gitlab-ci.yml
GitLab 中默认开启了 Gitlab CI/CD 的支持,但是要是用这个功能,我们需要告诉系统,我们需要执行什么样的pipeline,在gitlab里面,这通过 .gitlab-ci.yml 来实现。
且使用YAML文件.gitlab-ci.yml来管理项目构建配置。该文件需要存放于项目仓库的根目录(默认路径,可在 GitLab 中修改),它定义该项目的 CI/CD 如何配置。所以,我们只需要在.gitlab-ci.yml配置文件中定义流水线的各个阶段,以及各个阶段中的若干作业(任务)即可。
下面是.gitlab-ci.yml文件的一个简单的Hello World示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 定义 test 和 package 两个 Stages
stages:
- test
- package
# 定义 package 阶段的一个 job
package-job:
stage: package
script:
- echo "Hello, package-job"
- echo "I am in package stage"
# 定义 test 阶段的一个 job
test-job:
stage: test
script:
- echo "Hello, test-job"
- echo "I am in test stage"
以上配置中,用 stages 关键字来定义 Pipeline 中的各个构建阶段,然后用一些非关键字来定义 jobs。每个 job 中可以可以再用 stage 关键字来指定该 job 对应哪个 stage。job 里面的script关键字是每个 job 中必须要包含的,它表示每个 job 要执行的命令。
Badges
Badges 即:徽章,当 Pipelines 执行过程中或者执行完成时会生成徽章,你可以将这些徽章加入到你的README.md文件中,便于从仓库主页看到最新的构建状态。
Gitlab CI 实践
如上所述,我们的所有测试都需要提供硬件的基础环境(Runner)来为自动化的集成测试/部署提供底层基建,所以我们要做的第一件事情就是安装gitlab Runner
gitlab Runner配置
安装gitlab Runners
在此以CentOS为例进行说明,其他平台参考 官方指南。1
2
3
4
5
6
7
8 添加官方的repo.
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash
yum 安装Gtilab Runner.
sudo yum install gitlab-runner
rpm离线安装事先下载好的 Gitlab Runner rpm包。前置需要完成git的安装。
rpm -ivh gitlab-runner-10.5.0-1.x86_64.rpm
注册 Gitlab
安装了 GitLab Runner 之后,就可以为 GitLab 中的仓库注册一个 Runner,注册的交互式命令如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 输入注册命令
sudo gitlab-runner register
输入公司的 GitLab 网站地址
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
http://gitlab.xxxx.com/
你项目仓库的token,token可以在 Settings -> CI/CD -> Runners settings 中找到.
Please enter the gitlab-ci token for this runner
xxx
输入描述这个 runner 的名称
Please enter the gitlab-ci description for this runner
[hostame] my-runner
输入 runner 的标签
Please enter the gitlab-ci tags for this runner (comma separated):
my-tag,another-tag
输入 runner 的执行器.
Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
shell
Gitlab Runner 常用命令汇总
面的表格中列出了一些常用的Gitlab Runner命令,以供参考:
| 命令 | 描述 |
|---|---|
| gitlab-runner run | 运行一个runner服务 |
| gitlab-runner register | 注册一个新的runner |
| gitlab-runner start | 启动服务 |
| gitlab-runner stop | 关闭服务 |
| gitlab-runner restart | 重启服务 |
| gitlab-runner status | 查看各个runner的状态 |
| gitlab-runner unregister | 注销掉某个runner |
| gitlab-runner list | 显示所有运行着的runner |
| gitlab-runner verify | 检查已注册的运行程序是否可以连接到GitLab,但它不验证GitLab Runner服务是否正在使用运行程序。 |
任务配置
任务配置的一个示例
接下来,用一个实际项目来演示 GitLab CI/CD 的配置和使用,其中主要包括:编译测试、项目打包、部署服务、Sonar手动检查、Sonar定时检查五个阶段。
下面用一个传统的 Java web 项目(这里称之为cidemo)和Tomcat来作为示例,并用来展示常用配置的使用。当我每次push代码或者Merge Request时,都会生成一条流水线,且会自动执行我们上面所说的一些阶段,而Sonar手动检查我们设置为手动操作,且再额外配置Sonar定时检查的任务。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67# 定义stages
stages:
- test
- install
- run
- sonar
# 定义安装包的存放位置和Tomcat服务器的地址的变量,便于后续部署使用.
variables:
CIDEMO_PACKAGE_DIR: '/home/gitlab-runner/packages/cidemo/'
SERVER_HOME_DIR: '/home/gitlab-runner/tomcat/cidemo-tomcat/'
###################### 构建编译和单元测试的job. #######################
编译测试任务:
stage: test
only:
- branches
script:
- mvn clean test
###################### Maven安装得到war包的job. #######################
打包任务:
stage: install
only:
- develop
script:
- mvn install
- echo '准备将最新的war包复制、保存到某个目录里面供后续使用.'
- rm -rf $CIDEMO_PACKAGE_DIR/*.war
- cp target/*.war $CIDEMO_PACKAGE_DIR/cidemo.war
####################### 部署运行war包的job. #######################
部署运行任务:
stage: run
only:
- develop
script:
- echo '准备部署和运行war包!(为了方便部署到了Tomcat中运行)'
- cd $SERVER_HOME_DIR
- sh bin/shutdown.sh
- rm -rf webapps/cidemo.war
- cp $CIDEMO_PACKAGE_DIR/cidemo.war $SERVER_HOME_DIR/webapps/cidemo.war
- nohup sh ./bin/startup.sh > logs/cidemo_nohup.log 2>&1 &
###################### Sonar手动构建的job. #######################
Sonar手动检查:
stage: sonar
when: manual
only:
- develop
script:
- echo '准备对项目代码做sonar的质量检查!'
- mvn compile && mvn sonar:sonar -Dsonar.host.url=http://172.16.34.102:9000 -Dsonar.login=497a0e0e2fc07f64c4b54edc17bb47dfa251ba34
###################### Sonar每晚定时构建的job. #######################
Sonar定时检查:
stage: sonar
only:
- schedules
script:
- echo '开始定时对项目代码做sonar的质量检查!'
- mvn compile && mvn sonar:sonar -Dsonar.host.url=http://172.16.34.102:9000 -Dsonar.login=497a0e0e2fc07f64c4b54edc17bb47dfa251ba34
Gitlab CI/CD yaml 常用配置介绍
开始构建之前.gitlab-ci.yml文件定义了一系列带有约束说明的任务。这些任务都是以任务名开始并且至少要包含script部分,.gitlab-ci.yml允许指定无限量 jobs。每个 jobs 必须有一个唯一的名字,且名字不能是下面列出的保留字段:
| Keyword | Required | Description |
| ————- | ——– | ———————————————————————————- |
| script | yes | Runner执行的命令或脚本 |
| extends | no | 定义此作业将继承的父作业(GitLab 11.3 引入),重定义参数覆盖,未定义参数继承父任务 |
| image | no | 所使用的docker镜像,查阅使用docker镜像 |
| services | no | 所使用的docker服务,查阅使用docker镜像 |
| stage | no | 定义job stage(默认:test) |
| type | no | stage的别名(已弃用) |
| variables | no | 定义job级别的变量 |
| only | no | 定义一列git分支,并为其创建job |
| except | no | 定义一列git分支,不创建job |
| tags | no | 定义一列tags,用来指定选择哪个Runner(同时Runner也要设置tags) |
| allow_failure | no | 允许job失败。失败的job不影响commit状态 |
| when | no | 定义何时开始job。可以是on_success,on_failure,always或者manual |
| dependencies | no | 定义job依赖关系,这样他们就可以互相传递artifacts |
| cache | no | 定义应在后续运行之间缓存的文件列表 |
| before_script | no | 重写一组在作业前执行的命令 |
| after_script | no | 重写一组在作业后执行的命令 |
| environment | no | 定义此作业完成部署的环境名称 |
| coverage | no | 定义给定作业的代码覆盖率设置 |
| etry | no | 定义在发生故障时可以自动重试作业的时间和次数 |
| parallel | no | 定义应并行运行的作业实例数 |
接下来对其中的一些重要管检测进行补充说明
stages
stages 用来定义可以被 job 调用的 stages。stages 的规范允许有灵活的多级 pipelines。
stages中的元素顺序决定了对应job的执行顺序:
- 相同 stage 的 job 可以平行执行。
- 下一个 stage 的 job 会在前一个 stage 的 job 成功后开始执行。
接下仔细看看这个例子,它包含了3个 stage:1
2
3
4stages:
- build
- test
- deploy
- 首先,所有 build 的 jobs 都是并行执行的。
- 所有 build 的 jobs 执行成功后,test 的 jobs 才会开始并行执行。
- 所有 test 的 jobs 执行成功,deploy 的 jobs 才会开始并行执行。
- 所有的 deploy 的 jobs 执行成功,commit才会标记为success。
- 任何一个前置的 jobs 失败了,commit会标记为failed并且下一个 stages 的 jobs 都不会执行。
这有两个特殊的例子值得一提:
- 如果.gitlab-ci.yml中没有定义stages,那么 job’s stages 会默认定义为build,test和deploy。
- 如果一个 job 没有指定 stage,那么这个任务会分配到 test stage。