Skip to content

使用 gitlab-ci.yaml文件进行CI 持续集成

概念

Pipeline

一次 Pipeline 其实相当于一次构建任务,里面可以包含多个流程,如安装依赖、运行测试、编译、部署测试服务器、部署生产服务器等流程。 任何提交或者 Merge Request 的合并都可以触发 Pipeline,如下图所示:

bash
+------------------+           +----------------+
|                  |  trigger  |                |
|   Commit / MR    +---------->+    Pipeline    |
|                  |           |                |
+------------------+           +----------------+

Stages

Stages 表示构建阶段,说白了就是上面提到的流程。 我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:

所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败 因此,Stages 和 Pipeline 的关系就是:

bash
+--------------------------------------------------------+
|                                                        |
|  Pipeline                                              |
|                                                        |
|  +-----------+     +------------+      +------------+  |
|  |  Stage 1  |---->|   Stage 2  |----->|   Stage 3  |  |
|  +-----------+     +------------+      +------------+  |
|                                                        |
+--------------------------------------------------------+

Jobs

Jobs 表示构建工作,表示某个 Stage 里面执行的工作。 我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:

相同 Stage 中的 Jobs 会并行执行 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功 如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败, 但可以通过参数设置 allow_failure: true 进行跳过 所以,Jobs 和 Stage 的关系图就是:

bash
+------------------------------------------+
|                                          |
|  Stage 1                                 |
|                                          |
|  +---------+  +---------+  +---------+   |
|  |  Job 1  |  |  Job 2  |  |  Job 3  |   |
|  +---------+  +---------+  +---------+   |
|                                          |
+------------------------------------------+

构建执行器 GitLab Runner

可以使用GitLab Runner执行这些构建任务,因为 GitLab Runner 可以安装到不同的机器上,所以在构建任务运行期间并不会影响到 GitLab 的性能。 一般来说,构建任务都会占用很多的系统资源 (譬如编译代码),GitLab CI 又是 GitLab 的一部分,GitLab CI 最大的作用是管理各个项目的构建状态,如果由 GitLab CI 来运行构建任务的话,在执行构建任务的时候,GitLab 的性能会大幅下降。

安装

可参考gitlab-runner官方文档

下面是 Debian/Ubuntu/CentOS 的安装方法,其他系统去参考官方文档:

bash
# For Debian/Ubuntu
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash
$ sudo apt-get install gitlab-ci-multi-runner

# For CentOS
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash
$ sudo yum install gitlab-ci-multi-runner

注册 Runner

安装好 GitLab Runner 之后,我们只要启动 Runner 然后和 CI 绑定就可以了:

  • 打开你 GitLab 中的项目页面,在项目设置中找到 runners
  • 运行 sudo gitlab-ci-multi-runner register
  • 输入 CI URL
  • 输入 Token
  • 输入 Runner 的名字
  • 选择 Runner 的类型,executor可以是多种类型,简单的话可以选shell。有熟悉docker的可以使用docker。
  • 完成
bash
gitlab-runner register --name="XX"  --url="https://git.xx.com/" --token="XXX" --executor="shell"

当注册好 Runner 之后,可以用 sudo gitlab-ci-multi-runner list 命令来查看各个 Runner 的状态:

bash
sudo gitlab-runner list
bash
Listing configured runners  ConfigFile=/etc/gitlab-runner/config.toml
my-runner  Executor=shell Token=cd1cd7cf243afb47094677855aacd3 URL=http://mygitlab.com/ci

配置文件在/etc/gitlab-runner/config.toml 配置项类似下面,可能需要手动添加builds_dir和cache_dir这两个变量,再重启服务

bash
[[runners]]
name = "216XX"
url = "https://git.XX.com/"
token = "XX"
executor = "shell"
builds_dir = "/home/gitlab-runner/builds"
cache_dir = "/home/gitlab-runner/cache"
[runners.cache]

常见命令

bash
sudo gitlab-runner list # 查看各个 Runner 的状态
sudo gitlab-runner stop # 停止服务
sudo gitlab-runner start # 启动服务
sudo gitlab-runner restart # 重启服务

.gitlab-ci.yaml

.gitlab-ci.yml 在定义 Pipeline,当我们在项目根目录中添加了 .gitlab-ci.yml 文件后,每次提交代码或者合并 MR 都会自动运行构建任务了。

  1. 用 stages 关键字来定义 Pipeline 中的各个构建阶段,然后用一些非关键字来定义 jobs。
  2. 每个 job 中可以可以再用 stage 关键字来指定该 job 对应哪个 stage。
  3. job 里面的 script 关键字是最关键的地方了,也是每个 job 中必须要包含的,它表示每个 job 要执行的命令。

基本示例

bash
# 定义 stages
stages:
  - build
  - test

# 定义 job
job1:
  stage: test
  script:
    - echo "I am job1"
    - echo "I am in test stage"

# 定义 job
job2:
  stage: build
  script:
    - echo "I am job2"
    - echo "I am in build stage"

根据我们在 stages 中的定义,build 阶段要在 test 阶段之前运行,所以 stage:build 的 jobs 会先运行,之后才会运行 stage:test 的 jobs。

bash
I am job2
I am in build stage
I am job1
I am in test stage

常用关键字

更多语法官方文档

stages

定义 Stages,默认有三个 Stages,分别是 build, test, deploy

types(stages 的别名)

  • before_script:定义任何 Jobs 运行前都会执行的命令。
  • after_script:定义任何 Jobs 运行完后都会执行的命令。

variables

variables && Job.variables 定义了环境变量。 如果定义了 Job 级别的环境变量的话,该 Job 会优先使用 Job 级别的环境变量。

cache

cache && Job.cache 定义需要缓存的文件。

每个 Job 开始的时候,Runner 都会删掉 .gitignore 里面的文件。 如果有些文件 (如 node_modules/) 需要多个 Jobs 共用的话,我们只能让每个 Job 都先执行一遍 npm install。 这样很不方便,因此我们需要对这些文件进行缓存。缓存了的文件除了可以跨 Jobs 使用外,还可以跨 Pipeline 使用。

Job.script

定义 Job 要运行的命令,必填项。

Job.stage

定义 Job 的 stage,默认为 test。

Job.artifacts

定义 Job 中生成的附件。 当该 Job 运行成功后,生成的文件可以作为附件 (如生成的二进制文件) 保留下来,打包发送到 GitLab,之后我们可以在 GitLab 的项目页面下下载该附件。

Job.when

when 用于配置作业运行时间的条件。如果未在作业中定义,则默认值为 when: on_success 。

  • on_success (默认):仅当早期阶段没有作业失败或出现 allow_failure: true
  • on_failure :仅当早期阶段中至少有一个作业失败时才运行作业。处于早期阶段 allow_failure: true 的工作总是被认为是成功的.
  • never :无论作业在早期阶段的状态如何,都不要运行作业。只能在 rules 节或 workflow: rules
  • always :无论作业在早期阶段的状态如何,都运行作业。也可用于 workflow:rules
  • manual :仅在手动触发时运行作业。
  • delayed :将作业的执行延迟到指定的持续时间。
bash
stages:
  - build
  - cleanup_build
  - test
  - deploy
  - cleanup

build_job:
  stage: build
  script:
    - make build

cleanup_build_job:
  stage: cleanup_build
  script:
    - cleanup build when failed
  # cleanup_build_job 仅在失败时 build_job 执行。
  when: on_failure

test_job:
  stage: test
  script:
    - make test

deploy_job:
  stage: deploy
  script:
    - make deploy
  # 在 GitLab UI 中手动运行时执行 deploy_job 。
  when: manual
  environment: production

cleanup_job:
  stage: cleanup
  script:
    - cleanup after jobs
  # 无论成功或失败,始终 cleanup_job 作为管道中的最后一步执行。
  when: always

具体示例1

bash
# Pipeline 分成五个阶段:

# 安装依赖(install_deps)
# 运行测试(test)
# 编译(build)
# 部署测试服务器(deploy_test)
# 部署生产服务器(deploy_production)

stages:
  - install_deps
  - test
  - build
  - deploy_test
  - deploy_production

cache:
  key: ${CI_BUILD_REF_NAME}
  paths:
    - node_modules/
    - dist/


# 安装依赖
install_deps:
  stage: install_deps
  only:
    - develop
    - master
  script:
    - npm install


# 运行测试用例
test:
  stage: test
  only:
    - develop
    - master
  script:
    - npm run test


# 编译
build:
  stage: build
  only:
    - develop
    - master
  script:
    - npm run clean
    - npm run build:client
    - npm run build:server


# 部署测试服务器
deploy_test:
  stage: deploy_test
  # 只有当 develop 分支有提交的时候才会触发相关的 Jobs。 
  only:
    - develop
  script:
    - pm2 delete app || true
    - pm2 start app.js --name app


# 部署生产服务器
deploy_production:
  stage: deploy_production
  # 只有当 master 分支有提交的时候才会触发相关的 Jobs。 
  only:
    - master
  script:
    - bash scripts/deploy/deploy.sh

具体示例2

bash
#构建阶段-任务
stages:
  - analytics
  - test
  - build
  - package
  - deploy

#构建工作job名称
build_analytics:
  #该工作执行阶段
  stage: analytics
  #设置只对master分支有效
  only:
    - master
    - tags
  tags:
    - runner-tag-snoreqube
  script:
    - echo "=============== 开始代码质量检测 ==============="
    - echo "=============== 结束代码质量检测 ==============="

build_test:
  stage: test
  only:
    - master
    - tags
  tags:
    - runner-tag
  script:
    - echo "=============== 开始测试任务 ==============="
    - echo "=============== 结束测试任务 ==============="


build:
  stage: build
  only:
    - master
    - tags
  tags:
    - runner-tag
  script:
    - echo "=============== 开始编译任务 ==============="
    - echo "=============== 结束编译任务 ==============="

package:
  stage: package
  tags:
    - runner-tag
  script:
    - echo "=============== 开始打包任务 ==============="
    - echo "=============== 结束打包任务 ==============="

deploy_test:
  stage: deploy
  tags:
    - runner-tag
  #输出在gitlab-ci中设置的变量
  script:
    - echo "=============== 自动部署到测试服务器 ==============="
    - echo "测试服务器:" ${SERVER_TEST}
  #环境变量
  environment:
    name: test
    url: https://staging.example.com

deploy_test_manual:
  stage: deploy
  tags:
    - runner-tag
  script:
    - echo "=============== 手动部署到测试服务器 ==============="
  environment:
    name: test
    url: https://staging.example.com
  #设置条件 manual 允许失败  
  when: manual

deploy_production_manual:
  stage: deploy
  tags:
    - runner-tag
  script:
    - echo "=============== 手动部署到生产服务器 ==============="
    - echo "测试服务器:" ${SERVER_TEST}
  environment:
    name: production
    url: https://staging.example.com
  when: manual

参考资料

scarletsky.github.io持续集成gitlab-ci.yml配置文档基础