- 专栏地址:CI/CD 流水线
- 系列文章:CI/CD 半桶水(一)、CI/CD 半桶水(二)
- 本文作者:Clfeng
导学
通过前两章的内容,我们有了自己的 CI/CD 环境也掌握了 CI/CD 最核心的相关概念。这一章我们将进一步了解 CI/CD 的各种关键字及其作用。
注:这一章节看起来更像是一个查配置的章节,内容长且枯燥。笔者写这章的目的关键也还是为了整体知识的完整性。同时笔者也认为虽然对于一块知识点的学习应该是越完整越好,尽可能知道其所有的内容,即使看完之后细节都不记得了。但是知道有那么一个东西存在,那么当问题出现时我们更有可能分析出问题出现的原因以及得到更合理的解决方案
.gitlab-ci.yml reference
默认配置
default
定义 pipeline 中所有 job 的默人配置,可定义的相关配置项:
- after_script
- artifacts
- before_script
- cache
- image
- interruptible
- retry
- services
- tags
- timeout
全局配置
stages
定义 pipeline 各个 stage 的名称以及执行顺序
workflow
控制整个 pipeline 的运行
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
when: never
- if: '$CI_PIPELINE_SOURCE == "push"'
when: never
- when: always
variables:
DEPLOY_VARIABLE: "default-deploy"
workflow:
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
variables:
DEPLOY_VARIABLE: "deploy-production" # Override globally-defined DEPLOY_VARIABLE
- if: $CI_COMMIT_REF_NAME =~ /feature/
variables:
IS_A_FEATURE: "true" # Define a new variable.
- when: always # Run the pipeline in other cases
job1:
variables:
DEPLOY_VARIABLE: "job1-default-deploy"
rules:
- if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
variables: # Override DEPLOY_VARIABLE defined
DEPLOY_VARIABLE: "job1-deploy-production" # at the job level.
- when: on_success # Run the job in other cases
script:
- echo "Run script with $DEPLOY_VARIABLE as an argument"
- echo "Run another script if $IS_A_FEATURE exists"
job2:
script:
- echo "Run script with $DEPLOY_VARIABLE as an argument"
- echo "Run another script if $IS_A_FEATURE exists"
include
可以通过 include 关键字来对 yml 中的内容进行拆分,增强配置文件的可读性
Keyword | Method |
---|---|
local | Include a file from the local project repository. |
file | Include a file from a different project repository. |
remote | Include a file from a remote URL. Must be publicly accessible. |
template | Include templates that are provided by GitLab. |
include:local
include:
- local: '/templates/.gitlab-ci-template.yml'
# 简写
include: '.gitlab-ci-production.yml'
# 使用通配符
include: 'configs/*.yml'
include:file
include:
- project: "my-group/my-project"
ref: main
file: "/templates/.gitlab-ci-template.yml"
- project: "my-group/my-project"
ref: v1.0.0
file: "/templates/.gitlab-ci-template.yml"
- project: "my-group/my-project"
ref: 787123b47f14b552955ca2786bc9542ae66fee5b # Git SHA
file:
- "/templates/.builds.yml"
- "/templates/.tests.yml"
include:remote
include:
- remote: "https://gitlab.com/example-project/-/raw/main/.gitlab-ci.yml"
include:template
include:
- template: Android-Fastlane.gitlab-ci.yml
- template: Auto-DevOps.gitlab-ci.yml
普通配置
image
指定运行 job 的 docker 镜像
image
- name # 镜像的名称
- entrypoint # docker 镜像的 ENTRYPOINT
services
指定 docker service 镜像
services - name - alias - entrypoint - comand
before_script
在 job 的 script 相关命令执行前执行的命令,一般用于安装依赖预设环境变量的;其和 script 共用一个 shell
script
定义 job 被 runner 执行时所需要执行的命令
after_script
在 job 执行完之后执行的命令,其和 script 使用的不是一个 shell
stage
指定 job 所属阶段
extends
用于复用配置片段
.only-important:
variables:
URL: "http://my-url.internal"
IMPORTANT_VAR: "the details"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == "stable"
tags:
- production
script:
- echo "Hello world!"
.in-docker:
variables:
URL: "http://docker-url.internal"
tags:
- docker
image: alpine
rspec:
variables:
GITLAB: "is-awesome"
extends:
- .only-important
- .in-docker
script:
- rake rspec
以上配置 rspec
job 的求值结果为:
rspec:
variables:
URL: "http://docker-url.internal"
IMPORTANT_VAR: "the details"
GITLAB: "is-awesome"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_BRANCH == "stable"
tags:
- docker
image: alpine
script:
- rake rspec
incluce
使用 include 在 CI/CD 配置中包含外部 YAML 文件。 您可以将一个很长的 gitlab-ci.yml 文件分解为多个文件以提高可读性,或减少同一配置在多个地方的重复。
# included.yml
.template:
script:
- echo Hello!
# .gitlab-ci.yml
include: included.yml
useTemplate:
image: alpine
extends: .template
rules
使用 rules 在 pipelines 中包含或排除 job。
注:不可和 only/except 一起使用
rules - if - exists - allow_failure - variables - when
相关的内容参见 CI/CD 半桶水(二) jobs 章节
only/except
您可以使用 only 和 except 来控制何时向 pipelines 添加 job。
注:only/except 已经不在重点进行迭代开发了,推荐使用 rules
相关的内容参见 CI/CD 半桶水(二) jobs 章节
tags
使用 tags 从项目中所有可用的 runner 中选择特定的 runner
variables:
KUBERNETES_RUNNER: kubernetes
job:
tags:
- docker
# 这里比较有意思,我们可以通过设定变量来动态选用runner
- $KUBERNETES_RUNNER
script:
- echo "Hello runner selector feature"
allow_failure
可以通过 allow_failure 想让 job 失败不会影响后续 ci 的
allow_failure:exit_codes
通过 allow_failure:exit_codes 可以配置哪些退出码不被视为失败
test_job_1:
script:
- echo "Run a script that results in exit code 1. This job fails."
- exit 1
allow_failure:
exit_codes: 137
test_job_2:
script:
- echo "Run a script that results in exit code 137. This job is allowed to fail."
- exit 137
allow_failure:
exit_codes:
- 137
- 255
when
- on_success: 当前面各个 stages 都成功之后,执行当前 job
- on_failure: 当前面的 stage 中至少有一个 job 失败之后,执行当前 job
- always: 无论前面 stages 的状态如何,都执行 job
- manual: 手动直接 job
- delayed: 在指定时间后延迟执行 job
- never:
- 配合 rules 关键字,不执行 job
- 配合 workflow:rules 关键字,不执行 pipeline
# when: delayed 示例
timed rollout 10%:
stage: deploy
script: echo 'Rolling out 10% ...'
when: delayed
start_in: 30 minutes
# start_in 合法值
# '5'
# 5 seconds
# 30 minutes
# 1 day
# 1 week
environment
environment 相关属性
-
name: 设置一个环境的名称
-
url: 部署环境的 url
-
on_stop: 执行完部署环境的 job 之后可单独设置清理环境的 job
-
auto_stop_in: 指定环境多久过期
-
action
- start
- prepare
- stop
-
kubernetes: 配置将项目部署到 kubernetes 集群
default:
image: centos:7
tags:
- clf-cicd-runner
stages:
- deploy
deploy_prod:
stage: deploy
script:
- echo "Deploy to production server"
environment:
name: develop
url: https://dev.com
cache
已经学习了 《CI/CD 半桶水(二)》 可跳过
相关关键字
- paths: 指定缓存的文件或者目录
- key: 缓存的唯一标识
- files: 当指定的文件中,某个文件改变了,会生成一个新的 key
- prefix: 添加前缀到到
cache:key:files
计算的 hash 前
- untracked: 使用 untracked: true 缓存 Git 存储库中所有未跟踪的文件
- when: 定义什么条件下缓存 cache,可选值:on_success、on_failure、always
- policy: 定义缓存上传和下载的策略,可选值:pull、push、pull-push
prepare-dependencies-job:
stage: build
cache:
key: gems
paths:
- vendor/bundle
policy: push
script:
- echo "This job only downloads dependencies and builds the cache."
- echo "Downloading dependencies..."
faster-test-job:
stage: test
cache:
key: gems
paths:
- vendor/bundle
policy: pull
script:
- echo "This job script uses the cache, but does not update it."
- echo "Running tests..."
cache:key
使用 cache:key 关键字为每个缓存提供唯一的标识键。 使用相同缓存键的所有 job 都使用相同的缓存,包括在不同的 pipelines 中。
注:根据以上的释义,一个 key 对应这一份缓存文件,这份缓存文件可以在在同一 pipeline 不同的 job 进行复用,也可以在不同的 pipelines 中进行复用
artifacts
已经学习了 《CI/CD 半桶水(二)》 可跳过
artifacts 相关关键字
- name: 定义 artifacts 的名称
- paths: artifacts 缓存文件的路径
- dependencies: 定义当前 job 下载前面 stages 的那些 job 的 artifacts
- exclude: 排除缓存的文件
- expire_in: 使用 expire_in 指定 job artifacts 在到期和删除之前存储多长时间
- expose_as: 使用 expose_as 关键字在合并请求 UI 中公开 job artifacts
- public: 设定 artifacts 是否公开可用,如果是公开可用意味着在 public pipeline 中匿名用户和访客都可以下载
- untracked: 将所有 Git 未跟踪文件添加为 artifacts(以及 artifacts:paths 中定义的路径)
- when: 定义上传 artifacts 的条件
- reports
- api_fuzzing
- cobertura
- ...[其他的查看官网吧]
Use artifacts
to specify a list of files and directories that are attached to the job when it succeeds, fails, or always.
使用 artifacts 指定在作业成功、失败或始终时附加到作业的文件和目录列表。
The artifacts are sent to GitLab after the job finishes. They are available for download in the GitLab UI if the size is not larger than the maximum artifact size.
job 完成后,artifacts 将发送到 GitLab。 如果大小不大于最大 artifacts 大小,它们可以在 GitLab UI 中下载。
By default, jobs in later stages automatically download all the artifacts created by jobs in earlier stages. You can control artifact download behavior in jobs with dependencies.
默认情况下,后期的 jobs 会自动下载早期 job 创建的所有 artifacts。 您可以通过 dependencies 关键字控制 jobs 中 artifact 的下载行为。
When using the needs keyword, jobs can only download artifacts from the jobs defined in the needs configuration.
使用 needs 关键字时,jobs 只能从需求配置中定义的 jobs 下载 artifacts。
Job artifacts are only collected for successful jobs by default, and artifacts are restored after caches.
默认情况下,仅为成功的 job 收集 job artifacts,并在 caches 后恢复 artifacts。
重点小结:
- 储存位置在 GitLab【cache 存储在 runner】
- 前期 job 创建的 artifacts 在后期 job 中是自动下载的,可以直接用
- 可以通过 dependencies 关键字进行控制 artifacts 的下载行为
- 如果 job 中有 needs 关键字,那么只会下载 needs 关键字指定的 job 的 artifacts
artifacts:dependencies
默认情况下,job 会下载前面 stage 中所有 job 的 artifacts;我们可以通过 dependencies 去指定要下载哪些 job 的 artifacts(指定的 job 只能是当前 job 的前面的 stage 的 job)
build:osx:
stage: build
script: make build:osx
artifacts:
paths:
- binaries/
build:linux:
stage: build
script: make build:linux
artifacts:
paths:
- binaries/
test:osx:
stage: test
script: make test:osx
dependencies: # 指定只下载 build:osx 生成的 artifacts
- build:osx
test:linux:
stage: test
script: make test:linux
dependencies: # 指定只下载 build:linux 生成的 artifacts
- build:linux
# deploy job没有制定具体的,因此按照默认的,回去下载前面所有的 job 生成的 artifacts
deploy:
stage: deploy
script: make deploy
artifacts:exclude
exclude 可以防止将文件添加到 artifacts
artifacts:
paths:
- binaries/
exclude:
- binaries/**/*.o
artifacts:expire_in
使用 expire_in 指定作业 artifacts 在到期和删除之前存储多长时间
job:
artifacts:
expire_in: 1 week
# 其他可以指定的值的类型
# expire_in: '42'
# expire_in: 42 seconds
# expire_in: 3 mins 4 sec
# expire_in: 2 hrs 20 min
# expire_in: 2h20min
# expire_in: 6 mos 1 day
# expire_in: 47 yrs 6 mos and 4d
# expire_in: 3 weeks and 2 days
# expire_in: never
artifacts:expose_as
test:
script: ["echo 'test' > file.txt"]
artifacts:
expose_as: "artifact 2"
paths: ["file.txt"]
效果如下图:
artifacts:paths
定义缓存文件或目录的的路径。路径相对于项目目录,不能直接链接到项目目录之外。
artifacts:untracked
使用 artifacts:untracked 将所有 Git 未跟踪文件添加为 artifacts(以及 artifacts:paths 中定义的路径)。 artifacts:untracked 忽略存储库的 .gitignore 文件中的配置。
artifacts:
untracked: true
paths:
- binaries/
artifacts:when
定义上传 artifacts 的条件
可选值:
- on_success (default): 当 job 执行成功时上传 artifacts
- on_failure: 当 job 执行失败时上传 artifacts
- always: 总是上传 artifacts
retry
使用 retry 配置在失败的情况下重试 job 的次数
相关属性
- max: 最大重试次数
- when: 要重试的失败情况
test:
script: rspec
retry: 2
test:
script: rspec
retry:
max: 2
when: runner_system_failure
timeout
使用 timeout 为特定作业配置超时
build:
script: build.sh
timeout: 3 hours 30 minutes
test:
script: rspec
timeout: 3h 30m
parallel
使用 parallel 配置要并行运行的 job 实例数
dast_configuration
使用 dast_configuration 关键字指定要在 CI/CD 配置中使用的站点配置文件和扫描程序配置文件。
coverage
配置如何从 job 的输出日志中提取覆盖率
job1:
script: rspec
coverage: '/Code coverage: \d+\.\d+/'
trigger
Use trigger to define a downstream pipeline trigger. When GitLab starts a trigger job, a downstream pipeline is created. 使用 trigger 定义下游 pipeline 触发器。 当 GitLab 启动触发器 job 时,会创建一个下游管道。
参见 pipeline 的 Child/Parent 架构
# Basic trigger syntax for multi-project pipeline
rspec:
stage: test
script: bundle exec rspec
staging:
stage: deploy
trigger: my/deployment # 指向其他项目完整路径
# trigger:
# project: my/deployment
# branch: stable # 可以指向具体的分支
# trigger syntax for child pipeline
trigger_job:
trigger:
include: path/to/child-pipeline.yml
trigger_job:
trigger:
include:
- local: path/to/child-pipeline.yml
strategy: depend # 通过strategy: depend将子pipeline的状态映射到上游pipeline
# dynamically generated configuration file:
generate-config:
stage: build
script: generate-ci-config > generated-config.yml
artifacts:
paths:
- generated-config.yml
child-pipeline:
stage: test
trigger:
include:
- artifact: generated-config.yml
job: generate-config
interruptible
使用 interruptible 来指示如果运行的 job 因较新的 pipelines 运行而变得多余,则应取消该 job。
注:默认情况下如果同一分支,有新的 pipeline 运行,那么原先老的 pipeline 中的未运行的 job 会被取消,而正在运行的 job 则不会取消,通过 interruptible 可以让正在运行的 job 取消
resource_group
有时,在一个环境中同时运行多个 job 或 pipeline 可能会导致部署过程中出现错误。为避免这些错误,请使用 resource_group 属性确保运行程序不会同时运行某些 job。
当在 .gitlab-ci.yml 文件中为 job 定义了 resource_group 关键字时,job 执行在同一项目的不同 pipeline 中是互斥的。 如果属于同一资源组的多个 job 同时入队,则运行程序只会选择其中一个 job。 其他 job 一直等到 resource_group 空闲。
deploy-to-production:
script: deploy
resource_group: production
注:resource_group 和 trigger 一起使用的时候,需要配置 trigger:strategy:depend 以确保在 child pipeline 在执行完之前不会释放锁
inherit
使用 inherit: 控制全局定义的默认值和变量的继承。
default: # 定义的全局默认配置
image: "ruby:2.4"
before_script:
- echo Hello World
variables: # 定义的全局变量
DOMAIN: example.com
WEBHOOK_URL: https://my-webhook.example.com
rubocop:
inherit:
default: false # 不继承默认配置
variables: false # 不继承全局的变量
script: bundle exec rubocop
rspec:
inherit:
default: [image] # 继承全局默认配置的image字段
variables: [WEBHOOK_URL] # 继承全局变量的WEBHOOK_URL变量
script: bundle exec rspec
capybara:
inherit: # 继承默认配置,但是不继承全局的变量
variables: false
script: bundle exec capybara
karma:
inherit:
default: true
variables: [DOMAIN]
script: karma
YAML-specific features
可使用&
、*
、<<
等 yaml 特性来简化 .gitlab-ci.yml 的代码
# Hidden yaml configuration that defines an anchor named 'job_configuration'
# 如何理解上面的注释?
# 如果我们要隐藏一个job,除了将job相关的配置注释掉这种方式外还有一种方式,就是在job名前加 . ;这样job就不会执行
# 这样是否可以理解为什么上面的注释说的Hidden yaml configuration了吗?更近一步,可以配合下一个实例去理解
.job_template: &job_configuration
image: ruby:2.6
services:
- postgres
- redis
test1:
<<: *job_configuration # Merge the contents of the 'job_configuration' alias
script:
- test1 project
test2:
<<: *job_configuration # Merge the contents of the 'job_configuration' alias
script:
- test2 project
default:
image: centos:7
tags:
- clf-cicd-runner
stages:
- test
test_job1: &job_configuration
stage: test
before_script:
- echo "run test job 1 before script"
script:
- echo "run test job 1"
test_job2:
<<: *job_configuration
stage: test
script:
- echo "run test job 2"
# test_job2会有两句话输出:
# run test job 1 before script
# run test job 2
.job_template: &job_configuration
script:
- test project
tags:
- dev
.postgres_services:
services: &postgres_configuration
- postgres
- ruby
.mysql_services:
services: &mysql_configuration
- mysql
- ruby
test:postgres:
<<: *job_configuration
services: *postgres_configuration
tags:
- postgres
test:mysql:
<<: *job_configuration
services: *mysql_configuration
# -----------------------------------------------------------------------------
# The expanded version is:
.job_template:
script:
- test project
tags:
- dev
.postgres_services:
services:
- postgres
- ruby
.mysql_services:
services:
- mysql
- ruby
test:postgres:
script:
- test project
services:
- postgres
- ruby
tags:
- postgres
test:mysql:
script:
- test project
services:
- mysql
- ruby
tags:
- dev
脚本的 YAML 锚点
.some-script-before: &some-script-before
- echo "Execute this script first"
.some-script: &some-script
- echo "Execute this script second"
- echo "Execute this script too"
.some-script-after: &some-script-after
- echo "Execute this script last"
job1:
before_script:
- *some-script-before
script:
- *some-script
- echo "Execute something, for this job only"
after_script:
- *some-script-after
job2:
script:
- *some-script-before
- *some-script
- echo "Execute something else, for this job only"
- *some-script-after
变量的 YAML 锚点
# global variables
variables: &global-variables
SAMPLE_VARIABLE: sample_variable_value
ANOTHER_SAMPLE_VARIABLE: another_sample_variable_value
# a job that must set the GIT_STRATEGY variable, yet depend on global variables
job_no_git_strategy:
stage: cleanup
variables:
<<: *global-variables
GIT_STRATEGY: none
script: echo $SAMPLE_VARIABLE
隐藏 jobs
当 job 的名称以 . 开头的时,job 不会被 cicd 所处理,其效果和注释掉代码类似
.hidden_job:
script:
- run test
!reference tags
使用 !reference 自定义 YAML 标记从其他 job 部分选择关键字配置,并在当前部分中重用它。 与 YAML 锚点不同,您也可以使用 !reference 标签来重用包含的配置文件中的配置。
# setup.yml
.setup:
script:
- echo creating environment
# .gitlab-ci.yml
include:
- local: setup.yml
.teardown:
after_script:
- echo deleting environment
test:
script:
- !reference [.setup, script]
- echo running my own command
after_script:
- !reference [.teardown, after_script]
**小结:**通过这一章节的学习,我们了解了很多 YAML 特有的功能,通过这些功能特性,我们可以很好的维护我们的配置文件。
结语
看完下来是不是觉得这内容实在太多了,也可能不记得多少东西。其实没关系的,知道有这那么个东西存在就好,但问题出现的时候,您自然能回想起来,是不是有那么一个东西可以用,但是后在回来查便是了。到此为止,我们可能觉得自己无所不能了吧,哈哈哈哈~ 但其实还不够!!!下一章,我们将带大家了解一下 webhooks 以及 GitLab api 相关的内容。