Gitlab-CICD

CICD是什么

我们的开发模式经历了如下的转变:瀑布模型->敏捷开发→DevOps(Development、Operations的组合词,是一组过程、方法与系统的统称)

后来随着DevOps的兴起,出现了持续集成(Continuous Integration)、持续交付(Continuous Delivery) 、持续部署(Continuous Deployment) 的新方法,关于持续集成、持续交付、持续部署,总结如下:

  • 持续集成的重点是将各个开发人员的工作集合到一个代码仓库中。通常,每天都要进行几次,主要目的是尽早发现集成错误,使团队更加紧密结合,更好地协作。
  • 持续交付的目的是最小化部署或释放过程中固有的摩擦。它的实现通常能够将构建部署的每个步骤自动化,以便任何时刻能够安全地完成代码发布(理想情况下)。
  • 持续部署是一种更高程度的自动化,无论何时对代码进行重大更改,都会自动进行构建/部署。

持续集成的好处是什么?

持续集成可以使问题尽早暴露,从而也降低了解决问题的难度,正如老马所说,持续集成无法消除bug,但却能大大降低修复的难度和时间。

持续交付的好处是什么?

持续交付的好处在于快速获取用户反馈;适应市场变化和商业策略的变化。开发团队保证每次提交的修改都是可上线的修改,那么决定何时上线,上线哪部分功能则完全由产品业务团队决定。

虽然持续交付有显著的优点,但也有不成立的时候,比如对于嵌入式系统的开发,往往需要软硬件的配合。

持续部署的好处是什么?

持续部署的目标是通过减少批量工作的大小,并加快团队工作的节奏,帮助开发团队在其开发流程中消除浪费。这使团队能够一直处于一种可持续的平稳流状态, 让团队更容易去创新、试验,并达到可持续的生产率

市面上的CI有很多,如果在github上搜一下ci工具,也会搜到很多,比如:

相关概念

runner

部署 Gitlab runner 官方文档:Run GitLab Runner in a container | GitLab
关联 runner 到 gitlab 官方文档:Registering runners | GitLab

我们可以简单的把 Gitlab runner 给理解成.gitlab-ci.yml 文件内容的执行者,.gitlab-ci.yml 告诉了 Gitlab runner 去做什么。
Gitlab runner 不是一个配置项,它是需要专门部署的,比如用 docker 部署一个 runner 镜像到可以连接内网的容器。也可以使用公司内配好的 shared runners.

runner是一个单独的程序需要安装,并配置到gitlab

pipeline(管道流水线)

  • 一次 Pipeline 其实相当于一次构建任务,里面可以包含多个流程(Stage),比如自动构建、自动进行单元测试、自动进行代码检查等流程 ;
  • 任何提交或者 Merge Request 的合并都可以触发 Pipeline ;

Stage(构建阶段)

  • Stage表示构建阶段,就是上面提到的流程 ;
  • 可以在一次 Pipeline中定义多个 Stage;
  • Stage有如下特点 :
    • 所有 stages 会按照顺序运行,即当一个 stage 完成后,下一个 Stage才会开始
    • 只有当所有 Stage 成功完成后,该构建任务 Pipeline 才算成功
    • 如果任何一个 Stage失败,那么后面的 Stage 不会执行,该构建任务 (Pipeline) 失败

 

阶段是对批量的作业的一个逻辑上的划分,每个 pipeline都必须包含至少一个 Stage。多个 Stage是按照顺序执行的,如果其中任何一个 Stage失败,则后续的 Stage不会被执行,整个 CI 过程被认为失败。

Jobs(任务)

  • job表示构建工作,表示某个stage里面执行的工作 ;
  • 一个stage里面可以定义多个job ;
  • jobs有如下特点 :
    • 相同 stage 中的jobs 会并行执行
    • 相同 stage 中的 jobs 都执行成功时,该 stage 才会成功
    • 如果任何一个job 失败,那么该 stage 失败,即该构建任务 (Pipeline) 失败

.gitlab-ci.yml 文件

.gitlab-ci.yml 文件被用来管理项目的 runner 任务,Gitlab CI通过.gitlab-ci.yml文件管理配置job,该文件定义了statge顺序、job应该如何触发和工作、执行什么脚本、如何构建pipeline等流程

Yaml Syntax 写法详情具体请见 => YAML Syntax ‒ Ansible Documentation

yml和json写法的对比

例子1

1.数组写法

{
    "array": ["red", "blue", "yellow"]
}

2.yml写法

array:
  - red
  - blue
  - yellow

例子2

1.对象写法

{
  "student1": {
    "name": "小明"
  },
  "array": ["red", "blue", "yellow"],
  "student2": {
    "name": "小明"
  }
}

2.json写法

# 我是注释
student1:
  name: 小明
array:
  - red
  - blue
  - yellow
student2:
  name: 小明

简单例子

 

这里的四个Statge(阶段): Verify、Build、Dockerpush、Deploy四个,这四个阶段组成一条Pipeline

每个阶段都有一个job,所以总共四个job,也就是unit-testjava-packagedocker-pushservice-1这四个,当然,每个stage可以由多个job组成

 

对应.gitlab-ci.yml

## 定义pipeline流程:verify->build->dockerpush->deploy
stages:
  - verify
  - build
  - dockerpush
  - deploy
 
#单元测试

 
#java编译
java-package:
  stage: build
  tags:
    - test-cicd
  script:
    - echo build
 
#push镜像
docker-push:
  stage: dockerpush
  tags:
    - test-cicd
  script:
    - echo docker-push
 
#deploy
service-1:
  stage: deploy
  tags:
    - test-cicd
  script:
    - echo deploy

 

runner执行流程 

Gitlab-CI 关键字

Gitlab CI 的关键字有很多,但实际常用的只有较小一部分。在此部分会对常用关键字进行详解。
如果需要特殊配置可参考关键字文档=> Keyword reference for the .gitlab-ci.yml file | GitLab

script

需要被运行的脚本。以数组形式配置。

pipeline_job:
  ......
  script:
    - cd <文件夹目录路径>
    - npm install
    - npm build
  ......

before_script和after_script

随着项目越来越大,Job 越来越多,Job 中包含的重复逻辑可能会让配置文件臃肿不堪。.gitlab-ci.yml 中提供了 before_script 和 after_script 两个全局配置项。这两个配置项在所有 Job 的 script 执行前和执行后调用。

before_script 和 script 在一个上下文中是串行执行的,after_script 是独立执行的。所以根据执行器(在runner注册的时候,可以选择执行器,docker,shell 等)的不同,工作树之外的变化可能不可见,例如,在before_script中执行软件的安装。

你可以在任务中定义 before_scriptafter_script,也可以将其定义为顶级元素,定义为顶级元素将为每一个任务都执行相应阶段的脚本或命令。

variables 变量

在 Gitlab-CI 中,变量大致可分为三类:

1.Gitlab 给我们预先定义的变量,比如CI_COMMIT_BRANCH.

Predefined variables reference | GitLab

2.Setting => Gitlab CI/CD => variables 中定义的变量

3.在.gitlab-ci.yml 中定义的变量(如下示例)
variables:
  TEST_VAR: "All jobs can use this variable's value"

job1:
  variables:
    TEST_VAR_JOB: "Only job1 can use this variable's value"
  script:
    - echo "$TEST_VAR"
  ......

image

CI 流水线运行环境的 docker 镜像(任何相关的代码运行环境镜像皆可),比如docker镜像安装了代码质量扫码工具

.sonarqube:
  stage: check
  tags:
    - "public"
  image: sonarsource/sonar-scanner-cli:4.6
  allow_failure: false
  variables:
    SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"  # Defines the location of the analysis task cache
    GIT_DEPTH: "0"  # Tells git to fetch all the branches of the project, required by the analysis task
  cache:
    key: "SONAR_${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - |
      if [ -f "sonar-project.properties" ];then
      sonar-scanner -Dsonar.sources=. -Dsonar.branch.name=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
      fi
  only:
    refs:
      - merge_requests

stages

Gitlab CI 允许我们进行自定义的流水线阶段配置,我们可以将自己的流水线自我划分为若干stages,然后在不同的 stage 来做不同的事

 
## 定义pipeline流程:verify->build->dockerpush->deploy
stages:
  - verify
  - build
  - dockerpush
  - deploy

stage

stage 为 stages 的一个子项,在我们自定义单个流水线任务时可以配置

unit-test:
  stage: verify # 属于哪个流程
  tags:
    - test-cicd # 在哪个runner上面执行,在注册runner可以自定义
  script:
    - echo unit-test # 执行脚本

cache

缓存多个流水线任务之间共用的文件,目录, etc.

cache:
  key: cache-node-modules
  # 在这里写出需要缓存的文件的路径,在此为node_modules
  paths:
    - node_modules

retry

一个 job 可以被重新执行的最大数量。必须是个正整数, 0-2, 2 为最大值

  • when 可设置在特定失败原因的情况下执行
job:
  script: rspec
  retry:
    max: 2
    when: runner_system_failure

when

when可以设置以下值:

  1. on_success - 只有前面stages的所有工作成功时才执行。 这是默认值。
  2. on_failure - 当前面stages中任意一个jobs失败后执行。
  3. always - 无论前面stages中jobs状态如何都执行。
  4. manual - 手动执行(GitLab8.10增加)。
stages:
- build
- cleanup_build
- test
- deploy
- cleanup
 
build_job:
  stage: build
  script:
  - make build
 
cleanup_build_job:
  stage: cleanup_build
  script:
  - cleanup build when failed
  when: on_failure
 
test_job:
  stage: test
  script:
  - make test
 
deploy_job:
  stage: deploy
  script:
  - make deploy
  when: manual
 
cleanup_job:
  stage: cleanup
  script:
  - cleanup after jobs
  when: always

本说明:

  • 只有当build_job失败的时候才会执行`cleanup_build_job 。
  • 不管前一个job执行失败还是成功都会执行`cleanup_job 。
  • 可以从GitLab界面中手动执行deploy_jobs。

manual:

  • 在GitLab的用户界面中显示该作业的“播放”按钮
  • 意味着deploy_job仅在单击“播放”按钮时才会触发job。

修改后例子

stages:
  - verify
  - build
  - dockerpush
  - deploy
  - cleanup
 
before_script:
  - pwd
after_script:
  - echo after_script
 
#单元测试
unit-test:
  stage: verify
  tags:
    - test-cicd
  script:
    - echo unit-test
 
#java编译
java-package:
  stage: build
  tags:
    - test-cicd
  script:
    - echo build
 
#push镜像
docker-push:
  stage: dockerpush
  tags:
    - test-cicd
  script:
    - echo docker-push
 
#deploy
service-1:
  stage: deploy
  tags:
    - test-cicd
  script:
    - echo deploy
  when: manual # 手动触发job,只有点击按钮才会触发
 
cleanup_job:
  stage: cleanup
  script:
    - echo clean up
  when: always # 前面的job成功与否,都会执行该job

 

 

 

only & except

only和except两个参数说明了job什么时候将会被创建:

  • only定义了job需要执行的所在分支或者标签
  • except定义了job不会执行的所在分支或者标签

以下是这两个参数的几条用法规则:

  • only和except如果都存在在一个job声明中,则所需引用将会被only和except所定义的分支过滤.
  • only和except允许使用正则
  • onlyexcept可同时使用。如果onlyexcept在一个job配置中同时存在,则以only为准,跳过except(从下面示例中得出)。
  • onlyexcept允许使用特殊的关键字:branchestagstriggers
  • onlyexcept允许使用指定仓库地址但不是forks的仓库(查看示例3)

例子1

.job将会只在issue-开头的refs下执行,反之则其他所有分支被跳过:

job:
    # use regexp
    only:
        - /^issue-.*$/
    # use special keyword
    except:
        - branches

例子2

job只会在打了tag的分支,或者被api所触发,或者每日构建任务上运行

job:
    # use special keywords
    only:
        - tags      # tag 分支 commit 之后触发
        - triggers  # API 触发
        - schedules # 每日构建触发

例子3

.job将会在父仓库gitlab-org/gitlab-ce的非master分支有提交时运行。

job:
    only:
        - branches@gitlab-org/gitlab-ce
    except:
        - master@gitlab-org/gitlab-ce

模块化写法

随着流水线任务的变多,把所有的任务都写在.gitlab-ci.yml 文件中会显得很臃肿
解决方法是拆分多个任务到不同的模块

.gitlab.yml文件中按照如下写法即可引入不同的 yml 文件

include:
  - local: /.gitlab-ci/cache.yml
  - local: /.gitlab-ci/check.yml
  - local: /.gitlab-ci/pre-build.yml
  - local: /.gitlab-ci/build.yml
  - local: /.gitlab-ci/deploy.yml
  - local: /.gitlab-ci/publish-report.yaml

完整例子

例子1

# .gitlab-ci.yml
# 镜像为node的环境镜像,如果用的是别的环境可以更改为别的项目环境的镜像
image: node:latest

# 自定义stages
stages:
  - first_stage
  - second_stage
  - third_stage
  - fourth_stage
  - fifth_stage

# 自定义任务1
job_1_push:
  only:
    - pushes
  # 设置使用fe tags标签的shared runner
  tags:
    - yehanli
  # 当前任务需要执行的脚本
  script:
    - echo 'job1 ========= 完成'
  # 设置当前任务的stage
  stage: first_stage

# 自定义任务2
job_2_push:
  only:
    - pushes
  tags:
    - yehanli
  script:
    - echo 'job2 ========= 完成'
  stage: third_stage
# 自定义任务3
job_3_push:
  only:
    - pushes
  tags:
    - yehanli
  script:
    - echo 'job3 ========= 完成'
  stage: fourth_stage
  # 设置当前任务为手动触发
  when: manual

# 自定义任务4
job_4_push:
  only:
    - pushes
    - tags
  tags:
    - yehanli
  script:
    - echo 'job4 ========= 完成'
  stage: fourth_stage
  when: always

# 自定义任务5
job_5_web:
  only:
  # 设置为点击run pipeline时触发,流水线不自动触发
    - web
  tags:
    - yehanli
  script:
    - echo 'job5 ========= 完成'
  stage: fifth_stage

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章