1.2 .gitlab-ci.yml里使用的关键字2

2021-08-21  本文已影响0人  shark_tear

今天在家里又看了一些.gitlab-ci.yml文件里使用的关键字,晚上看的时候感觉这种效率很低,但是还是想把这个文件里使用的关键字全都过一遍。目前也没有摸索到更好的学习办法,暂且先这样吧。先看看今天学习的几个关键字和概念。

variables

用来定义变量,既可以在全局范围使用,也可以单任务级别使用。在gitlab里,变量分为两种类型:

变量定义的一些规则:

示例如下:

variables:
  DEPLOY_SITE: "https://example.com/"

deploy_job:
  stage: deploy
  script:
    - deploy-script --url $DEPLOY_SITE --path "/"

deploy_review_job:
  stage: deploy
  variables:
    REVIEW_PATH: "/review"
  script:
    - deploy-review-script --url $DEPLOY_SITE --path $REVIEW_PATH

调用方式和shell里调用变量的方式一样。

手动流水线里可以使用value和description来定义预填充变量:
示例如下:

variables:
  DEPLOY_ENVIRONMENT:
    value: "staging"  # Deploy to staging by default
    description: "The deployment target. Change this variable to 'canary' or 'production' if needed."

但是手动流水线的概念还没搞明白,所以这块内容在后面需要进行修改和更新。

image

用来指定运行这个任务的docker镜像。基本用法如下所示:

default:
  image: ruby:2.6

  services:
    - postgres:11.7

  before_script:
    - bundle install

test:
  script:
    - bundle exec rake spec

上面的示例中使用default关键字定义了一个全局的镜像参数,即所有任务默认都会使用这个镜像。除此之外,还可以在任务级别定义,即每个任务使用自己的镜像:

build-job1:
  stage: build
  image: nginx:1.8.0  

在上面这个示例中,build-job1任务使用nginx:1.8.0镜像。(待测试)

镜像的名称遵循下面的格式:

image的扩展用法

image:name
用来指定镜像的名称,用法如下:

image:
  name: 'registry.example.com/my/image:latest'  

这种用法和上面的三种没有区别。这种用法一般是和下面的entrypoint搭配使用。

image:entrypoint
entrypoint是用来覆盖镜像默认的执行命令。用法如下:
17.06及之后的版本

image:
  name: super/sql:experimental
  entrypoint: [""]

17.03及之前的版本

image:
  name: super/sql:experimental
  entrypoint: ["/bin/sh", "-c"]

上面这两种格式,会让runner基于镜像super/sql:experimental启动一个新镜像,但是会使用默认的shell来覆盖原来镜像的启动命令。

除了使用默认shell覆盖以外, 还可以使用其他任何你想使用的命令来覆盖,只需要将命令写入上面的entrypoint后面的数组里即可。

services

这个关键字用来指定一个服务容器镜像,在任务运行的时候,会创建一个服务容器,链接到image关键字里指定的镜像创建的任务容器上。实际上的流程比这一句要复杂的多,简单概括一下,应该是:

目前服务容器主要作用还是当做一个单独的小数据库使用,官方文档上提供的4种服务容器类型分别是:

default:
  before_script:
    - bundle install

test:2.6:
  image: ruby:2.6
  services:
    - postgres:11.7
  script:
    - bundle exec rake spec

test:2.7:
  image: ruby:2.7
  services:
    - postgres:12.2
  script:
    - bundle exec rake spec

在test:2.6任务里,定义的任务容器镜像是ruby:2.6,服务镜像是postgres:11.7

除了这种格式以外,还有更复杂一点的定义方式,看下面的示例:

default:
  image:
    name: ruby:2.6
    entrypoint: ["/bin/bash"]

  services:
    - name: my-postgres:11.7
      alias: db-postgres
      entrypoint: ["/usr/local/bin/db-postgres"]
      command: ["start"]

  before_script:
    - bundle install

test:
  script:
    - bundle exec rake spec

在services下支持另外4个参数:

隐藏任务(hidden_job)

如果想临时禁用一个任务,除了将它注释起来以外,还可以在它名称前面加一个点号,将它变成一个隐藏任务,这样在Gitlab的UI界面就看不到这个任务了,它也不会实际执行,如下所示:

.hidden_job:
  script:
    - run test

隐藏任务在.gitlab-ci.yml里的用法一般是用来做一些命令、变量或者配置的模板。在其他位置导入,例如昨天发布的文章里介绍的YAML锚,就可以导入隐藏任务模板。

extends

extends关键字是用来复用配置部分,和它功能类似的是YAML锚,但是它更灵活且可读性更强。它和YAML锚的区别是,可以从include关键字包含进来的配置文件里复用配置。

看下面的示例:

.tests:
  script: rake test
  stage: test
  only:
    refs:
      - branches

rspec:
  extends: .tests
  script: rake rspec
  only:
    variables:
      - $RSPEC

在这个例子里,rspec任务复用了来自.tests任务模板里的配置。然后在实际执行时,Gitlab会做以下操作:

最终解析出来的rspec任务内容如下所示:

rspec:
  script: rake test
  stage: test
  only:
    refs:
      - branches
    variables:
      - $RSPEC  

从结果中可以看到,相同的键only,它下面的两个值会合并到一起,用于最终的条件判断。only关键字在后面会介绍。

多级别继承

extends支持多级别继承,在实际使用的时候,应该避免超过3层的命令,最多可以使用11层(但是不要使用,太过复杂)。下面的实例演示了一个2层继承:

.tests:
  rules:
    - if: "$CI_PIPELINE_SOURCE" = "push"
    
.rspec:
  extends: .tests
  script: rake test

rspec 1:
  variables:
    RSPEC_SUITE: '1'
  extends: .rspec

rspec 2:
  variables:
    RSPEC_SUITE: '2'
    extends: .rspec
    
spinach
  extends: .tests
  script: rake spinach 

在上面的示例中,rspec1rspec2这两个任务都是双层扩展,他们俩扩展.rspec 这个隐藏任务模板的内容,而.rspec扩展来自.tests任务模板的内容。

合并细节

可以使用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                        

在上面的示例里,同时扩展了.only-important.in-docker这两个隐藏任务模板。而在这两个模板里面,有一个相同的变量URL,一个相同的tags。后扩展的是.in-docker模板,那么最终生效的是.in-docker里的URL变量以及tags,即URL变量的值是 "http://docker-url.internal"tags的值是docker。最终的rspec任务的内容是:

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

script的内容不会合并,因此最终生效的是rspec里自己的script,即- rake rspec

extendsinclude结合使用

要复用来自其他配置文件里的配置,可以结合使用extendsinclude,示例如下:
included.yaml文件内容

.template:
  script:
    - echo Hello!  

.gitlab-ci.yml文件内容:

include: included.yml

useTemplate:
  image: alpine
  extends: .template  

extends会首先到.gitlab-ci.yml文件里找.template模板的定义,如果没找到,才会去included.yml文件里查找。

stage

stage关键字用来定义任务所属的阶段,在相同stage里的任务会并行执行。如果没有定义stage参数,那么这个任务默认属于test阶段。

stage示例如下:

stages:
  - build
  - test
  - deploy

job1:
  stage: build
  script:
    - echo "This job compiles code."

job2:
  stage: test
  script:
    - echo "This job tests the compiled code. It runs when the build stage completes."

job3:
  script:
    - echo "This job also runs in the test stage".

job4:
  stage: deploy
  script:
    - echo "This job deploys the code. It runs when the test stage completes."

对于并发执行的任务,有一些前提条件:

stage: .prestage: .post

.pre阶段里的任务会在流水线开始执行之前就执行完成。.post是流水线任务执行完成以后执行的阶段。用户不需要自己定义.pre.post阶段,可以直接在任务里直接使用stage: .prestage: .post将任务划分到这两个阶段即可。看下面的示例:

stages:
  - build
  - test

job1:
  stage: build
  script:
    - echo "This job runs in the build stage."

first-job:
  stage: .pre
  script:
    - echo "This job runs in the .pre stage, before all other stages."

job2:
  stage: test
  script:
    - echo "This job runs in the test stage."

last-job:
  stage: .post
  script:
    - echo "This job runs in the .post stage, after all other stages."   

在上面的示例里,4个任务的执行顺序按照规则依次是:

before_script

before_script用来定义一个命令数组,在任务运行之前,会先执行这部分命令。但是artifactsbefore_script先执行,后面会介绍artfacts的用途。
beforce_script里定义的命令类型包括:

`before_script示例如下:

job:
  before_script:
    - echo "Execute this command before any `script:` command"
  script:
    - echo "This command execute after before-script command"    

提示,before_script里定义的命令和script里定义的命令是按照顺序在相同的shell里执行的。

script

使用script指定runner执行的shell脚本。除了触发任务(trigger job)以外,其他任务都需要使用script关键字指定执行的脚本。例如:

单个命令

job:
  script: "bundle exec rspec"

多个命令

job:
  script:
    - uname -a
    - bundle exec rspec  

有时候需要将命令使用单引号或双引号括起来,如下所示:

job:
  script:
    - curl --request POST --header 'Content-Type: application/json' \
        "https://gitlab/api/v4/projects"
job:
  script:
    - 'curl --request POST --header "Content-Type: application/json" \
        "https://gitlab/api/v4/projects"'

在写这些命令的时候,需要注意下面这些特殊字符:
{, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @,
如果某个命令的返回结果不是0,那么整个任务就会执行失败,可以捕获命令的返回结果,主动报错。但是可以保证任务不结束:

job:
  script:
    - false || exit_code=$?
    - if [ $exit_code -ne 0 ]; then echo "Previous command failed"; fi;

after_script

使用after_script可以定义一个命令数组,用于在任务执行完成之后执行,包括失败的任务。

在after_script里定义的命令类型包括:

after_script示例:

job:
  script:
    - echo "An example script section"
  after_script:
    - echo "Execute this command after the `script` section completes"  

提示:在after_script里指定的脚本是在新shell里执行的,和before_script以及script命令的执行环境是隔离开的。因此:

以上就是今天学习的几个脚本关键字,明天继续。

上一篇下一篇

猜你喜欢

热点阅读