meface/docs/article/devops/gitlabeci.md

353 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## gitlab-ci.yml文件编写
> 转自:[02: gitlab-ci.yml 文件编写](https://blog.csdn.net/weixin_43730107/article/details/135839032)
### 1.什么是gitlab-ci.yml文件
`gitlab-ci.yml` 文件是 GitLab CI/CD 的配置文件,它描述了各项任务如何和何时在版本控制过程中执行。文件中定义了一系列的任务或`jobs`这些jobs可以被组织到各个阶段并在触发某些事件时自动运行如代码提交或代码合并。每次提交或推送都会触发一个新的 CI/CD `pipeline``gitlab-ci.yml` 文件便是负责协调和控制这个 `pipeline` 执行过程的大脑。
### 2.创建第一个 gitlab-ci.yml 文件
**文件结构示例**
```shell
stages:
- build
- test
- deploy
build_job:
stage: build
script:
- echo "This is the build stage"
test_job:
stage: test
script:
- echo "This is the test stage"
deploy_job:
stage: deploy
script:
- echo "This is the deploy stage"
```
`stages` 定义一组阶段,然后在每个工作描述中使用 `stage` 关键字指定其属于哪个阶段。`GitLab CI/CD`将会按照 `stages` 定义的**阶段顺序以及每个阶段内的作业并行度来执行作业**。
### 3.特殊指令
#### before_script
通常`before_script`在`gitlab-ci.yml` 文件的顶层定义,作为全局设置。这样定义的 `before_script` 会在每个作业job执行前都会运行。before_script 虽然有全局配置的偏好,但也可以根据需要在单独的作业中定义。
```shell
# 在这个配置中,全局 before_script 会在 job1 和 job2 两个作业之前都执行一次。
stages:
- build
before_script:
- echo "This is a global before_script."
job1:
stage: build
script: echo "This is job1."
job2:
stage: build
script: echo "This is job2."
```
也可以在具体的作业中定义 before_script这样设置的 before_script 会只影响这个作业。
```shell
# job1 的 before_script 被重写为 "echo "This is a job-specific before_script."",并且只在 job1 执行前运行。
# 全局的 before_script 不会在 job1 之前执行,但会在 job2 之前执行。
# 作业特定的 before_script 会覆盖全局的定义。
stages:
- build
before_script:
- echo "This is a global before_script."
job1:
stage: build
before_script:
- echo "This is a job-specific before_script."
script: echo "This is job1."
job2:
stage: build
script: echo "This is job2."
```
---
#### after_script
after_script它类似于 before_script定义在这里的命令会在每个作业job的 script 部分执行完毕后运行。这常常用来在作业完成之后清理环境或存储日志等。
---
#### variables
可以定义一组环境变量,这些变量会在所有作业中可用。例如,你可能需要在多个作业中使用同一个数据库的链接地址。
```shell
stages:
- build
variables:
DATABASE_URL: "postgres://user:pass@example.com:5432/dbname"
job1:
stage: build
script: echo "The database url is $DATABASE_URL."
```
---
#### stages
定义作业的执行阶段。GitLab CI/CD 会按照 `stages` 的顺序执行作业。
```shell
stages:
- build
- test
job1:
stage: build
script: echo "Build stage"
job2:
stage: test
script: echo "Test stage"
```
---
#### rules and only/except
这两个指令都用于定义作业执行的条件。例如,你可以设置一个作业只在特定分支的提交时运行。
```shell
stages:
- build
- test
- deploy
build_job:
stage: build
script: echo "This is building stage."
only:
- master
test_job:
stage: test
script: echo "This is testing stage."
except:
- master
deploy_job:
stage: deploy
script: echo "This is deploying stage."
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: always
- if: '$CI_COMMIT_BRANCH != "master"'
when: never
```
`build_job` 仅在主分支(`master`上运行。相反test_job会在所有分支上运行除非是主分支。deploy_job 也仅在主分支上运行,使用了 `rules` 指令来实现这个条件,这是一个更复杂的条件判断,不同的规则 (if 语句)可以应对更为复杂的情况。
---
#### cache
允许你定义一个缓存,这个缓存可以在作业之间共享。这常常用于缓存依赖,以加快构建的速度。
```shell
stages:
- install
- build
variables:
BUNDLE_PATH: vendor/bundle
cache:
paths:
- vendor/bundle
install:
stage: install
script:
- bundle install --path vendor/bundle
build:
stage: build
script:
- bundle exec rake build
```
在这个示例中,我们将 Ruby gems 安装到 vendor/bundle 目录下,然后在 cache 指令中声明这个路径来缓存这些 gems。
这样做的好处是,当在后续的作业或者后续的 pipeline 运行时,不需要重新下载和安装这些 gems在此 .gitlab-ci.yml 文件的配置中,如果 cache 设置正确并且有效,然后在 vendor/bundle 路径下的gems没有发生变化即 Gemfile 和 Gemfile.lock 文件没有发生改变),那么 bundle install --path vendor/bundle 命令就不会再次下载已经缓存的 gems。这是因为 BundlerRuby的依赖管理工具会检查 gems 是否已经存在,如果已经存在并且版本匹配,那么就不会再次下载。
综上,对于重复的 install 作业,如果 Gemfile 和 Gemfile.lock 中的内容没有发生变化,那么即使在 pipeline 再次运行此作业,也不会再次下载已经缓存的 gems从而可以加快构建的速度。可以大大减少构建的时间。
`install``build` 两个作业分别在 `install``build` 阶段运行。`install` 阶段会使用 `bundle install` 命令来下载和安装 gemsbuild 阶段则使用 `bundle exec` 来执行构建命令。
通过这个配置,我们就可以在多个作业之间,以及多次 `pipeline` 运行之间共享这些 `gem` 的缓存,以此来加快构建的速度。
对于重复的 install 作业在下次pipeline中会再次运行吗
如果 cache 设置正确并且有效,然后在 vendor/bundle 路径下的gems没有发生变化即 Gemfile 和 Gemfile.lock 文件没有发生改变),那么 bundle install --path vendor/bundle 命令就不会再次下载已经缓存的 gems。这是因为 BundlerRuby的依赖管理工具会检查 gems 是否已经存在,如果已经存在并且版本匹配,那么就不会再次下载。
综上,对于重复的 install 作业,如果 Gemfile 和 Gemfile.lock 中的内容没有发生变化,那么即使在 pipeline 再次运行此作业,也不会再次下载已经缓存的 gems从而可以加快构建的速度。
---
#### artifacts
声明一些构建产物,这些产物将会在 `gitlab-ci.yml` 文件中其他作业或后续阶段的作业中可用,或者可供直接下载查看。
```shell
stages:
- build
- test
build:
stage: build
script:
- mkdir build
- echo "Build artifacts" > build/artifacts.txt
artifacts:
paths:
- build/
test:
stage: test
script:
- cat build/artifacts.txt
```
在这个示例中,我们的 pipeline 分为两个阶段build 和 test。在 build 阶段运行的 build 作业中,我们创建了一个 build 目录,并在其中生成了一个名为 artifacts.txt 的文件。
然后,我们使用 `artifacts` 指令声明了 `build/` 路径下的所有文件都是构建产物GitLab CI/CD 将会在构建完成后收集这些产物。
在后续的 test 阶段的 test 作业中,我们可以直接访问到这个 artifacts.txt 文件。也就是说,通过 `artifacts` 允许我们在后续阶段的作业中使用到前一阶段的构建产物。
---
#### include
用于在当前 .gitlab-ci.yml 文件中引入其他的 CI/CD 配置文件,可以实现配置的模块化和共享。被引入的文件可以位于同一项目的其它位置,也可以位于其他项目,甚至可以从远程的 HTTP(S) URL 中引入。引入的文件将像是在主配置文件中一样被解析和执行,这对于大型项目或需要共享 CI/CD 配置的情况很有用。
比如说,你有一个库 my-great-library。该库有自己的 .gitlab-ci.yml 文件,如下:
```shell
variables:
BUILD_DIR: build
stages:
- build
- test
build:
stage: build
script:
- mkdir ${BUILD_DIR}
- echo "Building the library" > ${BUILD_DIR}/result.txt
test:
stage: test
script:
- echo "Testing the library"
```
而你在其他许多项目里都依赖这个库,并且需要对这个库进行构建和测试。这时,你可以在其他项目的 CI 标记 include将这个库的 CI/CD 配置包含进来,例如:
项目 project-1 的 .gitlab-ci.yml
```shell
include:
- project: 'yourusername/my-great-library'
file: '.gitlab-ci.yml'
```
这样就可以实现在多个项目中共享一个统一的 CI/CD 配置,避免了每个项目都需要重复编写相同的配置,从而大大提高了效率。同时也有利于集中管理和修改这个共享的配置。
---
#### extends
用于复用已经定义的特定配置。在 GitLab CI/CD 配置中,我们可以定义一些通用的配置作为模板,例如设定重用的 `script` 块或者 `before_script` 块等,然后在需要的地方使用 `extends` 进行引用。不同于 `include` 关键词,`extends `并不会引入新的文件,而是仅仅在当前文件内部进行配置的重用。
```shell
# 我们首先声明一个 '.base_job',这个定义包含了所有作业共有的部分
.base_job:
before_script:
- echo "Setting up the job environment"
after_script:
- echo "Cleaning up after job"
# '.build_template' 扩展了 '.base_job',并添加了构建阶段特有的设定
.build_template:
extends: .base_job
variables:
BUILD_DIR: build
script:
- mkdir ${BUILD_DIR}
- echo "Building the project" > ${BUILD_DIR}/output.txt
stage: build
# '.test_template' 也扩展了 '.base_job',然后添加了测试阶段特有的设定
.test_template:
extends: .base_job
script:
- echo "Testing the project"
stage: test
# 现在我们定义具体的构建和测试作业,它们分别扩展了 '.build_template' 和 '.test_template'
job1:
extends: .build_template
variables:
JOB_NAME: JOB1
job2:
extends: .test_template
variables:
JOB_NAME: JOB2
stages:
- build
- test
```
通过 .base_job我们为所有作业指定了公共的 before_script 和 after_script。然后对于构建和测试阶段我们又分别创建了扩展了 .base_job 的 .build_template 和 .test_template。最后我们创建了两个具体的作业 job1 和 job2它们扩展了各自的模板并添加了一些特定的配置。.base_job作为模板.build_template和.test_template去继承它如果二者都有相同的key则使用子类的value覆盖父类同理job1和job2。
---
#### tags
`tags`是用来选择执行该 `job` 的特定 `Runner`
Runner 是 GitLab 提供的用于执行 CI/CD 任务的服务。每个 Runner 可以配置一组标签tags这样在定义 CI/CD 任务时,就可以通过设置相应的 tags 来选择对应的 Runner 来执行任务。
tags 中的 arm 指的是这个任务build_docker_arm必须由带有 arm 标签的 Runner 执行。这通常表示这个 Runner 是能够构建 ARM 架构 Docker 镜像的环境。如果没有带 arm 标签的 Runner该任务会排队等待直到有合适的 Runner 可用。所以这个 tags 配置是用来选择 Runner而不是在 build 镜像时指定基础镜像。