美文网首页
1.2 .gitlab-ci.yml里使用的关键字2

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

作者: shark_tear | 来源:发表于2021-08-21 23:15 被阅读0次

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

    • variables
    • image
    • service
    • 隐藏任务
    • extends
    • stage
    • before_script
    • script
    • after_script

    variables

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

    • 自定义变量,即使用variables关键字定义的变量
    • 预定义变量,即gitlab官方提前定义好的变量,可以直接使用。例如CI_COMMIT_REF_NAME,表示正在构建项目的分支或者tag名称。

    变量定义的一些规则:

    • 在变量的名称和值里都只能出现数字和字符串。
    • 出现同名变量时,后出现的值覆盖先出现的。
    • 所有YAML格式定义的变量在服务容器里都可以访问到。

    示例如下:

    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:latest
    • image: <image-name>:<tag>
    • image: <image-name>@<digest>
      即使用最新镜像,标签指定镜像,哈希值指定镜像

    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关键字里指定的镜像创建的任务容器上。实际上的流程比这一句要复杂的多,简单概括一下,应该是:

    • 根据services里指定的镜像,启动一个服务容器(service container)
    • 根据job里的image启动一个任务容器(job container)
    • 将服务容器和任务容器链接到一起,然后在任务容器里可以通过主机名访问服务容器里提供的服务(目前还不知道有什么用)

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

    • postgresql
    • mysql
    • redis
    • gitlab
      具体的用法后面再具体研究,这个services.gitlab-ci.yml文件里的用法如下所示:
    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个参数:

    • name,服务名称,也是镜像名称
    • alias,别名,可以用来在任务容器里访问服务,因为默认名称在带有registry信息的时候非常长,不方便使用,可以设置一个简短的别名。
    • entrypoint,用来覆盖服务镜像默认执行命令
    • command,和Dockerfile里的CMD指令类似,用来覆盖镜像里默认的CMD指令。

    隐藏任务(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会做以下操作:

    • 基于键做深度迭代合并
    • 合并.tests的内容到rspec任务
    • 不会合并键对应的值

    最终解析出来的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."
    

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

    • 有多个runner,可以一次运行多个任务
    • 一个runner里的concurrent设置大于1,表示一个runner可以同时运行超过1个任务,此时可以并发执行多个任务。

    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个任务的执行顺序按照规则依次是:

    • first-job
    • job1
    • job2
    • last-job

    before_script

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

    • 单行命令
    • 分为多行的单个长命令
    • YAML锚

    `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里定义的命令类型包括:

    • 单行命令
    • 分为多行的单个长命令
    • YAML锚

    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命令的执行环境是隔离开的。因此:

    • 会将当前工作目录设置为默认值
    • 无权访问before_script或script里定义的命令做出的修改,包括:
      • 在script脚本里定义的命令别名或导出的变量
      • 在工作树以外做出的修改(取决于runner执行器),像在before_script里或script里安装的软件。
    • 有一个独立的超时时间,硬编码为5min
    • 不会影响任务的结束代码。如果任务的script部分成功执行,但是after_script超时导致失败。整个任务的结束代码还是0(表示任务成功执行)
    • 如果任务超时或者被取消,after_script不会执行。

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

    相关文章

      网友评论

          本文标题:1.2 .gitlab-ci.yml里使用的关键字2

          本文链接:https://www.haomeiwen.com/subject/assxiltx.html