文章目录(Table of Contents)
简介
CI(continuous integration)
表示持续集成。他的基本思想是让一个自动化程序监测一个或是多个源代码仓库是否有变更。当有变更推送(push/merge
)到仓库的时候,他会检测到更改,并进行相关的单元测试等。
Gitlab-CI
是 Gitlab
中内置的进行持续集成的工具。它提供了一个叫 Gitlab-runner 的软件,只要在对应的平台(机器或 docker
)上下载并运行这个命令行软件,并输入从 gitlab
交互界面获取的 token
,就可以把当前机器和对应的 gitlab-ci
流程绑定,也即:每次跑 ci
都在这个平台上进行。
Gitlab-CI
的所有流程都是可视化的,每个流程节点的状态可以在 gitlab
的交互界面上看到,包括执行成功或失败。如下图所示:

本文会对 Gitlab-CI
的使用进行详细的介绍。
参考资料
- Gitlab-ci :从零开始的前端自动化部署,这一篇会介绍的比较详细
- Gitlab-CI 使用教程,这一篇对
.gitlab-ci.yml
中各个关键词介绍会比较详细 - Git 入门指南,非常详细的
git
的入门说明
Gitlab-CI 涉及的抽象概念
Pipeline 和 Job
Pipeline 是 Gitlab 根据项目的 .gitlab-ci.yml
文件执行的流程,它由许多个任务节点组成,而这些Pipeline 上的每一个任务节点,都是一个独立的 Job
。
在配置 yml
文件时,每个 Job
都会配置一个 stage
属性,来表示这个 Job
所处的阶段。一个 Pipleline
有若干个 stage
,每个 stage
上有至少一个 Job(一个 stage 可以有多个 jobs),如下图所示,这张图会在后面有一个详细的说明:

Runner
Runner 可以理解为在特定的机器上,根据 .gitlab-ci.yaml 文件,对项目执行 pipeline 的程序。Runner 可以分为两种:
Shared Runner
(共享型),所有项目都可以使用,只可以由系统管理员创建。通常情况下,是Gitlab 平台提供的免费使用的 runner 程序,它由 Google 云平台提供支持,每个开发团队有十几个。对于公共开源项目是免费使用的,如果是私人项目则有每月 2000 分钟的 CI 时间上限。Specific Runner
(指定型),只有特定的项目可以使用,自己部署服务器,然后注册为 Runner。gitlab 给我们提供了一个叫gitlab-runner
的命令行软件,只要在对应机器上下载安装这个软件,并且运行 gitlab-runner register 命令,然后输入从 gitlab-ci 交互界面获取的 token 进行注册, 就可以在自己的机器上远程运行 pipeline 程序了。
YML 文件的基本语法规则
CI 流程的运行控制,决定于项目根目录下编写的配置文件—— .gitlab-ci.yml,正因如此,我们需要掌握 YML 的基本语法规则。YML 是一种编写配置文件的语言,比 JSON 更为简洁和方便,因此,我们首先要掌握的就是 YML 文件的编写语法。
下面是一个最简单的 YML 文件:
- install-job: # 注释
- tags:
- - sss
- stage: install
- script:
- - npm install
从中可以看两点:
- YML 通过缩进组织层级
- YML 里允许通过 # 符号编写注释
YML 中数组的写法
在 YML 中数组使用如下的形式进行书写,
- colors
- - red
- - blue
- - yellow
下面是 JSON 中的数组的写法:
- { "colors": ["red","blue","yellow"] }
YML 中字典的写法
在 YML 中也可以利用缩进来完成字典形式的表达:
- people:
- name: zhangsan
- age: 14
这个在 JSON 中等价于下面的形式:
- {
- "people": {
- "name": "zhangsan"
- "age": 14
- }
- }
需要注意的是,在 YML 中一般不需要给字符串增加双引号或是单引号。
.gitlab-ci.yml 常用配置
在了解了 YML
文件的语法格式后,接下来需要了解的就是 .gitlab-ci.yml
独特的配置关键字。这些关键字将在 .gitlab-ci.yml
中使用,并用来控制一个 pipeline
具体的运作过程。下面我们会介绍常见的 .gitlab-ci.yml
中的关键字。
image
该关键字指定一个任务(job)所使用的 docker 镜像。例如image: python:latest
使用 Python 的最新镜像。或是 image: python:3.7
指定某一个特定版本的 python。
stage 与 stages
stages 是定义在 YML 文件在外层的内容,他的值是一个数组,用于定义一个 pipeline 不同的流程节点(可以认为是执行指令的先后顺序)。在每一个 job 中,我们需要指定 stage,从而可以指定不同 job 的执行顺序。看下面的例子:
- image: python:3.7
- stages: # 这里定义 pipeline
- - build
- - doc
- - test
- build_1: # 这里是一个 job
- stage: build
- script:
- - echo $PWD
- build_2:
- stage: build # 与 job:build_1 的 stage 相同
- script:
- - echo $PWD
- doc_1:
- stage: doc
- script:
- - echo $PWD
- test_1:
- stage: test
- script:
- - echo $PWD
- test_2:
- stage: test
- script:
- - echo $PWD
- test_3:
- stage: test
- script:
- - echo $PWD
最终可以在 gitlab 中可视化的看到如下的 pipeline。可以看到当两个任务对应 stage 相同时,他们会并列。

script
在上面的例子中可以看到每个 job
中都有关键词 script
。它是当前 pipeline
节点(某个 job
)运行的 shell
脚本(以项目根目录为上下文执行)。
这个 script 是我们控制 CI 流程的核心。我们所有的工作:从安装,编译到部署都是通过script中定义的 shell 脚本来完成的。如果脚本执行成功,pipeline
就会进入下一个 Job
节点,如果执行失败那么 pipeline
就会终止。
下面是一个最简单的 script
,打印当前的路径,以及当前文件夹内的文件:
- pages:
- stage: doc
- script:
- - echo $PWD
- - echo $(ls .)
tags
tags
关键字指定了使用哪个 Runner
(哪个机器)去执行我们的任务,注意与下面 only
关键字的 tags
进行区分。这里的 tag
是 git tag
。
- image: python:3.6
- job1:
- only:
- - dev # 只有提交分支是 dev 的时候才触发
- tags:
- - machine1 # 指定哪个机器执行我们的任务
- script:
- - echo $PWD
only 和 except
only
和 except
这两个关键词是用来控制任务触发的条件。例如当提交的分支是 master
分支时才触发,则可以按下面这样写:
- job1:
- only:
- - master
- script:
- - echo $PWD
或是当提交的分支为 master
或者打了 tags 才触发(及没有 tags 是不会触发的)
- # 举这个例子是想说明only关键字之间的关系是”或“关系
- job1:
- only:
- - master
- - tags
- script:
- - echo $PWD
when
- on_success:只有前面 stages 的所有工作成功时才执行,这是默认值。
- on_failure:当前面 stages 中任意一个 jobs 失败后执行
- always:无论前面 stages 中 jobs 状态如何都执行
- manual:手动执行
- delayed:延迟执行
- # 官方示例
- stages:
- - build
- - cleanup_build
- - test
- - deploy
- - cleanup
- build_job:
- stage: build
- script:
- - make build
- # 如果build_job任务失败,则会触发该任务执行
- cleanup_build_job:
- stage: cleanup_build
- script:
- - cleanup build when failed
- when: on_failure
- test_job:
- stage: test
- script:
- - make test
- deploy_job:
- stage: deploy
- script:
- - make deploy
- when: manual
- # 总是执行
- cleanup_job:
- stage: cleanup
- script:
- - cleanup after jobs
- when: always
Gitlab Page 生成
Gitlab
会自动将 public
目录(这个目录需要自己创建)下的文件进行发布成 Gitlab Page
。下面放一个最简单的例子,整个仓库的目录结构如下所示,有一个 .gitlab-ci.yml
的配置文件,将 html
文件放在 source
文件夹里面:
- .
- ├── README.md
- ├── .gitlab-ci.yml
- └── source
- └── index.html
public
文件夹中必须有 index.html
文件。这里index.html
可以随意写一下就可以了。我们主要来看一下 .gitlab-ci.yml
的配置文件,里面有 mkdir public
来创建 public 文件夹。
- image: python3.6
- stages:
- - doc
- pages:
- stage: doc
- script:
- - mkdir public # 需要创建 public 文件夹
- - cp -r source/* public/ # 将 source 中的文件移动到 public
- artifacts:
- paths:
- - public
- only:
- - master
上面就是一个最简单的 Gitlab Page
的例子。我们也可以使用 Sphinx
来生成 html
文件,最后将生成的文件移动到 public 文件夹即可。(关于 Sphinx
的使用说明可以参考,Python 文档生成-Sphinx)
pages: deploy - No entries extracted
在使用 sphinx
自动生成 gitlab page
的时候,可能会出现以下的报错:
- Uploading artifacts...
- WARNING: public: no matching files
- ERROR: No files to upload
这是因为 public
文件夹内没有文件,所有上传失败。我们需要注意,public 文件夹是在项目的根目录下的(可以理解为一个隐藏的文件夹,他是不会被上传到仓库中去的)。所以我们将文件移动到 public 下的时候,需要返回项目的根目录下,或者移动的时候把路径写全了。
例如我们的项目路径是在 /home/wangmaonan/example/
,那么我们的 public
的路径就是 /home/wangmaonan/example/public/
,也就是说我们需要把所有的文件移动到上面的路径内。
例如下面是一个自动部署 sphinx
的脚本,可以看到我们直接将 sphinx-build
生成的文件放在 /home/wangmaonan/example/public/
这个路径下:
- image: python:3.7-alpine
- stages:
- - doc
- pages:
- stage: doc
- script:
- - pip install -U sphinx
- - pip install -U sphinx_rtd_theme
- - pip install -U recommonmark
- - cd ./doc/source
- - sphinx-build -b html . /home/wangmaonan/example/public
- artifacts:
- paths:
- - public
- only:
- - docs
- 微信公众号
- 关注微信公众号
-
- QQ群
- 我们的QQ群号
-
评论