GitLab版本控制系统实践

image-20220513150137673

目录

本节实践

  1. 实践:GitLab开发工作流(测试成功)-2022.5.11
  2. 实践:基于Jenkins提交流水线(测试成功)-2022.5.13
  3. 实践:基于GitLabCI提交流水线(测试成功)-2022.5.13

实验环境

jenkins/jenkins:2.332.2-centos7-jdk8
gitlab-ce:14.9.3-ce.0

实验软件

链接:https://pan.baidu.com/s/1l_MVaXhySraIAY3JOlDBWg?pwd=7dmf
提取码:7dmf
2022.5.14-GitLab版本控制系统实践-code

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kzopKeVs-1652495034018)(C:/Users/hg/AppData/Roaming/Typora/typora-user-images/image-20220514102048805.png)]

1、GitLab开发工作流

💘 实践:GitLab开发工作流(测试成功)-2022.5.11
image-20220514085640047

1.创建项目组

配置group名称最好与项目组有关的,例如业务的简称等等。项目组的类型分为 Private、Internal、Public三种类型。

  • Private 私有类型(当group为私有类型,后面组下面的项目都是私有类型)
  • Public 公开类型

本次创建一个名为devops4的项目组,private类型:

image-20220511225256991

2.创建项目

在这个页面可以创建一个空的项目、根据一个模板创建项目、导入一个已存在的项目(Gitlab、GitHub等系统)。

本次创建一个 devops4-commit-service 空的项目,私有类型:

image-20220511224646369

image-20220511224822351

image-20220511225045892

3.将代码导入项目

  • 在执行git 客户端命令之前,可以先设置当前的用户信息,名称和邮箱。(可选、规范化)
git config --global user.name "hg"
git config --global user.email "2675263825@qq.com"
  • 下载代码库,并在代码库中创建文件提交。
### 下载项目
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop
$ git clone http://172.29.9.101/devops4/devops4-commit-service.git
Cloning into 'devops4-commit-service'...
Username for 'http://172.29.9.101': root
remote: Enumerating objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3
Unpacking objects: 100% (3/3), done.


### 查看项目
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop
$ ls devops4-commit-service/
README.md

### 进入项目中
#### 创建文件
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop
$ cd devops4-commit-service/

hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (main)
$ vim Jenkinsfile
pipeline {
    agent any

    stages {
        stage('Hello') {
            steps {
                script {
                    echo "hello"
                }
            }
        }
    }
}


### 提交文件到远程仓库
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (main)
$ git add .
warning: LF will be replaced by CRLF in Jenkinsfile.
The file will have its original line endings in your working directory.

hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (main)
$ git commit -m"add Jenkinsfile"
[main 9b86acb] add Jenkinsfile
 1 file changed, 13 insertions(+)
 create mode 100644 Jenkinsfile
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (main)
$ git push origin main
Username for 'http://172.29.9.101': root
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 359 bytes | 359.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To http://172.29.9.101/devops4/devops4-commit-service.git
   de4395c..9b86acb  main -> main

扩展:将本地已存在的代码提交到远程仓库

cd existing_folder
git init
git remote add origin http://172.29.9.101/devops4/devops4-commit-service.git
git add .
git commit -m "Initial commit"
git push -u origin main
  • 代码提交后的效果:发现 Jenkinsfile 文件已经从本地同步到了远程的gitlab仓库中了。

image-20220511230202603

4.拉取特性分支

为什么要拉取分支? 一个分支不够吗? 一般我们使用 master 主干分支存放最新的能够发布生产的代码,而单独创建一些特性分支来做项目需求任务的开发分支。 这样的好处是防止主干分支污染,对分支起到了保护的作用。

  • 下面进入 demo-hello-service 项目主页,然后基于主干分支master,创建特性分支feature-1-DEV。操作如下:

image-20220511230402826

image-20220511230426223

image-20220511230439657

5.特性分支开发与提交

  • 查看当前本地分支,发现没有刚刚远程创建的 feature-dev-01 分支。
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (main)
$ git branch -av
* main                9b86acb add Jenkinsfile
  remotes/origin/HEAD -> origin/main
  remotes/origin/main 9b86acb add Jenkinsfile
  • git pull 同步远程仓库所做的更新到本地, 这样远程的feature-dev-01 分支就同步到了本地。然后我们使用 git checkout feature-dev-01 切换到特性分支。
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (main)
$ git pull
Username for 'http://172.29.9.101': root
From http://172.29.9.101/devops4/devops4-commit-service
 * [new branch]      feature-dev-01 -> origin/feature-dev-01
Already up to date.

hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (main)
$ git checkout feature-dev-01
Switched to a new branch 'feature-dev-01'
Branch 'feature-dev-01' set up to track remote branch 'feature-dev-01' from 'origin'.
  • 我们更改了Jenkinsfile文件内容,然后将更改内容提交到远程仓库。
### 更改文件内容
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (feature-dev-01)
$ pwd
/c/Users/hg/Desktop/devops4-commit-service

hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (feature-dev-01)
$ vim Jenkinsfile
pipeline {
    agent any

    stages {
        stage('Hello') {
            steps {
                script {
                    echo "hello"
                    echo "hello xyy"
                }
            }
        }
    }
}


### 提交到远程仓库分支
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (feature-dev-01)
$ git add .
warning: LF will be replaced by CRLF in Jenkinsfile.
The file will have its original line endings in your working directory.

hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (feature-dev-01)
$ git commit -m"add xyy"
[feature-dev-01 e7cc53c] add xyy
 1 file changed, 1 insertion(+)
hg@LAPTOP-G8TUFE0T MINGW64 ~/Desktop/devops4-commit-service (feature-dev-01)

$ git push origin feature-dev-01
Username for 'http://172.29.9.101': root
Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 304 bytes | 304.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote:
remote: To create a merge request for feature-dev-01, visit:
remote:   http://172.29.9.101/devops4/devops4-commit-service/-/merge_requests/new?merge_request%5Bsource_branch%5D=feature-dev-01
remote:
To http://172.29.9.101/devops4/devops4-commit-service.git
   9b86acb..e7cc53c  feature-dev-01 -> feature-dev-01

这样我们就把本地的特性分支开发的代码提交到了远程特性分支中了, 接下来对应该对该特性分支进行测试验证,没问题后合并到主干分支。

image-20220511231227121

6.特性分支合并操作

  • 将特性分支 feature-dev-01 代码合并到主干分支main Merge Request。

image-20220511231342885

  • 在这个页面,选择源分支和目标分支。

image-20220511231423358

在这个页面:

  • 1 指定合并请求的标题
  • 2 描述信息,一般都是变更信息
  • 3 指定主管进行审核(最终该用户决定是否合并)
  • 4 指定进行代码审查的同事
  • 5 合并成功后删除源分支(最后很定要删除源分支,可以先保留一个版本后再删除,此处最好取消勾选)

image-20220511231518870

image-20220511231550256

  • 提交合并后,由管理员审查进行合并。

image-20220511231635684

image-20220511231715823

合并后的效果: 特性分支的更改已经同步到了主干分支。

image-20220511231755907

到此一个基本的项目开发提交代码过程就已经完成了。(多熟悉一下这个过程)

测试结束。😘

2、Jenkins提交流水线

目的:掌握通过触发器将GitLab和Jenkins集成,实现提交流水线。

💘 实践:基于Jenkins提交流水线(测试成功)-2022.5.13

image-20220514100956964

image-20220514101037706

1.触发器配置

image-20220512070753368

1、Jenkins开启trigger

目的: 开启trigger后,就可以实现其他系统通过一个指定的URL进行自动触发构建了;

  • 新建一个文件夹存放对应GitLab仓库组中的流水线。这里建议用仓库组的名称作为文件夹的名称devops4;

用Gitlab项目名称与流水线命名; devops4-commit-service项目;

image-20220511232011281

(GitLab截图)

image-20220511232302210

(Jenkins流水线截图)

  • 开启Generic webhook;

image-20220511232354692

  • 配置触发Token,例如:作业名称devops4-commit-service (这个token是流水线触发需要传递的);

image-20220511232431240

  • 生成的触发URL;

img

http://172.29.9.101:8080/generic-webhook-trigger/invoke?token=devops4-commit-service

(此时,已经生成了触发URL,接着可以使用Curl或者Postman进行触发测试了!)

2、配置GitLab WebHook

1️⃣ 进入GitLab项目设置, 进入 webhook配置页面;

  • 配置要触发的URL,即Jenkins触发器接口URL;
  • 选择发生哪种GitLab事件后触发此Webhook;例如:Push提交代码、Tag创建标签等等;

image-20220512071310412

image-20220512071338122

事件:

  • Push 提交事件
  • Tag Push 创建事件
  • MergeRequest 合并事件
  • Issue 问题创建更新事件

2️⃣ 保存后但此时会报如下错误:

报错现象:如果出现此FAQ:Url is blocked: Requests to the local network are not allowed

image-20220512071510462

解决方法:进入Admina Area->Settings-> network->Outbound requests

image-20220512071847032

勾选允许请求webhooks和服务:(更改后,重新添加webhook即可)

image-20220512071935388

修改完成后,再次添加webhook操作:

此时可以发现,添加webhook操作成功了:

image-20220512072036777

3️⃣ 测试模拟触发

模拟事件触发,点击test按钮选择push事件,此时去看下Jenkins是否成功被触发。

image-20220512072841304

触发成功则提示: Hook executed successfully: HTTP 200, 此时可以看下Jenkins是否已经触发了一次构建;

image-20220512073152597

image-20220512073505950

这里可以看到jenkins已经触发了一个构建,符合预期。

3、Webhook问题排查调试
  • 进入webhook添加页面的最下方,点击你所创建的webhook的 Edit按钮 ;

image-20220512073613952

  • webhook历史记录: 此记录可以判断,当前动作提交是否产生了webhook。

image-20220512073630843

🍀 点击 View details 可以看到此webhook发送给对端Jenkins的数据信息,和请求状态。

  • 200: 表示触发Jenkins请求成功;
  • Resend Request: 重新发送请求;(此处便于排查调试错误)
  • RequestBody: GitLab传递给Jenkins的数据信息;

image-20220512073739619

  • 假如请求由于xxx原因导致没有触发jenkins构建, 可以在这里点击 Resend Request 按钮进行重新发送请求,而不是再次提交代码。

image-20220512073824032

  • 如果Jenkins触发成功了之后,我们可以在Jenkins的构建日志中查看效果。 这些数据就是gitlab post传递过来的。

image-20220512073904235

到此:你基本上已经知道了Gitlab如何触发Jenkins的了。(多看几遍,多练习几遍)

2.提交流水线优化

1.过滤新建分支和tag的触发

你可能发现问题了,新建一个分支或者标签也会出现构建,这个构建是没有意义的。我们需要排除掉。没错,jenkins 的 Generic webHook 也是支持的。

参考官方的说明:https://github.com/jenkinsci/generic-webhook-trigger-plugin/blob/master/src/test/resources/org/jenkinsci/plugins/gwt/bdd/gitlab/gitlab-push-ignore-create-remove-branch.feature

img

👉🏼 也是可以针对用户进行过滤的!

  • 我们先来测试下,创建新分支是否会触发jenkins构建:

在gitlab新创建一个feature-dev-02

image-20220512155130460

在jebnkins上观察效果:

image-20220512155200889

可以看到,在gitlab新建分支是会触发jenkins进行构建的。

同时可以看到,这里的before值是40个0:

image-20220512155418759

image-20220512155454208

  • 此时就需要我们进行优化了:

添加三个变量,获取当前的提交信息 $object_kind $before $after

此步骤一定要注意下参数名和值后面的空格,要去掉

img

  • 通过正则表达式配置触发条件:Expression ^push\s(?!0{40}).{40}\s(?!0{40}).{40}$ Text $object_kind $before $after。 push请求只有after和before的值都不是40个0的时候触发构建(为40个0的情况是删除分支或者新建分支)

img

  • 以上配置完成后,在gitlab上重新提交,并在jenkins观察效果:

image-20220512155848932

符合预期,jenkins并没有再次构建。

2.如何支持多个分支触发构建?
  • gitlab上设置,只允许feature开头的分支才可以进行触发:

image-20220512161043337

编辑gitlab上的webhook配置:

image-20220512161217000

  • main分支模拟提交代码,观察效果:

image-20220512161351176

可以看到main分支提交代码未触发webhook,当然jenkins更不会被构建了。

  • frature-dev-01分支模拟提交代码,观察效果:

image-20220512161557830

image-20220512161615814

可以看到,jnekins流水线被触发了。

  • 创建多个gitlab webhook, 设置不同的分支,最终指向同一个jenkins 作业;

img

符合预期效果,测试结束。😘

3.其他集成

1.代码下载部分

1️⃣ 生成下载代码

找一个pipeline 类型的项目进入流水线语法, 找到片段生成器中的 checkout 。 我们使用checkout方法来进行代码下载(svn也是支持的哦)

image-20220512075932432

我们的代码库是私有类型的,需要一个具有clone 代码权限的用户账号来下载代码。(测试场景你可以将gitlab admin用户的账号存储在Jenkins的凭据中用于后期代码下载, 线上环境最好创建一个单独的reporter角色的用户进行代码下载,机器人账号。)

img

image-20220512080128631

然后我们来生成代码片段吧,

  • 1 填写项目仓库地址
  • 2 指定访问项目仓库的账号
  • 3 指定要下载的代码库分支
  • 4 点击生成代码

image-20220512080208346

image-20220512080239669

2️⃣ 编写pipeline测试代码:

一个基本的下载代码的demo示例:

checkout([$class: 'GitSCM', branches: [[name: 'main']], extensions: [], userRemoteConfigs: [[credentialsId: '54df701e-d369-4f69-85c6-7209d45c283b', url: 'http://172.29.9.101/devops4/devops4-commit-service.git']]])

本次完整代码如下:

pipeline {
    agent any

    stages {
        stage('CheckOut') {
            steps {
                script {//这里的代码是稍微经过整理的
                    checkout([$class: 'GitSCM', 
                        branches: [[name: 'main']], 
                        extensions: [], 
                        userRemoteConfigs: [[credentialsId: '54df701e-d369-4f69-85c6-7209d45c283b', 
                                                    url: 'http://172.29.9.101/devops4/devops4-commit-service.git']]])
                }
            }
        }
    }
}

image-20220512083652670

3️⃣ 运行流水线测试:

在任意一个pipeline jenkins作业里都可以:

本次就在devops4-commit-service项目即可,点击立即构建:

image-20220512083740541

可以发现能够成功拉取gitlab仓库里的代码。

👉🏼 这边可以看到拉取的代码存档的位置如下:

image-20220512083848736

image-20220512083305038

[root@devops ~]#docker exec jenkins ls /var/jenkins_home/workspace/devops4-commit-service

image-20220512083956008

🍀 现在有个问题:pipeline里的代码写死了,很不方便!

image-20220512084110061

一个动态传递分支参数的示例:

开始测试:

  • 在pipeline流水线的构建触发器位置把post content功能打开

image-20220512141742590

  • 再来到gitlab上进行提交测试

image-20220512141958887

  • 此时再到jebnkins上观察构建结果

可以看到,构建成功,且gitlab请求的post内容也出现了:

image-20220512142107610

  • 将这段post内容赋值到json.cn网站进行查看:

image-20220512142329886

  • 此时我们再来编辑下jenkins项目,想法把这些数据拿到手:

image-20220512142627695

编写pipeline代码:

image-20220512143114281

println("${webhookData}")
pipeline {
    agent any

    stages {
        stage('CheckOut') {
            steps {
                script {
                    checkout([$class: 'GitSCM', 
                        branches: [[name: 'main']], 
                        extensions: [], 
                        userRemoteConfigs: [[credentialsId: '54df701e-d369-4f69-85c6-7209d45c283b', 
                                                    url: 'http://172.29.9.101/devops4/devops4-commit-service.git']]])
                }
            }
        }
    }
}
  • 此时在gitlab重新发起post请求:

image-20220512142851225

  • 在jenkines上观察效果:

发现目前已经可以拿到post的全部数据了:

image-20220512143226523

image-20220512143028168

  • 接下来就是进行数据过滤了:

编写pipeline代码:

image-20220512145200961

println("${webhookData}")

webhookData = readJSON text: "${webhookData}"

env.srcUrl = webhookData.project.git_http_url
env.branchName = webhookData.ref - "refs/heads/"
env.commitId = webhookData.checkout_sha

currentBuild.description = """
srcUrl: ${env.srcUrl} \n
branchName: ${env.branchName} \n
"""
currentBuild.displayName = "${env.commitId}"

pipeline {
    agent any

    stages {
        stage('CheckOut') {
            steps {
                script {
                    checkout([$class: 'GitSCM', 
                        branches: [[name: "${env.branchName}"]], 
                        extensions: [], 
                        userRemoteConfigs: [[credentialsId: '54df701e-d369-4f69-85c6-7209d45c283b', 
                                                    url: "${env.srcUrl}"]]])
                }
            }
        }
    }
}

将写好的代码保存到pipeline里。

  • 验证:

在gitlab上重新触发,并在jenkins进行验证:

image-20220512145052362

image-20220512145116238

  • 此时,想要commitId的前8位该如何取呢?

这样处理就好:

image-20220512150607184

println("${webhookData}")

webhookData = readJSON text: "${webhookData}"

env.srcUrl = webhookData.project.git_http_url
env.branchName = webhookData.ref - "refs/heads/"
env.commitId = webhookData.checkout_sha[0..7]

currentBuild.description = """
srcUrl: ${env.srcUrl} \n
branchName: ${env.branchName} \n
"""
currentBuild.displayName = "${env.commitId}"

pipeline {
    agent any

    stages {
        stage('CheckOut') {
            steps {
                script {
                    checkout([$class: 'GitSCM', 
                        branches: [[name: "${env.branchName}"]], 
                        extensions: [], 
                        userRemoteConfigs: [[credentialsId: '54df701e-d369-4f69-85c6-7209d45c283b', 
                                                    url: "${env.srcUrl}"]]])
                }
            }
        }
    }
}

重新构建并测试:

image-20220512150717147

如何预期效果。

测试结束。😘完美

2.解析WebhookData
  • Jenkins接收GitLab传递数据;(配置Jenkins Generic Webhook)

添加一个Post参数, 接收GitLab传递的数据;也就是说将GitLab传递的所有数据都保存在了这个变量中;后期我们在流水线中解析这个变量(JSON数据)。

img

  • 流水线中解析GitLab数据;(JSON格式化)

使用readJSON解析格式化JSON数据,获取仓库信息;(如果你不清楚为什么这样获取branchName等信息,可以返回上面看下GitLab传递的数据,使用JSONPath语法获取数据);

//gitlab传递的数据{}
println("${WebhookData}")

//数据格式化
webHookData = readJSON text: "${WebhookData}"

//提取仓库信息
env.srcUrl = webHookData["project"]["git_http_url"]   //项目地址
env.branchName = webHookData["ref"] - "refs/heads/"  // 分支
env.commitId = webHookData["checkout_sha"]          //提交id
env.commitUser = webHookData["user_username"]       // 提交人
env.userEmail = webHookData["user_email"]           // 邮箱


## 这里为什么要使用env.定义变量呢? 因为全局变量保险些,便于后面所有阶段间的引用;
  • 个性化显示构建信息;

将代码的提交ID作为构建ID, 填写项目构建相关的Git信息;

img

currentBuild.description = "Trigger by Gitlab \n branch: ${env.branchName} \n user: ${env.commitUser} "
currentBuild.displayName = "${env.commitId}"

(完整的Jenkinsfile)

//gitlab传递的数据{}
println("${WebhookData}")

//数据格式化
webHookData = readJSON text: "${WebhookData}"

//提取仓库信息
env.srcUrl = webHookData["project"]["git_http_url"]   //项目地址
env.branchName = webHookData["ref"] - "refs/heads/"  // 分支
env.commitId = webHookData["checkout_sha"]          //提交id
env.commitUser = webHookData["user_username"]       // 提交人
env.userEmail = webHookData["user_email"]           // 邮箱

currentBuild.description = "Trigger by Gitlab \n branch: ${env.branchName} \n user: ${env.commitUser} "
currentBuild.displayName = "${env.commitId}"

pipeline {
    agent { label "build" }

    stages{
        stage("CheckOut"){
            steps{
                script {
                    //仓库信息
                    //branchName = "${params.branchName}"
                    //srcUrl = "${params.srcUrl}"

                    //下载代码
                    // 使用变量填充分支名称和仓库地址;
                    checkout([$class: 'GitSCM', 
                            branches: [[name: "${env.branchName}"]], 
                            extensions: [], 
                            userRemoteConfigs: [[
                                credentialsId: '7eaa6c7f-f954-4a65-bcd7-15f27edb680b', 
                                url: "${env.srcUrl}"]]])

                    // //验证
                     sh "ls -l "
                }
            }
        }

        // 代码构建
        stage("Build"){
            steps{
                script{
                    echo "build"
                }
            }
        }

        //单元测试
        stage("UnitTest"){
            steps{
                script{
                    echo "unit test"
                }
            }
        }
    }
}
3.邮件通知反馈
  • 默认情况可能每个Gitlab用户没有配置邮箱的, 需要Gitlab用户要配置好邮箱。 点击头像进入 edit profile

image-20220512220414007

来到Emails,里先设置一下自己的邮箱:

image-20220512220621332

然后,在这个页面配置好邮箱地址,最好这几个email都配置上吧…最后点击Update profile settings

image-20220512231814111

image-20220512231831934

  • 奇怪,我这里怎么163、qq邮箱都收不到确认邮件呢??😥

image-20220512222617386

经过百度,发现是在gitlab里的配置文件要做下配置的:

[root@devops ~]#docker ps
CONTAINER ID   IMAGE                                  COMMAND                  CREATED       STATUS                  PORTS                                                                                      NAMES
11a54a1f4a2a   gitlab/gitlab-ce:14.9.3-ce.0           "/assets/wrapper"        6 days ago    Up 28 hours (healthy)   0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:2222->22/tcp                             devops_tutorial_gitlab
f3f039aa667a   jenkins/jenkins:2.332.2-centos7-jdk8   "/sbin/tini -- /usr/…"   4 weeks ago   Up 24 hours             0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:50000->50000/tcp, :::50000->50000/tcp   jenkins
[root@devops ~]#docker exec -it devops_tutorial_gitlab bash
root@11a54a1f4a2a:/# vi /etc/gitlab/gitlab.rb
#搜索smtp
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.163.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "onexlforyou@163.com"
gitlab_rails['smtp_password'] = "NVSMOUfAxxxEMXAB"
gitlab_rails['smtp_domain'] = "163.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
gitlab_rails['gitlab_email_from'] = 'onexlforyou@163.com'

root@11a54a1f4a2a:/# gitlab-ctl reconfigure

image-20220512230631903

image-20220512230917768

image-20220512232120119

image-20220512231434198

image-20220512231531784

image-20220512231618636

此时,发下就可以正常识别到自己的邮箱了:

image-20220512231704671

参考链接:

http://t.zoukankan.com/zgz345-p-9122146.html

image-20220512232258888

  • Jenkins需要配置邮件通知,安装插件Email Extension安装后重启Jenkins。

image-20220512232615940

  • 然后进入系统管理-> 系统配置 , 先配置下全局的admin的邮箱地址。(最后配置下不然可能会出错的)

image-20220512233020808

->Extended E-email Notification。设置邮件系统配置信息。

  • 登入邮箱拿到授权码:这个是qq邮箱的操作方式

img

发送短信之后获取授权码

img

  • 这里我使用的是QQ邮箱,填写SMTP服务器地址smtp.qq.com 和端口 465注意要开启SSL,密码为授权码。

img

image-20220512233218307

image-20220512233312546

换个选项注意下: 不选择 HTML 就是普通的文本, HTML 可以支持html网页,更加美观。这里选择 HTML

img

  • pipeline as code , 进入片段生成器,生成邮件通知代码。

image-20220512233500740

emailext body: 'hello world!....jenkins', subject: 'test……', to: 'onexlforyou@163.com'
  • 然后我们将此段代码加入到Jenkins pipeline 中运行, 可以看到效果:

image-20220512233652736

同时,我们可以看到,这里收到邮件了:

image-20220512233746335

  • jenkins as code 将email 写成一个函数。这个通知信息是一个html格式的。

def EmailUser(userEmail,status){
 	emailext body: """
            <!DOCTYPE html> 
            <html> 
            <head> 
            <meta charset="UTF-8"> 
            </head> 
            <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> 
                <img src="http://192.168.1.200:8080/static/0eef74bf/images/headshot.png">
                <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">   
                    <tr> 
                        <td><br /> 
                            <b><font color="#0B610B">构建信息</font></b> 
                        </td> 
                    </tr> 
                    <tr> 
                        <td> 
                            <ul> 
                                <li>项目名称:${JOB_NAME}</li>         
                                <li>构建编号:${BUILD_ID}</li> 
                                <li>构建状态: ${status} </li>                         
                                <li>项目地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>    
                                <li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li> 
                            </ul> 
                        </td> 
                    </tr> 
                    <tr>  
                </table> 
            </body> 
            </html>  """,
            subject: "Jenkins-${JOB_NAME}项目构建信息 ",
            to: userEmail

}
  • 自己本次完整代码
println("${webhookData}")

emailext body: 'hello world!....jenkins', subject: 'test……', to: 'onexlforyou@163.com'

webhookData = readJSON text: "${webhookData}"

env.srcUrl = webhookData.project.git_http_url
env.branchName = webhookData.ref - "refs/heads/"
env.commitId = webhookData.checkout_sha[0..7]

currentBuild.description = """
srcUrl: ${env.srcUrl} \n
branchName: ${env.branchName} \n
"""
currentBuild.displayName = "${env.commitId}"

env.userEmail = webhookData.user_email

pipeline {
    agent any

    stages {
        stage('CheckOut') {
            steps {
                script {
                    checkout([$class: 'GitSCM', 
                        branches: [[name: "${env.branchName}"]], 
                        extensions: [], 
                        userRemoteConfigs: [[credentialsId: '54df701e-d369-4f69-85c6-7209d45c283b', 
                                                    url: "${env.srcUrl}"]]])
                }
            }
        }

        stage("build"){
            steps {
                script{
                    echo "build"
                }
            }
        }

        stage("test"){
            steps {
                script{
                    echo "test"
                }
            }
        }

        stage("deploy"){
            steps {
                script{
                    echo "deploy"
                }
            }
        }


    }

    post {
        always {
            script {
                EmailUser("${env.userEmail}", currentBuild.result)
            }
        }
    }
}


//发送邮件
def EmailUser(userEmail,status){
    emailext body: """
            <!DOCTYPE html> 
            <html> 
            <head> 
            <meta charset="UTF-8"> 
            </head> 
            <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> 
                <img src="https://bucket-hg.oss-cn-shanghai.aliyuncs.com/img/image-20211108223350304.png">
                <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">   
                    <tr> 
                        <td><br /> 
                            <b><font color="#0B610B">构建信息</font></b> 
                        </td> 
                    </tr> 
                    <tr> 
                        <td> 
                            <ul> 
                                <li>项目名称:${JOB_NAME}</li>         
                                <li>构建编号:${BUILD_ID}</li> 
                                <li>构建状态: ${status} </li>                         
                                <li>项目地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>    
                                <li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li> 
                            </ul> 
                        </td> 
                    </tr> 
                    <tr>  
                </table> 
            </body> 
            </html>  """,
            subject: "Jenkins-${JOB_NAME}项目构建信息 ",
            to: userEmail

}
  • 效果:

在gitlab上模拟一次feature-dev-01的提交,看是否会触发jenkins项目的构建及能否收到邮件?

image-20220512235759864

最后收到的邮件效果:

image-20220512235721766

👉🏼 老师课件代码(完整的jenkinsfile )

try {
    //gitlab传递的数据{}
    println("${WebhookData}")
    //数据格式化
    webHookData = readJSON text: "${WebhookData}"
    //提取仓库信息
    env.srcUrl = webHookData["project"]["git_http_url"]   //项目地址
    env.branchName = webHookData["ref"] - "refs/heads/"  // 分支
    env.commitId = webHookData["checkout_sha"]          //提交id
    env.commitUser = webHookData["user_username"]       // 提交人
    env.userEmail = webHookData["user_email"]           // 邮箱

    currentBuild.description = "Trigger by Gitlab \n branch: ${env.branchName} \n user: ${env.commitUser} "
    currentBuild.displayName = "${env.commitId}"
} catch(e){
    println(e)
    currentBuild.description = "Trigger by Jenkins"
}

pipeline {
    agent { label "build" }

    stages{
        stage("CheckOut"){
            steps{
                script {
                    //仓库信息
                    //branchName = "${params.branchName}"
                    //srcUrl = "${params.srcUrl}"

                    //下载代码
                    checkout([$class: 'GitSCM', 
                            branches: [[name: "${env.branchName}"]], 
                            extensions: [], 
                            userRemoteConfigs: [[
                                credentialsId: '7eaa6c7f-f954-4a65-bcd7-15f27edb680b', 
                                url: "${env.srcUrl}"]]])

                    // //验证
                     sh "ls -l "
                }
            }
        }

        // 代码构建
        stage("Build"){
            steps{
                script{
                    echo "build"
                }
            }
        }

        //单元测试
        stage("UnitTest"){
            steps{
                script{
                    echo "unit test"
                }
            }
        }
    }

    post {
        always {
            script {
                //emailext body: 'hello world!....jenkins', subject: 'test.....', to: '2560350642@qq.com'
                EmailUser("${env.userEmail}", currentBuild.currentResult)
            }
        }
    }
}

//发送邮件
def EmailUser(userEmail,status){
    emailext body: """
            <!DOCTYPE html> 
            <html> 
            <head> 
            <meta charset="UTF-8"> 
            </head> 
            <body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> 
                <img src="http://192.168.1.200:8080/static/0eef74bf/images/headshot.png">
                <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">   
                    <tr> 
                        <td><br /> 
                            <b><font color="#0B610B">构建信息</font></b> 
                        </td> 
                    </tr> 
                    <tr> 
                        <td> 
                            <ul> 
                                <li>项目名称:${JOB_NAME}</li>         
                                <li>构建编号:${BUILD_ID}</li> 
                                <li>构建状态: ${status} </li>                         
                                <li>项目地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>    
                                <li>构建日志:<a href="${BUILD_URL}console">${BUILD_URL}console</a></li> 
                            </ul> 
                        </td> 
                    </tr> 
                    <tr>  
                </table> 
            </body> 
            </html>  """,
            subject: "Jenkins-${JOB_NAME}项目构建信息 ",
            to: userEmail

}

符合预期,测试结束。😘

3、GitLabCI提交流水线

因为GitLabCI与GitLab版本控制系统深度集成,所以不需要配置触发器。

  • 默认已经支持了提交代码、合并代码触发流水线的运行;
  • 默认流水线运行后会自动的下载本项目代码;
💘 实践:基于GitLabCI提交流水线(测试成功)-2022.5.13

image-20220514101710671

1.流水线优化

1、过滤新建分支和tag的触发
  • 先来测试下,gitlabci里新建分支是否会触发流水线的运行?

本次在devops4-commit-service项目里测试:

新创建分支feature-dev-03

image-20220513104839095

可以看到,新建分支操作是会触发流水线运行的:

image-20220513104931751

  • 编写pipeline代码,通过CI_COMMIT_BEFORE_SHA来过滤新建分支和tag的触发:

编写之前可以来看下gitlabci官网预定义的一些变量:

image-20220513105305340

image-20220513105411089

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"
  • 验证

此时,再新建一个分支,看是否会触发流水线的运行

image-20220513105612601

可以发现,此时新建分支不会触发流水线的运行了,符合预期:

image-20220513105640168

2、解决job运行重新下载代码
  • 问题现象:通过下面的CI作业,观察第二个作业是否可以拿到第一个作业的文件:
workflow:
  rules:
    - if: $CI_COMMIT_BEFORE_SHA == "0000000000000000000000000000000000000000"
      when: never
    - when: always

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 
    - echo "Do your deploy here"

分析: citest1作业并没有获取上个阶段产出文件, 因为默认每个作业运行时都会重新下载代码,重新下载代码会把其他文件删除掉:

image-20220513143608006

👉🏼 如何解决?

  1. 禁止后面的作业重复的下载代码;
  2. 使用artifact关键字, 收集制品传递给其他作业;
方法1:GIT_CHECKOUT

GIT_CHECKOUT变量,默认值为true,即作业每次运行都下载代码。按照我们目前的需求,需要禁止下载代码:

我们将此变量的值在全局配置为false,然后在第一个作业(.pre)中配置为true。也就实现了只在第一个作业下载代码而不会出现其他作业下载代码了。

GIT_CHECKOUT: "false" 
  • 优化一下pipeline, 仅在pipelineInit作业中运行代码下载,其他作业跳过;

还需要注意的是:这种方法要保证这些作业都是运行在一个gitlabci-runner上的才行,因此这里把上面的标签全部删除掉,其保证只有一个runner是开启了那个untagged的功能:

image-20220513144242828

variables:
  ENV_TYPE: "dev"
  GIT_CHECKOUT: "false" 

pipelineInit:
  stage: .pre
  variables:
    GIT_CHECKOUT: "true" 
  script:
    - ls -l 

cibuild:
  stage: build
  script:
    - ls -l 
    - echo 123 >test.yaml 
    - ls -l 

citest1:
  stage: test
  script:
    - ls -l 
  • 提交触发运行,查看citest1 作业中的输出, 发现工作目录中已经存在之前作业的产出文件;

image-20220513144415234

image-20220513144446584

方法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:

注意:这个方法可以解决在不同runners上重新下载代码的问题!

同样,我们把2个runner上的untagged功能都勾选上,用于测试实验:

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作业生成的制品;

image-20220513145059193

image-20220513145141314

2.邮件通知反馈

  • 编辑/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'] = "exnyvnekjdgwecga"
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>>
  • 测试邮件:

image-20220513103454028

  • 配置流水线状态通知

image-20220513103526634

image-20220513103539983

image-20220513103552938

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
  1. 个人微信二维码:x2675263825 (舍得), qq:2675263825。

    image-20211002091450217

  2. 个人微信公众号:《云原生架构师实战》

    image-20211002141739664

  3. 个人csdn

    https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

    image-20211002092344616

  4. 个人博客:(www.onlyyou520.com)

    image-20220513150311181

    image-20220513150409987

  5. 开源干货😘

    语雀:https://www.yuque.com/go/doc/73723298?#

    image-20220513150633944

最后

好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值