## 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。这是因为 Bundler(Ruby的依赖管理工具)会检查 gems 是否已经存在,如果已经存在并且版本匹配,那么就不会再次下载。 综上,对于重复的 install 作业,如果 Gemfile 和 Gemfile.lock 中的内容没有发生变化,那么即使在 pipeline 再次运行此作业,也不会再次下载已经缓存的 gems,从而可以加快构建的速度。可以大大减少构建的时间。 `install` 和 `build` 两个作业分别在 `install` 和 `build` 阶段运行。`install` 阶段会使用 `bundle install` 命令来下载和安装 gems,build 阶段则使用 `bundle exec` 来执行构建命令。 通过这个配置,我们就可以在多个作业之间,以及多次 `pipeline` 运行之间共享这些 `gem` 的缓存,以此来加快构建的速度。 对于重复的 install 作业,在下次pipeline中会再次运行吗? 如果 cache 设置正确并且有效,然后在 vendor/bundle 路径下的gems没有发生变化(即 Gemfile 和 Gemfile.lock 文件没有发生改变),那么 bundle install --path vendor/bundle 命令就不会再次下载已经缓存的 gems。这是因为 Bundler(Ruby的依赖管理工具)会检查 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 镜像时指定基础镜像。