(共556篇)
全部分类

CI/CD入门概念
[ CICD ] 

本文采用的是Gitlab-CI/CD 15.1.1 版本

runner

使用 CI/CD 必须提前注册至少一个 runner, runner 是用来具体执行任务的工具

runner 通常被安装在某个主机上, 并通过"注册"的方式, 注册到 gitlab 所在的服务器, 通常可以在gitlab设置-overview-runner中看到当前环境中所有的 runner 信息, 页面中也提供了安装/注册 runner 的教程, 根据提示注册至少一个 runner 即可

也可以指定一个 docker 容器, 让 runner 在容器中运行, (注意: 在 docker 容器中执行 runner 和把应用程序打包为一个容器是两个概念)这个稍后再说

runner 根据执行权限的不同分为共享 runner 和专属 runner, 专属 runner 只能用于指定的项目, 共享 runner 可以同时多个项目

gitlab-ci.yaml

这是 gitlab 执行 ci/cd 的配置文件, 有最重要的两个作用:

  1. runner 执行作业时的顺序
  2. runner 在执行过程中遇到指定条件的具体行为

配置文件中的参数分为两种类型:

1
2
3
4
5
6
7
8
9
# 键值对类型, 键值对之间必须使用空格隔开, 否则会报错
variables:
  VAR1: "zhangsan"
  VAR2: "lisi"

# set类型, 以"- value"的形式定义
before_scripts:
  - command1
  - command2

job

一个配置文件中通常包含多个 job(任务), 比如这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
job1: #job名称
  stage: build
  script:
    - command1
    - command2

job2: #job名称
  stage: test
  script:
    - command1
    - command2

job 的名称是完全可以自定义的, 但是 gitlab 定义的一些关键词是不能用的, 比如[‘image’,‘services’,‘stages’,’types’,‘before_script’,‘after_script’,‘variables’,‘cache’,‘include’,’true’,‘false’,’nil’]等, 如果多个 job 使用了相同的名称, 只会有一个被添加到 pipeline 中, 但是具体是哪一个,就无法预测了

script(job 参数)与 before_script,after_script

script 是 job 中的一个配置项, 用来设置当前 job 中要执行的命令, 一个 job 中的 script 可以包含多条命令

before_script 在 script 之前,artifacts 恢复之后执行

after_script 在 script 之后执行, 且不管 script 是否执行成功都会执行

before_script 与 script 中的语句会在同一个 shell 中执行,所以 before_script 中的变量等信息, script 中是可以使用的

after_script 与 script 不在同一个 shell 中执行, 所以 script 中的变量, 在 after_script 中是不能使用的

这三者的值可以使用可以执行任何的 shell 脚本, 甚至是直接执行某个.sh 文件

1
2
3
4
job1:
  scripts:
    - echo 'first line'
    - /bin/bash setup.sh

也可以使用多行 shell 语句, 多行语句要使用"|“符号表示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
job2:
  stage: build
  tags:
    - nuxt2
  script:
    - ls -alh
    - |
      if [[ -f cat.txt ]]; then 
        echo "cat.txt exists ,file content:" 
        cat cat.txt
      else 
        echo "cat.txt not found ,will create cat.txt content 'job1' " 
        echo 'job1' > cat.txt 
        cat cat.txt
      fi      

pipeline 与 stage(job 参数)

pipeline 直译为"管道”, 是 ci/cd 中的顶级组件, 默认情况下, 每产生新的 commit, 都会触发一次新的 pipeline

一个 pipeline 通常包含多个任务 stage(阶段), stage 之间会按照定义好的顺序"依次"执行, ci/cd 定义了三个默认 stage: build, test, deploy,

当某个 job 执行失败,会终止 pipeline 的继续执行

比如下面的配置, 虽然 test,build,deploy 的定义顺序不同, 但会默认按照’build, test, deploy’的顺序执行任务

1
2
3
4
5
6
7
8
job1:
  stage: test

job3:
  stage: deploy

job4:
  stage: build

一个 stage(阶段)可以包含多个 job(任务), 也就是说多个 job 的 stage 值是允许相同的, 相同 stage 中的 job 是可以"并行"执行的

比如下面的配置中, 只有 job1 与 job2 都"执行完成并执行成功"后, 才能继续执行 job3 与 job4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
job1:
  stage: build

job2:
  stage: build

job3:
  stage: test

job4:
  stage: test

stages (pipeline 参数)

stages 是个顶级的配置项, 用来添加自定义的 stage, 并且设置它们的执行顺序, 像下面这样, 各 job 会按照 job3-job2-job1 的顺序执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
stages:
  - s1
  - s2
  - s3

job1:
  stage: s3

job2:
  stage: s2

job3:
  stage: s1

allow_failure (pipeline 参数)

前面说过, 任何一个 job 执行失败都会终止 pipeline 的执行, ,但是如果给 job 设置了 allow_failure:true 会允许当前 job 执行失败,且不会终止 pipeline 的继续执行, 也就是说下一个阶段的 job 可以继续执行下去

比如下面的案例中, job2 中的 command2 如果执行失败, 不影响 job3 的继续执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
stages:
  - s1
  - s2
  - s3

job1:
  stage: s1
  script:
    - command1
job2:
  stage: s2
  script:
    - command2
  allow_failure: true

job3:
  stage: s3
  script:
    - command3

variables (pipeline/job 参数)

variables 用来定义 pipeline 中的变量, 这些变量已经配置,会贯穿于整个 pipeline, 也就是说 pipeline 中所有的 job 都可以访问到它们

1
2
3
4
5
6
7
variables:
  BUILD_MODE: "dev"
  ENCODE_KEY: "123456"

job1:
  script:
    - echo $BUILD_MODE # 输出'dev'

job 中也可以使用 variables 添加或者覆盖 pipeline 级别的变量

1
2
3
4
5
6
7
8
9
variables:
  BUILD_MODE: "dev"
  ENCODE_KEY: "123456"

job1:
  variables:
    BUILD_MODE: "dev2"
  script:
    - echo $BUILD_MODE # 输出'dev2'

job 执行时, 还可以根据不同的条件添加/设置, 后面再说

when (job 参数)

when 放在 job 的顶级配置中时, 用来设置 job 的执行时机, 通常有以下几种值:

  1. on_success: 这是每个 job 的默认值, 只有当上一个阶段执行成功或者上一个阶段设置了"allow_failure: true(允许失败)“的情况下, 才会执行当前 job
  2. manual: 设置当前 job 必须通过手动触发
  3. always: 忽略上一个阶段中的任务执行结果, 不管他们成功还是失败, 都允许执行当前 job
  4. on_failure: 当上一个阶段中至少有一个 job 执行失败, 才能执行当前 job, 需要注意的是, 这的执行失败, 前提是执行失败的 job 没有设置 allow_failure: true, 设置了 allow_failure: true 的 job 执行失败后, 会走向 on_success
  5. delayed: 将作业的执行延迟指定的持续时间, 通常与 start_in 参数配合使用
  6. never: 永远不执行当前 job(这个值在下面会用到)

start_in

start_in 用来设置 job 的延迟时间, 比如:

1
2
3
4
5
6
7
job1:
  when: delayed
  start_in: 1 week # 1周后再执行
  start_in: 1 day # 1天后再执行
  start_in: 5 hours # 5小时后再执行
  start_in: 5 minutes # 1分钟后再执行
  start_in: 5 seconds # 1秒后再执行

rules (job 参数)

当一个 pipeline 启动时, gitlab 会检查配置文件, 来确定哪些 job 可以运行,并且确定他们的执行顺序

rules 是 job 里面的配置项, 可以用来确定各 job 会是否在当前的 pipeline 中执行, 还可以设置指定条件下的其他参数

rules 中可以使用[“if”,“changes”,“exists”,“allow_failure”,“variables”,“when”]等关键字来配置

rules 与 only 不能同时出现在一个 job 中

判断条件 if

rules 中的 if 关键字可以创建条件语句, 条件语句中可以使用 gitlab 提供的变量或者自定义的变量,

当条件语句为 true 的时候, job 会被添加到 pipeline 中, 否则不会添加, 比如下面的案例, 就表示 job1 只有在发起合并请求时才会被添加到 pipeline 中:

1
2
3
job1:
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

if 语句可以使用[’==’,’!=’,’=~’,’!~’]作为判断运算符, 前两个是字符串判断, 后两个允许使用正则判断(只有 15.x 版本之后才能使用正则表达式)

变量的类型、获取、判断可以参考CI 变量表达式

判断条件 changes

changes 关键字可以执行"当某些文件发生变化时, 才会把所在 job 添加到 pipeline”, 比如下面的案例:就表示 job1 只有在 readme.md 文件"或者"package.json 文件或者 dist 目录下的任何文件发生改变时才会被添加到 pipeline 中

1
2
3
4
5
6
job1:
  rules:
    - changes:
        - readme.md
        - package.json
        - dist/*

changes 的值可以使用 glob 匹配模式

判断条件 exists

exists 关键字可以执行"当存在某些文件时, 才会把所在 job 添加到 pipeline", 比如下面的案例:就表示 job1 只有在 readme.md 文件存在时才会被添加到 pipeline 中

1
2
3
4
job1:
  rules:
    - exists:
        - readme.md

复合判断条件

if,changes,exists 是可以混合使用的, 比如下面的例子:

1
2
3
4
5
6
7
job1:
  rules:
    - if: $CI_COMMIT_BRANCH == 'master'
      changes:
        - packages.json
      exists:
        - DockerFile

条件满足时设置/覆盖参数 allow_failure

前面说了一个 pipeline 级别与 job 级别的 allow_failure, 在 rules 里面, 也可以根据条件设置任务是否允许失败, 能够更精细的控制 job 的 allow_failure 属性

比如下面的案例中, 如果触发 pipeline 的是 master 分支, 就允许当前 job 执行失败, 如果是 dev 分支, 就不允许当前 job 执行失败

1
2
3
4
5
6
job1:
  rules:
    - if: $CI_COMMIT_BRANCH == 'master'
      allow_failure: true
    - if: $CI_COMMIT_BRANCH == 'dev'
      allow_failure: false

条件满足时设置/覆盖参数 variables

在 rules 里面, 也可以根据条件新增变量或者覆盖已有变量, 在 rules 中设置变量,能够更精细的控制 job 的变量

,比如下面的案例: 当触发 pipeline 的分支是 master 时, 添加变量 VAR_ENV 的值为’prod’, 如果是 dev 分支, 添加变量 VAR_ENV 的值为’dev’

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
variables:
  VAR_ENV: 'default'
job1:
  script:
    - echo $VAR_ENV  # master分支触发pipeline时,输出prod, dev分支触发pipeline时, 输出dev, 其他分支
  rules:
    - $CI_COMMIT_BRANCH == 'master'
      variables:
        - VAR_ENV: 'prod'
    - $CI_COMMIT_BRANCH == 'dev'
      variables:
        - VAR_ENV: 'dev'

条件满足时设置/覆盖参数 when

rules 中的 when 是用来根据条件动态决定是否加入到 pipeline 中, 它的用法与 job 级别的 when 参数是相同的, 目的与 allow_failure/variables 一样都是为了让控制粒度更精细

比如下面的例子: 当 master 分支触发 pipeline 时, job1 只能通过手动执行, 当 dev 分支触发 pipeline 时, 禁止执行 job1

1
2
3
4
5
6
7
job1:
  rules:
    - if: $CI_COMMIT_BRANCH == 'master'
      when: manual

    - if: $CI_COMMIT_BRANCH == 'dev'
      when: never

needs(job 参数)

needs 用来定义 job 之间的依赖关系, 它的值是一个 list 类型

假设我们有一份这样的文件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
build1:
  stage: build
  script:
    - command1

build2:
  stage: build
  script:
    - command1

test1:
  stage: test
  script:
    - command1

test2:
  stage: test
  script:
    - command1

在 runner 有多个的情况下, pipeline 会并行执行 build1,build2, 等待它们都执行成功, 再并行执行 test1,test2 任务, needs 关键字可以让 test1,test2 提前执行, 比如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
build1:
  stage: build
  script:
    - command1

build2:
  stage: build
  script:
    - command1

test1:
  stage: test
  needs: [build1]
  script:
    - command1

test2:
  stage: test
  needs: [build2]
  script:
    - command1

现在, 如果 build1 执行完成, pipeline 不用等待 build2 任务结束, 就可以让 test1 任务提前执行

合并请求管道

任何分支上的任何更改, 都会触发管道的执行, 管道内会按照 stages 指定的顺序按阶段执行

但是管理员可以设置管道内的任务在发生合并请求时执行, 比如下面的案例:

1
2
3
4
5
job1:
  script:
    - command1
  only:
    - merge_requests

假设创建一个 a 分支合并到 b 分支的请求, merge requests 请求被创建时, 就会触发任务 job1, 且 job1 执行时使用的是 a 分支的代码

处理合并请求的人, 会在页面中看到类似于"Detached merge request pipeline #169 pending for 7f7b05b7"的提示, 就说明当前的合并请求已经触发了一个 pipeline

打开合并请求页面时, 如果对应的 pipeline 已经完成, 页面上只显示一个"Merge"按钮, 如果 pipeline 未完成, 页面上会有"Merge when pipeline success(等待 pipeline 成功后合并)“和"Merge Immediately(强制合并)“按钮

这个顺序就好比实际开发中"开发分支的功能发布并验证没有问题后, 再合并到 master 分支”

merge request 类型的 pipeline 还可以使用下面方式实现:

1
2
3
4
5
job1:
  script:
    - command1
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'

如果想让当前任务流中所有任务都在 merge request 事件时执行, 可以使用workflow字段:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
workflow:
  rules: -if $CI_PIPELINE_SOURCE == 'merge_request_event'

job1:
  script:
    - command1

job2:
  script:
    - command1