GitLAB-CI-CD
GitLab CI-CD
目录
[toc]
GitLabCI/CD简介
GitLabCI/CD简介
GitLabCI/CD是GitLab内置的持续集成与持续部署系统
- 开源: CI/CD是开源GitLab社区版和专有GitLab企业版的一部分。(极狐)
- 易于学习: 官方具有详细的学习操作文档。
- 无缝集成: CI/CD是GitLab的一部分,支持从计划到部署,具有出色的用户体验。 (例如:做一些基于版本控制系统的提交流水线、合并流水线,是很方便的!)
- 可扩展: 可以根据需要添加任意数量的构建节点。
- 更快的结果: 每个构建可以拆分为多个作业,这些作业可以在多台计算机上并行运行。
- 针对交付进行了优化: 多个阶段,手动部署, 环境 和 变量。
- 针对交付进行了优化: 多个阶段,手动部署, 环境和变量。
jenkins里,你想要获取git分支、git提交用户的话,我们都需要先去抓收据,去采集数据,进行一个过滤,再拿到;
但在gitlab里,使用gitlab ci时,里面就有现成的环境变量,我们直接使用就好,所以这一点,还是有很大的优势的。这个文档是大家在开发流水线时必须依赖的一个文档,使用时要注意下这里的版本!
https://docs.gitlab.com/14.9/ee/ci/variables/predefined_variables.html
gitlab ci/cd官方文档
https://docs.gitlab.com/14.9/ee/ci/
常用变量参考文档:
https://docs.gitlab.com/14.9/ee/ci/variables/predefined_variables.html
Pipeline
在每个项目中,使用名为的YAML文件配置GitLab CI/CD
流水线。
Stages
一条流水线可以包含若干个阶段, 一个阶段可以包含若干个作业。
Job
作业是具体要执行的任务,命令脚本语句的集合;
Runner
Runner是每个作业的执行节点 ;每个作业可以根据标签选择不同的构建节点;
GitLabRunner安装部署
见独立md文件。
开发第一条Pipeline
1. gitlab-ci.yml
如何开启GitLabCI/CD? 首先要将代码存储到GitLab, 然后在代码库的(默认根目录)添加一个.gitlab-ci.yml
文件。该文件中定义了流水线的阶段和运行步骤。
根据不同的场景,可以自定义流水线定义文件的位置。
(默认)存储到项目根目录: /.gitlab-ci.yml
为项目中添加.gitlab-ci.yml
文件,表示启动的CI/CD。默认提交动作会自动运行该.gitlab-ci.yml
中定义的作业。
- 来到gitlab项目里,创建一个
.gitlab-ci.yml
文件
- 1 填写当前创建的文件的名称
.gitlab-ci.yml
; - 2 选择文件的类型;
- 3 选择一个项目模板;(这里我们先选择一个bash类型)
进行提交,默认就会自动跑流水线了:
但是,此时流水线状态为pending状态,这是为什么呢?
- 根据报错提示,可以知道是因为
.gitlab-ci.yml
文件里没指定runner
我们这里先重新写下代码
因此,一般情况下,我们再写流水线代码时,一般需要给每个阶段指定tags:
注意:这里的每个阶段都要添加这个tags才行!
改好后,提交,并观察流水线运行状态:
此时,流水线运行状态就正常了。
- 我们这里想手动来触发下流水线,观察下test阶段2个作业,为什么这2个作业不是并行运行的呢?
- 是因为我们的gitlab-runner的配置文件里需要修改下并行选项参数:
[root@Devops6 ~]#vim /etc/gitlab-runner/config.toml
将concurrent = 1
改为
concurrent = 10
配置完后,默认生效的。
- 我们再来运行一次流水线,观察下现象
可以看到,这里是并行运行作业的了,符合预期。
2. 流水线页面
- 1 清除runner的缓存;
- 2 进行CI文件语法校验;
- 3 手动触发运行流水线;
- 4 流水的步骤, 可以查看各个阶段的运行日志;
3. Pipeline编辑器
Pipeline开发工具与设置
1.Pipeline开发工具
可视化编辑器
变更.gitlab-ci.yml文件后, 可以通过Visualize
对CI文件中的定义进行可视化;
语法检测校验
通过Lint可以检测当前CI文件是否存在语法错误;若存在语法错误可以根据提示进行修正;
作业运行日志
一条流水线包含很多个作业,每个作业的运行日志可以在Jobs
界面看到。
Pipeline环境变量
预定义变量信息:https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
代码类
- CI_COMMIT_AUTHOR 提交人
- CI_COMMIT_BRANCH 提交分支
- CI_COMMIT_MESSAGE
- CI_COMMIT_REF_NAME
- CI_COMMIT_SHORT_SHA
作业类:
- CI_JOB_ID
- CI_JOB_NAME
- CI_JOB_STAGE
- CI_JOB_URL
流水线类:
- CI_PIPELINE_ID
- CI_PIPELINE_SOURCE
- CI_PIPELINE_TRIGGERED
- CI_PIPELINE_URL
2.Pipeline设置
General pipelines
管道权限、取消冗余管道、跳过历史部署作业;
为项目自定义ci文件
- 修改名称:gitlab-ci-cd.yml
- 自定义路径:../ci/xx/xx/.yml
- 也是可以这种raw格式的:(但是切记,一定是可公开访问的路径,不能到凭据信息)
http://172.29.9.101:8076/devops6/devops-demo-service/-/raw/main/.gitlab-ci.yml
为项目设置流水线状态标志
支持Markdown、HTML、AsciiDoc格式。
==💘 实战:为项目设置流水线状态标志-2023.5.8(测试成功)==
- 实验环境
gitlab/gitlab-ce:15.0.3-ce.0
实验软件(无)
在项目代码的
README.md
文件里添加如下部分代码
[](http://172.29.9.101:8076/devops6/devops-demo-service/-/commits/main)
此部分代码位置:gitlab项目-Settings-CI/CD-Gernral Pipelines-Pipeline Status
- 本次在
main分支
的README.md
文件下添加如上部分代码
- 提交代码后,触发流水线,观察结果
符合预期。😘
设置管道(pipeline)预览权限
可以来到项目
>Project information
>Members
:给这个项目里增加成员
Guest和非项目成员无法,看到管道中作业的日志和管道所生成的制品;
开启公共的管道访问:
- 公共项目,每个人都可以访问。
- 内部项目,对于除外部用户之外的所有登录用户。
- 私人项目,所有项目成员(Guest 或更高级别)。
可以来到项目>Settings>CI/CD>Genernal pipelines
:配置管道权限!
Pipeline核心语法
gitlab-ci语法:
https://docs.gitlab.com/ee/ci/yaml/
stages 阶段控制
- .pre阶段的作业总是在流水线开始时执行;
- .post阶段的作业总是在流水线结束时执行;
CI代码:
stages:
- build
- test
- deploy
job0:
tags:
- go
stage: .pre
script:
- echo " init"
job1:
tags:
- go
stage: build
script:
- echo "build"
job2-1:
tags:
- mvn
stage: test
script:
- echo "test"
- sleep 10
job2-2:
tags:
- mvn
stage: test
script:
- echo "test"
job3:
tags:
- go
stage: deploy
script:
- echo "deploy"
job10:
tags:
- go
stage: .post
script:
- echo "end"
代码直接写在gitlab的CI/CD
的editor里:
- 这里我们先修改下runner上的标签
- 运行
如果两个或者多个作业,指向同一个阶段名称,则该阶段下的所有作业都并行运行;如果不能并行运行,需要检查runner的配置文件中的concurrent
值, 要大于1。
variables 环境变量
变量可以分为全局变量和局部变量;全局变量是整个流水线可以用的,局部变量是仅在作业中生效的;
- CI代码
stages:
- build
variables:
BUILD_TOOLS:
value: "mvn"
description: "choice build tools" #描述信息,注释不能用//,只能用#号。
RUNNER_TAG: "go"
job1:
tags:
- "${RUNNER_TAG}"
stage: build
variables:
BUILD_TOOLS: "gradle"
script:
- echo "${BUILD_TOOLS}"
- 运行
job 作业默认配置
定义一个作业的时候,一般定义哪些关键字呢? 作业在哪个runner运行? 作业属于流水线中的哪个阶段? 这个作业要做什么?
- CI代码
stages:
- build
variables:
RUNNER_TAG: "go"
before_script:
- echo "pipeline before script"
after_script:
- echo "pipeline after script"
job1:
tags:
- ${RUNNER_TAG}
stage: build
before_script:
- echo "before script...."
script:
- echo "mvn package"
after_script:
- echo "after script..."
job2:
tags:
- ${RUNNER_TAG}
stage: build
script:
- echo "build"
参数解析:
语法关键字 | 作用 | 备注 |
---|---|---|
variables | 定义作业中的环境变量; | |
tags | 根据标签选择运行作业的构建节点; | 多个标签, 则匹配具有所有标签的构建节点;GitLab14.1版本后, 标签的值可以使用变量;GitLab14.3版本后, 标签数量必须小于50; |
stage | 指定当前作业所属的阶段名称; | |
before_script | 作业在运行前执行的Shell命令行; | |
script | 作业在运行中执行的Shell命令行; | 每个作业至少要包含一个script; |
after_script | 作业在运行后执行的Shell命令行; |
- 运行
需要注意:如果
before_script和after_script
定义在pipeline里,则每个作业里都会运行这2个脚本;如果是定义在某个job里,则只会在其job里运行!
job 作业运行控制
语法关键字 | 作用 | 备注 |
---|---|---|
allow_failure | 控制作业状态,是否允许作业失败,默认值为false 。启用后,如果作业运行失败,该作业将在用户界面中显示橙色警告。![]() | 管道将认为作业成功/通过,不会被阻塞。 假设所有其他作业均成功,则该作业的阶段及其管道将显示相同的橙色警告。但是,关联的提交将被标记为"通过",而不会发出警告。 |
when | 根据状态控制作业运行, 当前面作业成功或者失败时运行。 | on_success 前面阶段成功时执行(默认值);on_failure 前面阶段失败时执行;always 总是执行;manual 手动执行;delayed 延迟执行;start_in'5'5 seconds30 minutes1 day1 weeknever 永不执行; |
retry | 作业重新运行,遇到错误重新运行的次数。 | 值为整数等于或大于0,但小于或等于2异常分类 (一般就是3次) |
timeout | 作业运行超时时间; | |
rules | 根据特定的变量或文件变更来控制作业运行; | ifchangesexists |
needs | 作业依赖控制; | needs: ["作业名称"] |
parallel | 生成多个作业,并行运行 | parallel:5值 2-50之间 |
parallel 并行运行
- 代码
stages:
- build
variables:
RUNNER_TAG: "go"
job1:
tags:
- ${RUNNER_TAG}
stage: build
parallel: 5
script:
- echo "mvn package"
模拟做压测。
- 运行
needs 作业关联运行
- CI代码
needs 指定要依赖的作业名称
stages:
- build
- test
variables:
RUNNER_TAG: "go"
job1:
tags:
- ${RUNNER_TAG}
stage: build
script:
- echo "mvn package"
- sleep 10
job2:
tags:
- ${RUNNER_TAG}
stage: build
script:
- echo "build"
job3:
tags:
- ${RUNNER_TAG}
stage: test
script:
- echo "mvn package"
job4:
tags:
- ${RUNNER_TAG}
stage: test
needs: ["job2"]
script:
- echo "mvn package"
- 运行
rules根据变量/文件控制
根据条件(变量)判断: IF
用法:
定义变量条件;
运算符:
● =
● !=
● =~
条件链接符:
● &&
● ||
CI代码:
variables:
DOMAIN: example.com
codescan:
stage: build
tags:
- build
rules:
- if: '$DOMAIN == "example.com"'
when: manual
- when: on_success
script:
- echo "codescan"
- sleep 5;
运行:
根据文件判断: changes
exists
changes
文件变更时条件为真;
示例: 代码提交后,当Dockerfile文件发生变更则条件为真。即手动执行此作业。
注意:非Push相关动作,此条件永远为真。
CI代码:
citest1:
tags:
- build
stage: test
rules:
- changes:
- Dockerfile
when: manual
- when: never
script:
- echo "Do a test here"
- echo "For example run a test suite"
运行:
直接运行次作业时,肯定是不会运行流水线的,因此此时是没有Dockerfile
文件的。
我们来创建一个Dockerfile
文件,再次运行流水线,并观察现象:
allow_failure
允许作业在不停止管道的情况下失败;
CI代码:
stages:
- test
citest1:
tags:
- build
stage: test
allow_failure: true
script:
- lsl -l
- echo "Do a test here"
citest2:
tags:
- build
stage: test
script:
- ls -l
- echo "Do a test here"
运行:
variables
重新定义变量的值;
示例: 如果当前的分支是主干分支main, 则重新定义ENV_TYPE
的值为prod
。
注意: 只影响局部作业内的变量,不会影响全局变量。
CI代码:
variables:
ENV_TYPE: "dev"
cddeploy:
tags:
- build
stage: deploy
rules:
- if: $CI_COMMIT_REF_NAME == "main"
variables:
ENV_TYPE: "prod"
script:
- echo "Deploy env ${ENV_TYPE}"
运行:
🍀 某一类文件写法:
when
同when语法的运行方式;
这里的when是写在rules里面的,也可以写在外面的。
rules代码汇总:
stages:
- build
- test
variables:
RUNNER_TAG: "go"
SKIP_BUILD: "true"
job1:
tags:
- ${RUNNER_TAG}
stage: build
rules:
- if: '$SKIP_BUILD == "true"' # 此时job1 不会被运行
when: never
- when: always
before_script:
- echo "before script...."
script:
- echo "mvn package"
after_script:
- echo "after script..."
job2:
tags:
- ${RUNNER_TAG}
stage: test
rules:
- changes:
- README.md # 提交时仅该文件存在变更时才会触发
when: always
- when: never
script:
- echo "test"
job3:
tags:
- ${RUNNER_TAG}
stage: test
rules:
- exists:
- Dockerfile #只要项目中存在该文件就会运行,提交存在也算。
when: manual
- when: never
script:
- echo "test"
job4:
tags:
- ${RUNNER_TAG}
stage: test
script:
- echo "test"
运行:
when 状态控制和运行方式
- 根据上游作业的状态决定
- 当前作业是否运行?
- 运行的方式?(手动/自动/定时)
CI代码:
stages:
- build
- test
- deploy
variables:
RUNNER_TAG: "go"
job1:
tags:
- ${RUNNER_TAG}
stage: build
before_script:
- echo "before script...."
script:
- echo "mvn package"
after_script:
- echo "after script..."
job2:
tags:
- ${RUNNER_TAG}
stage: test
when: on_success
script:
- echo "build"
job3:
tags:
- ${RUNNER_TAG}
stage: test
when: on_failure
script:
- echo "build"
job4:
tags:
- ${RUNNER_TAG}
stage: deploy
when: manual
script:
- echo "build"
运行:
when: delay
test1:
tags:
- ${RUNNER_TAG}
stage: test
script:
- echo "Do a test here"
- echo "For example run a test suite"
- sleep 3
when: delay
start_in: '5'
timeout作业运行超时时间
build:
script: build.sh
timeout: 3 hours 30 minutes
test:
script: rspec
timeout: 3h 30m
retry 作业失败后重试次数
CI代码:
stages:
- build
- test
variables:
RUNNER_TAG: "go"
job1:
tags:
- ${RUNNER_TAG}
stage: build
retry: 2
before_script:
- echo "before script...."
script:
- echo "mvn package"
- mvs
after_script:
- echo "after script..."
job2:
tags:
- ${RUNNER_TAG}
stage: test
script:
- echo "build"
运行:
根据特定的错误匹配:
always :在发生任何故障时重试(默认)。
unknown_failure :当失败原因未知时。
script_failure :脚本失败时重试。
api_failure :API失败重试。
stuck_or_timeout_failure :作业卡住或超时时。
runner_system_failure :构建节点的系统发生故障。
missing_dependency_failure: 依赖丢失。
runner_unsupported :Runner不受支持。
stale_schedule :无法执行延迟的作业。
job_execution_timeout:作业运行超时。
archived_failure :作业已存档且无法运行。
unmet_prerequisites :作业未能完成先决条件任务。
scheduler_failure :调度失败。
data_integrity_failure :结构完整性问题。
####
max :最大重试次数 when :重试失败的错误类型
stages:
- build
- test
variables:
RUNNER_TAG: "go"
job1:
tags:
- ${RUNNER_TAG}
stage: build
retry: 2 # 不管任何错误,都重试2次
before_script:
- echo "before script...."
script:
- echo "mvn package"
- mvs # 命令错误
after_script:
- echo "after script..."
job2:
tags:
- ${RUNNER_TAG}
stage: test
when: on_failure # 为了让这个作业运行所以添加的,不然前面作业失败这个作业就不运行了。
script:
- echo "build"
- aaa # 命令错误
retry:
max: 2
#when: api_failure
when: script_failure # 定义脚本错误: 正常会retry两次
运行:
allow_failure 允许作业失败
CI代码:
stages:
- build
- test
variables:
RUNNER_TAG: "go"
job1:
tags:
- ${RUNNER_TAG}
stage: build
allow_failure: true
retry: 2
before_script:
- echo "before script...."
script:
- echo "mvn package"
- mvs
after_script:
- echo "after script..."
job2:
tags:
- ${RUNNER_TAG}
stage: test
script:
- echo "build"
运行:
Pipeline运行控制
1.workflow 控制流水线
控制管道是否创建和运行。根据条件(变量)判断: IF
if 定义变量条件;
variables 重新定义变量的值;
when
- always
- never
命令 | 备注 |
---|---|
if: '$CI_PIPELINE_SOURCE == "merge_request_event"' | 合并请求时运行流水线; |
if: '$CI_PIPELINE_SOURCE == "push"' | 提交代码运行流水线; |
- 预定义变量
https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
🍀 demo
CI代码:
variables:
SKIP_RUN: "true"
RUNNER_TAG: "go"
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "push"
when: never
stages:
- build
job2:
tags:
- ${RUNNER_TAG}
stage: build
script:
- echo "build"
运行:
运行后,是没看见触发流水线的。
🍀 demo
CI代码:
variables:
SKIP_RUN: "true"
RUNNER_TAG: "go"
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "push"
when: never
- if: $CI_PIPELINE_SOURCE == "web"
when: never
stages:
- build
job2:
tags:
- ${RUNNER_TAG}
stage: build
script:
- echo "build"
运行:
可以看到,这里在web触发时,依然报错了:……
2.Git 选项跳过流水线
- 提交信息中添加关键字
[ci skip]
或者[skip ci]
; - Git 2.10 更高版本,可以通过以下配置设置CI/CD;
## 跳过
git push -o ci.skip
## 传递变量
git push -o ci.variable="MAX_RETRIES=10" -o ci.variable="MAX_TIME=600"
🍀 demo
这里改变下项目里readme文件内容,进行提交,commit message信息里写上[ci skip]
,再次观察是否会触发提交流水线(默认是提交一次就会触发一次流水线的)?
可以看到,这里跳过了流水线的触发。
3.trigger 触发下游管道
- 触发项目管道
- 触发子管道
strategy: 默认情况下,一旦创建了下游管道,trigger作业就会以success状态完成。要强制等待下游管道完成,使用 strategy: depend
。
触发项目管道:(不要自己触发自己,这样就进入到一个环里面了。)
triggers:
stage: deploy
trigger:
project: devops/devops-maven-service
branch: main
strategy: depend ## 状态同步
触发子管道:
stages:
- deploy
trigger-cd-pipeline:
stage: deploy
trigger:
include: ci/stages.yml ## 触发当前项目的子流水线
trigger-project-pipeline:
stage: deploy
trigger:
include:
- project: "devops/devops05-app-service" ## 触发其它项目的子流水线
ref: "main"
file: "ci/stages.yml"
测试过程:
- 创建一个项目
devops6-gitlabci-demo
- 在新项目里创建一个.gitllabci.yml文件:
stages:
- build
before_script:
- echo "Before script section"
- echo "For example you might run an update here or install a build dependency"
- echo "Or perhaps you might print out some debugging details"
after_script:
- echo "After script section"
- echo "For example you might do some cleanup here"
build1:
tags:
- go
stage: build
script:
- sleep 20
- echo "Do your build here"
- 先来测试下 触发项目管道
stages:
- deploy
triggers:
stage: deploy
trigger:
project: devops6/devops6-gitlabci-demo
branch: main
strategy: depend ## 状态同步
提交代码并观察现象:
可以看到,此时成功触发了其他项目。
- 再来测试下 trigger触发当前项目的子流水线
在当前项目devops-demo-service
里创建.ci/ci.yaml
文件:
stages:
- build
- test
build01:
stage: build
tags:
- go
script:
- echo "build"
test01:
stage: test
tags:
- go
script:
- echo "test"
提交后,默认就会触发流水线的运行:
此时,有这个需求:改了目录里面的内容,就不让他构建,该怎么写?
CI代码:
stages:
- deploy
workflow:
rules:
- changes:
- .ci/*
when: never
- when: always
triggers:
stage: deploy
trigger:
project: devops6/devops6-gitlabci-demo
branch: main
strategy: depend ## 状态同步
此时,提交后,我们再次修改.ci/ci.yaml内容
,再次观察是否会触发流水线?
stages:
- build
- test
build01:
stage: build
tags:
- go
script:
- echo "build"
test01:
stage: test
tags:
- go
script:
- echo "test"
test02:
stage: test
tags:
- go
script:
- echo "test"
提交并观察:
可以看到,此时就不会触发流水线了。
我们继续看下trigger如何触发当前项目的子流水线
CI代码:
stages:
- deploy
workflow:
rules:
- changes:
- .ci/*
when: never
- when: always
triggers:
stage: deploy
trigger:
project: devops6/devops6-gitlabci-demo
branch: main
strategy: depend ## 状态同步
triggers2:
stage: deploy
trigger:
include: .ci/ci.yaml
提交:
此时,已经成功触发了当前项目的子流水线。
- 我们再来看看如何触发其他项目的子流水线?
在之前新创建的devops6-gitlabci-demo
项目里创建.ci/ci.yaml
:
stages:
- build
- test
build01:
stage: build
tags:
- go
script:
- echo "build"
test01:
stage: test
tags:
- go
script:
- echo "test"
test02:
stage: test
tags:
- go
script:
- echo "test"
提交。 然后在devops-demo-service
项目的.gitlab-ci.yml
里编写CI代码:
stages:
- deploy
workflow:
rules:
- changes:
- .ci/*
when: never
- when: always
triggers:
stage: deploy
trigger:
project: devops6/devops6-gitlabci-demo
branch: main
strategy: depend ## 状态同步
triggers2:
stage: deploy
trigger:
include: .ci/ci.yaml
trigger-project-pipeline:
stage: deploy
trigger:
include:
- project: "devops6/devops6-gitlabci-demo" ## 项目名称
ref: "main"
file: ".ci/ci.yaml"
提交并观察现象:
符合预期。
4.API触发Pipeline
创建一个认证token:
使用API触发
使用curl命令进行测试:
curl -X POST \
-F token=156d70fce2d6afca6d0b21c6624b85 \
-F ref=main \
http://172.29.9.101:8076/api/v4/projects/2/trigger/pipeline
这里的2是项目id:
触发后,报如下提示:
看是被workflow规则过滤了:
这里再改下CI代码:
提交后,再次在命令行进行触发:
这里还是提示被workflow规则过滤了。
再次修改下CI代码:
stages:
- deploy
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "trigger"
when: always
- changes:
- .ci/*
when: never
- when: always
triggers:
stage: deploy
trigger:
project: devops6/devops6-gitlabci-demo
branch: main
strategy: depend ## 状态同步
triggers2:
stage: deploy
trigger:
include: .ci/ci.yaml
trigger-project-pipeline:
stage: deploy
trigger:
include:
- project: "devops6/devops6-gitlabci-demo" ## 项目名称
ref: "main"
file: ".ci/ci.yaml"
提交后,再次在命令行触发,观察现象:
因此,要特别注意下,这个workflow下的规则匹配。(这里把它写在最上面就可以正常触发了,但是写在changes下面,就不能正常触发的)
使用postman测试
gitlabci作业中触发
script:
- "curl -X POST -F token=TOKEN -F ref=REF_NAME http://172.29.9.101:8076/api/v4/projects/2/trigger/pipeline"
优化: 将token以变量的方式存储到项目中。
stages:
- build
build-job:
tags:
- build
stage: build
script:
- "curl -X POST -F token=${CITOKEN} -F ref=main http://172.29.9.101:8076/api/v4/projects/2/trigger/pipeline"
- echo "Compile complete."
- sleep 1
触发并传递参数
curl -X POST \
-F token=156d70fce2d6afca6d0b21c6624b85 \
-F ref=main \
-F "variables[BUILD_TOOL]=mavenandmaven" \
http://172.29.9.101:8076/api/v4/projects/2/trigger/pipeline
ciTriggerTest:
tags:
- build
stage: build
script:
- echo ${BUILD_TOOL}
PipelineTemplate实践
https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates
extends
extends可以指定多个模板, 相同的参数最后模板会覆盖前面的。例如: 下面两个模板中,继承关系是:
- 继承 .test1 (此时rspec的变量
NAME
的值为gitlab) - 继承 .test2 (此时rspec的变量
NAME
的值为gitlabCI , 覆盖了.test1中的值)
.test1:
variables:
NAME: "gitlab"
tags:
- build
stage: test
rules:
- if: $CI_COMMIT_BRANCH == "main"
script: echo "mvn test"
.test2:
variables:
NAME: "gitlabCI"
tags:
- build01
stage: test
rspec:
extends:
- .test1
- .test2
script: echo " DevOps"
###### 结果
rspec:
variables:
NAME: "gitlabCI"
tags:
- build01
stage: test
rules:
- if: $CI_COMMIT_BRANCH == "main"
script: echo " DevOps"
include
include用于在CI/CD 配置中引入外部 YAML 文件。可以将一个长.gitlab-ci.yml
文件分解为多个文件以提高可读性,或减少同一配置在多个地方的重复。
- local 导入当前仓库中的文件;
- file 导入当前项目或其他项目库中的文件;
- remote 导入一个远程的文件(例如:http://xxx.yaml)
- template 导入GitLab官方提供的模板文件;
## 本地仓库文件
include:
- local: '/templates/.gitlab-ci-java.yml'
## 其他仓库文件
include:
- project: 'devops/my-project'
ref: main
file:
- '/templates/.gitlab-ci-java.yml'
- '/templates/.tests.yml'
## 远程文件
include:
- remote: 'https://192.168.1.200//-/raw/main/.gitlab-ci.yml'
🍀 测试
Extend:继承模板
Include:引入模板
- 创建新项目
gitlab-temp-repo
- 定义2个模板
创建CI/java-ci.yaml
文件:
.test1:
variables:
NAME: "gitlab"
tags:
- build
stage: test
rules:
- if: $CI_COMMIT_BRANCH == "main"
script: echo "mvn test"
.test2:
variables:
NAME: "gitlabCI"
tags:
- build02
stage: test
script: echo "mvn test"
- 在
devops-demo-service
项目编辑CI文件
include:
- project: 'devops6/gitlab-temp-repo'
ref: main
file:
- '/CI/java-ci.yaml'
test1:
extends:
- .test1
test2:
tags:
- build
extends:
- .test2
- 运行
能够做成每个项目一个template就很不错了。
综合实例:
将模板文件,放到单独的一个仓库中;
ci.yml
.build:
tags:
- build
stage: build
variables:
BUILD_TOOL: "maven3"
BUILD_SHELL: "mvn clean package"
script:
- "${BUILD_SHELL}"
.test:
tags:
- "linux"
stage: test
variables:
TEST_SHELL: "mvn test"
script:
- "${TEST_SHELL}"
.gitlab-ci.yml
workflow:
rules:
- if: $CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000" # 40个零 创建分支或者tag
when: never
include:
- project: 'devops/devops-ci-lib' ## 引入ci.yml模板
ref: main
file: '/CI/ci.yml'
variables:
GIT_CHECKOUT: "false"
RUNNER_TAG: "mvn"
BUILD_SHELL: "mvn clean package -DskipTests"
TEST_SHELL: "mvn test"
stages:
- build
- test
# 下载代码
checkout:
tags:
- ${RUNNER_TAG}
stage: .pre
variables:
GIT_CHECKOUT: "true"
script:
- echo "GetCode..."
# maven构建
build:
tags:
- ${RUNNER_TAG}
extends: .build ##重用build作业
# maven test
test:
tags:
- ${RUNNER_TAG}
extends: .test
💘 实践:练习Pipeline模板库(测试成功)-2022.5.6(这个有点难度)
🍀 老师文档
- 创建一个新的项目 “devops4/devops4-devops-service” (模板库);
- 为项目添加一个CI模板文件(ci/ci.yml);(参考pipeline.yml)
- 添加cicd.yml 文件, pipeline, include导入模板库中的ci/ci.yml
ci/ci.yml: ‘devops4/devops4-devops-service 模板库
.build:
variables:
SHELL: "mvn clean build"
tags:
- build
stage: build
script: echo "${SHELL}"
cicd.yml
### 导入仓库文件
include:
- project: 'devops4/devops4-devops-service'
ref: main
file:
- '/ci/ci.yml'
variables:
BUILD_SHELL: "mvn build"
stages:
- build
### 继承模板
build:
extends:
- .build
variables:
SHELL: $BUILD_SHELL
远程CI文件配置:
http://192.168.1.200/devops4/devops4-devops-service/-/raw/main/cicd.yml
🍀 自己测试过程:
- 创建模板库
devops4-devops-service
创建如下相关文件:
ci/ci.yml
.build:
variables:
SHELL: "mvn clean build"
tags:
- build
stage: build
script: echo "${SHELL}"
cicd.yml
### 导入仓库文件
include:
- project: 'devops4/devops4-devops-service'
ref: main
file:
- '/ci/ci.yml'
variables:
BUILD_SHELL: "mvn build"
stages:
- build
### 继承模板
build:
extends:
- .build
variables:
SHELL: $BUILD_SHELL
写完后提交。
获取cicd.yml
文件的路径:
http://172.29.9.101/devops4/devops4-devops-service/-/raw/main/cicd.yml
- 来到另一个项目里
devops4-monrepo-service
在项目>Settings
>CI/CD
>Gerneral pipelines
里把刚才拷贝的那个链接填在这里,保存:
- 然后,直接运行这个流水线,观察效果:
符合预期,实验结束。
提交阶段流水线
因为GitLabCI与GitLab版本控制系统深度集成,所以不需要配置触发器。
- 默认已经支持了提交代码、合并代码触发流水线的运行;
- 默认流水线运行后会自动的下载本项目代码;(每个job会下载项目代码)
流水线优化
1.过滤新建分支和tag的触发
workflow:
rules:
- if: $CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000"
when: never
🍀 测试过程如下:
- 先来测试下,gitlabci里新建分支是否会触发流水线的运行?
本次在devops4-commit-service
项目里测试:
新创建分支feature-dev-03
:
可以看到,新建分支操作是会触发流水线运行的:
- 编写pipeline代码,通过
CI_COMMIT_BEFORE_SHA
来过滤新建分支和tag的触发:
编写之前可以来看下gitlabci官网预定义的一些变量:
workflow:
rules:
- if: $CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000"
when: never
- when: always
stages:
- build
- test
- deploy
before_script:
- echo "Before script section"
- echo "For example you might run an update here or install a build dependency"
- echo "Or perhaps you might print out some debugging details"
after_script:
- echo "After script section"
- echo "For example you might do some cleanup here"
build:
stage: build
script:
- echo "Do your build here"
test:
stage: test
script:
- echo "Do another parallel test here"
- echo "For example run a lint test"
build-job:
stage: build
script:
- "curl -X POST -F token=${CITOKEN} -F ref=main http://172.29.9.101/api/v4/projects/2/trigger/pipeline"
- echo "Compile complete."
- sleep 1
deploy:
stage: deploy
script:
- echo "Do your deploy here"
- 验证
此时,再新建一个分支,看是否会触发流水线的运行
可以发现,此时新建分支不会触发流水线的运行了,符合预期:
2.解决job运行重新下载代码
制品需要通过分布式缓存或者通过语法提前保存。
指的是,不同的runner节点。
通过下面的CI作业,观察第二个作业是否可以拿到第一个作业的文件;
variables:
ENV_TYPE: "dev"
cibuild:
tags:
- build
stage: build
script:
- ls -l
- echo 123 >test.yaml
- ls -l
citest1:
tags:
- build
stage: test
script:
- ls -l
分析: citest1
作业并没有获取上个阶段产出文件, 因为默认每个作业运行时都会重新下载代码;重新下载代码会把其他文件删除掉;
如何解决?
- 禁止后面的作业重复的下载代码;
- 使用artifact关键字, 收集制品传递给其他作业;
因为作业可能被分配到不同的runner上运行的。
这里测试如下:
方法1:GIT_CHECKOUT
GIT_CHECKOUT
变量,默认值为true
,即作业每次运行都下载代码。按照我们目前的需求,需要禁止下载代码:
我们将此变量的值在全局配置为false
,然后在第一个作业(.pre)中配置为true
。也就实现了只在第一个作业下载代码而不会出现其他作业下载代码了。
GIT_CHECKOUT: "false"
优化一下pipeline, 仅在pipelineInit
作业中运行代码下载,其他作业跳过;
variables:
ENV_TYPE: "dev"
GIT_CHECKOUT: "false"
pipelineInit:
tags:
- build
stage: .pre
variables:
GIT_CHECKOUT: "true"
script:
- ls -l
cibuild:
tags:
- build
stage: build
script:
- ls -l
- echo 123 >test.yaml
- ls -l
citest1:
tags:
- build
stage: test
script:
- ls -l
查看citest1
作业中的输出, 发现工作目录中已经存在之前作业的产出文件;
🍀 自己测试存在的问题
老师,我在"gitlab ci-cd语法"这一节里,做“解决job运行重新下载代码”实验时,利用“GIT_CHECKOUT”方式测试后,.pre阶段能看到下载的代码,但是后面2个阶段没看到下载下来的代码,帮看看下,多谢@ZeYang
我这个问题好奇怪哦,老师的实验现象及文档上的都没问题……;
自己重启了gitlab还是不行……;
自己重新注册下gitlab-ci runner再看下:……还是不行。。。;
最后发现了问题:。。。
默认这里是git fetch
,git shallow clobe
值为20。
但是在运行流水线时,报错:
经过百度,说是要在项目-设置-ci/cd-General pipelines里设置为git clone
才行。
设置后,再次运行流水线:
此时,发现是ok的。
但是,在测试利用GIT_CHECKOUT
下载代码时,就出现了问题,和老师的现象不一样
排查了好多问题,都解决不了……
报错如下:(在此步骤的上面)
最后,自己将项目-设置-ci/cd-General pipelines里设置为git fetch
,然后把下面的git shadow clone
设置为0后,再次运行流水线,就符合预期效果了。
CI代码:
variables:
ENV_TYPE: "dev"
GIT_CHECKOUT: "false"
pipelineInit:
tags:
- build
stage: .pre
variables:
GIT_CHECKOUT: "true"
script:
- ls -l
cibuild:
tags:
- build
stage: build
script:
- ls -l
- echo 123 >test.yaml
- ls -l
citest1:
tags:
- build
stage: test
script:
- ls -l
很奇怪,这是为什么呢??
⚠️ 汇总:
这个问题原因找到了。
之前项目里默认配置的是git fetch
,Git shallow clone=20
,但是后续跑流水线时报错,百度了下,就改成git clone
。
但是后面在做GIT_CHECKOUT
解决job运行重新下载代码时,测试现象和课程上的不一样。
最后改成了git fetch
,Git shallow clone=0
,现象就一致了。
方法2:Artifacts
在作业结束时,收集作业中的文件或目录并以附件的形式保存在关联的作业中。作业运行完成后,制品将被存储到GitLab,并且可以在GitLab UI中下载。
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
when: on_success
expire_in: '1 week'
paths:
- target/*.jar
- name : 定义所创建的制品存档的名称;
- when :定义何时进行制品收集;
- expire_in : 制品的过期时间,过期自动清理;
- paths: 定义要收集的制品文件或者目录信息;
dependencies:
- build ## 作业名称
dependencies:
要获取哪些作业制品, 作业列表;只能是当前阶段之前的作业。如果空数组则跳过下载任何工件;不考虑先前作业的状态,因此,如果它失败或是未运行的手动作业,则不会发生错误。
基于artifacts和dependencies调整pipeline:
variables:
ENV_TYPE: "dev"
#GIT_CHECKOUT: "false"
pipelineInit:
tags:
- build
stage: .pre
#variables:
#GIT_CHECKOUT: "true"
script:
- ls -l
cibuild:
tags:
- build
stage: build
script:
- ls -l
- echo 123 >test.yaml
- ls -l
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
when: on_success
expire_in: '1 week'
paths:
- test.yaml
citest1:
tags:
- build
stage: test
dependencies:
- cibuild
script:
- ls -l
查看结果:citest1
作业会下载cibuild
作业生成的制品;
以上问题已解决。
gitlab配置邮件通知反馈
- 编辑/etc/gitlab/gitlab.rb文件开启gitlab email。这里以QQ邮箱为例
### GitLab email server settings
###! Docs: https://docs.gitlab.com/omnibus/settings/smtp.html
###! **Use smtp instead of sendmail/postfix.**
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "2560350642@qq.com"
gitlab_rails['smtp_password'] = "exnyvccnekcccjdgwecga"
gitlab_rails['smtp_domain'] = "smtp.qq.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
### Email Settings
gitlab_rails['gitlab_email_enabled'] = true
gitlab_rails['gitlab_email_from'] = '2560350642@qq.com'
gitlab_rails['gitlab_email_display_name'] = 'GitLab Admin'
- 重新配置
gitlab-ctl stop ;
gitlab-ctl reconfigure ;
gitlab-ctl start gitlab-ctl status
- 登录gitlab-rails控制台,发送测试邮件:
su - git
gitlab-rails console
irb(main):002:0> Notify.test_email('2560350642@qq.com', 'test email', 'gitlab email test').deliver_now
Notify#test_email: processed outbound mail in 0.5ms
Delivered mail 5eba1b04de4e5_12903fe2ca0c79b0519ec@gitlab-995f97976-2nmb4.mail (1055.9ms)
Date: Tue, 12 May 2020 03:41:56 +0000
From: GitLab Admin <2560350642@qq.com>
Reply-To: GitLab Admin <noreply@192.168.1.200>
To: 2560350642@qq.com
Message-ID: <5eba1b04de4e5_12903fe2ca0c79b0519ec@gitlab-995f97976-2nmb4.mail>
Subject: Message Subject
Mime-Version: 1.0
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: 7bit
Auto-Submitted: auto-generated
X-Auto-Response-Suppress: All
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><p>Message Body And Linuxea.com</p></body></html>
=> #<Mail::Message:70243016426420, Multipart: false, Headers: <Date: Tue, 12 May 2020 03:41:56 +0000>, <From: GitLab Admin <2560350642@qq.com>>, <Reply-To: GitLab Admin <noreply@192.168.1.200>>, <To: 2560350642@qq.com>, <Message-ID: <5eba1b04de4e5_12903fe2ca0c79b0519ec@gitlab-995f97976-2nmb4.mail>>, <Subject: Message Subject>, <Mime-Version: 1.0>, <Content-Type: text/html; charset=UTF-8>, <Content-Transfer-Encoding: 7bit>, <Auto-Submitted: auto-generated>, <X-Auto-Response-Suppress: All>>
- 测试邮件:
- 配置gitlab流水线状态通知
FAQ
TS:gitlab-ci运行作业报错fatal: git fetch-pack: expected shallow list,fatal: The remote end hung up unexpectedly
-2023.5.10(已解决)
1、故障现象
自己在使用gitlab-ci跑job时,之前都没错的,但是后面报错了……
fatal: git fetch-pack: expected shallow list
fatal: The remote end hung up unexpectedly
2、解决办法
解决方法,修改gitlab的cicd配置,如下图所示:
这里设置为git clone
后,保存配置。
- 测试
此时,就可以正常运行作业了。
参考链接
http://blog.sway.com.cn/?p=878
1
Gitlab全局或者项目里设置变量Variables
Variables
:变量,比如说,这里可以存放一些密码,可以选择加密或不加密!
1、全局设置变量
2、项目里设置变量
gitlab是具有制品库功能的
Maximum artifacts size
gitlab是一体化的,不但有ci/cd功能,还具有制品库功能,制品仓库;
注意:gitlab的构建id这个是系统级别的,不一定按顺序来
方法:如何关闭自动ci/cd
1.全局层面设置: 全局->Settings->CI/CD->Continuous Intergration Deployment
:
2.项目层面设置: 项目->Settings->CI/CD->Auto Devops
:
GitLab & Jenkins
可以轻松集成,不像jenkins那么复杂。
集成和代码是绑定一起的,可能对开发平台比较友好。
如果企业里有专门的人来运维jenkins,那么还是建议用jenkins。
如果祖业的数量比较高的话,那么它的维护成本还是比较高的。
例如jenkins更新。
gitlab ci/cd也是gitlab里核心的一个功能!
gitlab ci/cd比jebjnins稍微简单点,不用写很多复杂的脚本
但是想要实现一些更为复杂的功能时,那也避免不了写脚本(写shell脚本)
同一个阶段,默认就是并行运行的
测试demo如下:
CI代码:
citest1:
tags:
- build
stage: test
script:
- echo "Do a test here"
citest2:
tags:
- build
stage: test
script:
- echo "Do a test here"
citest3:
tags:
- build
stage: test
script:
- echo "Do a test here"
运行:
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
🍀 微信二维码 x2675263825 (舍得), qq:2675263825。
🍀 微信公众号 《云原生架构师实战》
🍀 语雀
https://www.yuque.com/xyy-onlyone
🍀 csdn https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421
🍀 知乎 https://www.zhihu.com/people/foryouone
最后
好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!