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-test
、java-package
、docker-push
、service-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_script
,after_script
,也可以将其定义为顶级元素,定义为顶级元素将为每一个任务都执行相应阶段的脚本或命令。
variables 变量
在 Gitlab-CI 中,变量大致可分为三类:
1.Gitlab 给我们预先定义的变量,比如CI_COMMIT_BRANCH
.
Predefined variables reference | GitLab
2.Setting => Gitlab CI/CD => variables 中定义的变量
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可以设置以下值:
- on_success - 只有前面stages的所有工作成功时才执行。 这是默认值。
- on_failure - 当前面stages中任意一个jobs失败后执行。
- always - 无论前面stages中jobs状态如何都执行。
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允许使用正则
only
和except
可同时使用。如果only
和except
在一个job配置中同时存在,则以only
为准,跳过except
(从下面示例中得出)。only
和except
允许使用特殊的关键字:branches
,tags
和triggers
。only
和except
允许使用指定仓库地址但不是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
extends
extends 用来继成模板,如果源文件有的,会覆盖模板里的,源文件里没有的,会继承模板里的
stages: - build - test .test: # 模板以 . 开头 stage: test before_script: - echo "我是before_script" script: - echo "哈哈哈" buildjob: stage: build script: ls testjob: extends: .test # 继承 .test 模板,有的会覆盖模板里的,没有的会继承 before_script: - echo "我是在 script 前面运行的" after_script: - echo "我是after_script" script: - echo "嘎嘎嘎"
合并后
testjob: stage: test # 源文件没有,继承 before_script: # 源文件有,覆盖 - echo "我是在 script 前面运行的" after_script: # 模板里没有,使用源文件的 - echo "我是after_script" script: # 源文件有,覆盖 - echo "嘎嘎嘎"
模块化写法
随着流水线任务的变多,把所有的任务都写在.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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
2022-12-21 OAuth2基础(一)