基于K8s的DevOps平台实践(二)

news2024/12/26 3:12:42

文章目录

  • 1. 流水线入门
    • 🍑 流水线基础语法
    • 🍑 脚本示例
    • 🍑 脚本解释
    • 🍑 Blue Ocean
  • 2. Jenkinsfile实践
    • 🍑 演示一
    • 🍑 演示二
    • 🍑 演示三
    • 🍑 演示四
    • 🍑 总结
  • 3. 多分支流水线实践
    • 🍑 演示一
    • 🍑 演示二
    • 🍑 演示三
    • 🍑 总结


1. 流水线入门

工厂的流水线如下:

在这里插入图片描述

官方文档 的流水线如下:

在这里插入图片描述

为什么叫做流水线?其实和工厂产品的生产线类似,pipeline 是从源码到发布到线上环境。

关于流水线,需要知道的几个点:

  • 重要的功能插件,帮助 Jenkins 定义了一套工作流框架;

  • Pipeline 的实现方式是一套 Groovy DSL( 领域专用语言 ),所有的发布流程都可以表述为一段 Groovy 脚本;

  • 将 WebUI 上需要定义的任务,以脚本代码的方式表述出来;

  • 帮助jenkins实现持续集成 CI(Continue Integration)和持续部署 CD(Continue Deliver)的重要手段;

🍑 流水线基础语法

官方文档

两种语法类型:

  • Scripted Pipeline,脚本式流水线,最初支持的类型
  • Declarative Pipeline,声明式流水线,为 Pipeline plugin 在 2.5 版本之后新增的一种脚本类型,后续 Open Blue Ocean 所支持的类型。与原先的 Scripted Pipeline 一样,都可以用来编写脚本。Declarative Pipeline 是后续 Open Blue Ocean 所支持的类型,写法简单,支持内嵌 Scripted Pipeline 代码

注意:为与 BlueOcean 脚本编辑器兼容,通常建议使用 Declarative Pipeline 的方式进行编写,从 jenkins 社区的动向来看,很明显这种语法结构也会是未来的趋势。

🍑 脚本示例

json 脚本

pipeline { 
    agent {label '172.21.51.68'}
    environment { 
        PROJECT = 'myblog'
    }
    stages {
        stage('Checkout') { 
            steps { 
                checkout scm 
            }
        }
        stage('Build') { 
            steps { 
                sh 'make' 
            }
        }
        stage('Test'){
            steps {
                sh 'make check'
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh 'make publish'
            }
        }
    }
	post {
        success { 
            echo 'Congratulations!'
        }
		failure { 
            echo 'Oh no!'
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

🍑 脚本解释

  • checkout 步骤为检出代码;scm 是一个特殊变量,指示 checkout 步骤克隆触发此 Pipeline 运行的特定修订

  • agent:指明使用哪个 agent 节点来执行任务,定义于 pipeline 顶层或者 stage 内部

    • any,可以使用任意可用的 agent 来执行

    • label,在提供了标签的 Jenkins 环境中可用的代理上执行流水线或阶段。例如:agent { label 'my-defined-label' },最常见的使用方式

    • none,当在 pipeline 块的顶部没有全局代理,该参数将会被分配到整个流水线的运行中并且每个 stage 部分都需要包含他自己的 agent 部分。比如:agent none

    • docker, 使用给定的容器执行流水线或阶段。 在指定的节点中,通过运行容器来执行任务

agent {
    docker {
        image 'maven:3-alpine'
        label 'my-defined-label'
        args  '-v /tmp:/tmp'
    }
}
  • options:允许从流水线内部配置特定于流水线的选项。

    • buildDiscarder,为最近的流水线运行的特定数量保存组件和控制台输出。例如: options { buildDiscarder(logRotator(numToKeepStr: '10')) }
    • disableConcurrentBuilds,不允许同时执行流水线。 可被用来防止同时访问共享资源等。 例如: options { disableConcurrentBuilds() }
    • timeout,设置流水线运行的超时时间, 在此之后,Jenkins将中止流水线。例如: options { timeout(time: 1, unit: 'HOURS') }
    • retry,在失败时, 重新尝试整个流水线的指定次数。 For example: options { retry(3) }
  • environment:指令制定一个 键-值对序列,该序列将被定义为所有步骤的环境变量

  • stages:包含一系列一个或多个 stage 指令,stages 部分是流水线描述的大部分 “work” 的位置。 建议 stages 至少包含一个 stage 指令用于连续交付过程的每个离散部分,比如构建、测试和部署。

pipeline {
    agent any
    stages { 
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
  • steps:在给定的 stage 指令中执行的定义了一系列的一个或多个 steps。

  • post:定义一个或多个 steps ,这些阶段根据流水线或阶段的完成情况而运行 post 支持以下 post-condition 块中的其中之一: alwayschangedfailuresuccessunstableaborted

    • always,无论流水线或阶段的完成状态如何,都允许在 post 部分运行该步骤
    • changed,当前流水线或阶段的完成状态与它之前的运行不同时,才允许在 post 部分运行该步骤
    • failure,当前流水线或阶段的完成状态为 “failure”,才允许在 post 部分运行该步骤,通常 web UI 是红色
    • success,当前流水线或阶段的完成状态为 “success”,才允许在 post 部分运行该步骤,通常 web UI 是蓝色或绿色
    • unstable,当前流水线或阶段的完成状态为 “unstable”,才允许在 post 部分运行该步骤,通常由于测试失败,代码违规等造成。通常 web UI 是黄色
    • aborted,只有当前流水线或阶段的完成状态为 “aborted”,才允许在 post 部分运行该步骤,通常由于流水线被手动的aborted。通常 web UI 是灰色

创建 pipeline 示意:新建任务 -> 流水线

jenkins/pipelines/p1.yaml

pipeline {
   agent {label '172.21.51.68'}
   environment { 
      PROJECT = 'myblog'
   }
   stages {
      stage('printenv') {
         steps {
            echo 'Hello World'
            sh 'printenv'
         }
      }
      stage('check') {
         steps {
            checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-user', url: 'http://gitlab.luffy.com/root/myblog.git']]])
         }
      }
      stage('build-image') {
         steps {
            sh 'docker build . -t myblog:latest -f Dockerfile'
         }
      }
      stage('send-msg') {
         steps {
            sh """
            curl 'https://oapi.dingtalk.com/robot/send?access_token=4778abd23dbdbaf66fc6f413e6ab9c0103a039b0054201344a22a5692cdcc54e' \
   -H 'Content-Type: application/json' \
   -d '{"msgtype": "text", 
        "text": {
             "content": "我就是我, 是不一样的烟火"
        }
      }'
      """
         }
      }
   }
}

点击 “立即构建”,同样的,我们可以配置触发器,使用 webhook 的方式接收项目的 push 事件

  • 构建触发器选择 Build when a change is pushed to GitLab.
  • 生成 Secret token
  • 配置 gitlab,创建 webhook,发送 test push events 测试

🍑 Blue Ocean

官方文档

关于 Blue Ocean 我们需要知道的几点:

  • 是一个插件, 旨在为 Pipeline 提供丰富的体验 ;
  • 连续交付(CD)Pipeline 的复杂可视化,允许快速和直观地了解 Pipeline 的状态;
  • 目前支持的类型仅针对于 Pipeline,尚不能替代 Jenkins 经典版UI

思考:

  1. 每个项目都把大量的 pipeline 脚本写在 Jenkins 端,对于谁去维护及维护成本是一个问题
  2. 没法做版本控制

2. Jenkinsfile实践

Jenkins Pipeline 提供了一套可扩展的工具,用于将 “简单到复杂” 的交付流程实现为 “持续交付即代码”。

Jenkins Pipeline 的定义通常被写入到一个文本文件(称为 Jenkinsfile )中,该文件可以被放入项目的源代码控制库中。

🍑 演示一

演示1:使用 Jenkinsfile 管理 pipeline

  • 在项目中新建 Jenkinsfile 文件,拷贝已有 script 内容
  • 配置 pipeline 任务,流水线定义为 Pipeline Script from SCM
  • 执行 push 代码测试

Jenkinsfile:jenkins/pipelines/p2.yaml

pipeline {
   agent {label '172.21.51.68'}
   environment { 
      PROJECT = 'myblog'
   }
   stages {
      stage('printenv') {
         steps {
            echo 'Hello World'
            sh 'printenv'
         }
      }
      stage('check') {
         steps {
            checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-user', url: 'http://gitlab.luffy.com/root/myblog.git']]])
         }
      }
      stage('build-image') {
         steps {
            sh 'docker build . -t myblog:latest -f Dockerfile'
         }
      }
      stage('send-msg') {
         steps {
            sh """
            curl 'https://oapi.dingtalk.com/robot/send?access_token=4778abd23dbdbaf66fc6f413e6ab9c0103a039b0054201344a22a5692cdcc54e' \
   -H 'Content-Type: application/json' \
   -d '{"msgtype": "text", 
        "text": {
             "content": "我就是我, 是不一样的烟火"
        }
      }'
      """
         }
      }
   }
}

🍑 演示二

演示2:优化及丰富流水线内容

  • 优化代码检出阶段

    由于目前已经配置了使用 git 仓库地址,且使用 SCM 来检测项目,因此代码检出阶段完全没有必要再去指定一次

  • 构建镜像的 tag 使用 git 的 commit id

  • 增加 post 阶段的消息通知,丰富通知内容

  • 配置 webhook,实现 myblog 代码推送后,触发 Jenkinsfile 任务执行

jenkins/pipelines/p3.yaml

pipeline {
    agent { label '172.21.51.68'}

    stages {
        stage('printenv') {
            steps {
            echo 'Hello World'
            sh 'printenv'
            }
        }
        stage('check') {
            steps {
                checkout scm
            }
        }
        stage('build-image') {
            steps {
            	retry(2) { sh 'docker build . -t myblog:${GIT_COMMIT}'}
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=4778abd23dbdbaf66fc6f413e6ab9c0103a039b0054201344a22a5692cdcc54e' \
                    -H 'Content-Type: application/json' \
                    -d '{"msgtype": "text", 
                            "text": {
                                "content": "😄👍构建成功👍😄\n 关键字:luffy\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
                        }
                }'
            """
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=4778abd23dbdbaf66fc6f413e6ab9c0103a039b0054201344a22a5692cdcc54e' \
                    -H 'Content-Type: application/json' \
                    -d '{"msgtype": "text", 
                            "text": {
                                "content": "😖❌构建失败❌😖\n 关键字:luffy\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
                        }
                }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

🍑 演示三

演示3:使用 k8s 部署服务

  • 新建 deploy 目录,将 k8s 所需的文件放到 deploy 目录中

  • 将镜像地址改成模板,在 pipeline 中使用新构建的镜像进行替换

  • 执行 kubectl apply -f deploy 应用更改,需要配置 kubectl 认证

$ scp -r k8s-master:/root/.kube /root

jenkins/pipelines/p4.yaml

pipeline {
    agent { label '172.21.51.68'}

    environment {
        IMAGE_REPO = "172.21.51.143:5000/myblog"
    }

    stages {
        stage('printenv') {
            steps {
              echo 'Hello World'
              sh 'printenv'
            }
        }
        stage('check') {
            steps {
                checkout scm
            }
        }
        stage('build-image') {
            steps {
                retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
            }
        }
        stage('push-image') {
            steps {
                retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
            }
        }
        stage('deploy') {
            steps {
                sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
                timeout(time: 1, unit: 'MINUTES') {
                    sh "kubectl apply -f manifests/"
                }
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=4778abd23dbdbaf66fc6f413e6ab9c0103a039b0054201344a22a5692cdcc54e' \
                    -H 'Content-Type: application/json' \
                    -d '{"msgtype": "text", 
                            "text": {
                                "content": "😄👍构建成功👍😄\n 关键字:myblog\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
                        }
                }'
            """
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=4778abd23dbdbaf66fc6f413e6ab9c0103a039b0054201344a22a5692cdcc54e' \
                    -H 'Content-Type: application/json' \
                    -d '{"msgtype": "text", 
                            "text": {
                                "content": "😖❌构建失败❌😖\n 关键字:luffy\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
                        }
                }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

🍑 演示四

演示4:使用凭据管理敏感信息

上述 Jenkinsfile 中存在的问题是敏感信息使用明文,暴漏在代码中,如何管理流水线中的敏感信息(包含账号密码),之前我们在对接 gitlab 的时候,需要账号密码,已经使用过凭据来管理这类敏感信息,同样的,我们可以使用凭据来存储钉钉的 token 信息,那么,创建好凭据后,如何在 Jenkinsfile 中获取已有凭据的内容?

Jenkins 的声明式流水线语法有一个 credentials() 辅助方法(在 environment 指令中使用),它支持 secret 文本,带密码的用户名,以及 secret 文件凭据。

下面的流水线代码片段展示了如何创建一个使用带密码的用户名凭据的环境变量的流水线。

在该示例中,带密码的用户名凭据被分配了环境变量,用来使你的组织或团队以一个公用账户访问 Bitbucket 仓库;这些凭据已在 Jenkins 中配置了凭据 ID jenkins-bitbucket-common-creds

当在 environment 指令中设置凭据环境变量时:

environment {
    BITBUCKET_COMMON_CREDS = credentials('jenkins-bitbucket-common-creds')
}

这实际设置了下面的三个环境变量:

  • BITBUCKET_COMMON_CREDS - 包含一个以冒号分隔的用户名和密码,格式为 username:password
  • BITBUCKET_COMMON_CREDS_USR - 附加的一个仅包含用户名部分的变量。
  • BITBUCKET_COMMON_CREDS_PSW - 附加的一个仅包含密码部分的变量。
pipeline {
    agent {
        // 此处定义 agent 的细节
    }
    environment {
        //顶层流水线块中使用的 environment 指令将适用于流水线中的所有步骤。 
        BITBUCKET_COMMON_CREDS = credentials('jenkins-bitbucket-common-creds')
    }
    stages {
        stage('Example stage 1') {
 			//在一个 stage 中定义的 environment 指令只会将给定的环境变量应用于 stage 中的步骤。
            environment {
                BITBUCKET_COMMON_CREDS = credentials('another-credential-id')
            }
            steps {
                // 
            }
        }
        stage('Example stage 2') {
            steps {
                // 
            }
        }
    }
}

因此对 Jenkinsfile 做改造:jenkins/pipelines/p5.yaml

pipeline {
    agent { label '172.21.51.68'}

    environment {
        IMAGE_REPO = "172.21.51.143:5000/myblog"
        DINGTALK_CREDS = credentials('dingTalk')
    }

    stages {
        stage('printenv') {
            steps {
            echo 'Hello World'
            sh 'printenv'
            }
        }
        stage('check') {
            steps {
                checkout scm
            }
        }
        stage('build-image') {
            steps {
                retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
            }
        }
        stage('push-image') {
            steps {
                retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
            }
        }
        stage('deploy') {
            steps {
                sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
                timeout(time: 1, unit: 'MINUTES') {
                    sh "kubectl apply -f manifests/"
                }
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{"msgtype": "text", 
                            "text": {
                                "content": "😄👍构建成功👍😄\n 关键字:luffy\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
                        }
                }'
            """
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{"msgtype": "text", 
                            "text": {
                                "content": "😖❌构建失败❌😖\n 关键字:luffy\n 项目名称: ${JOB_BASE_NAME}\n Commit Id: ${GIT_COMMIT}\n 构建地址:${RUN_DISPLAY_URL}"
                        }
                }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

🍑 总结

上面我们已经通过 Jenkinsfile 完成了最简单的项目的构建和部署,那么我们来思考目前的方式:

目前都是在项目的单一分支下进行操作,企业内一般会使用 feature、develop、release、master 等多个分支来管理整个代码提交流程,如何根据不同的分支来做构建?

构建视图中如何区分不同的分支?

如何不配置 webhook 的方式实现构建?

如何根据不同的分支选择发布到不同的环境(开发、测试、生产)?

3. 多分支流水线实践

官方示例

我们简化一下流程,假如使用 develop 分支作为开发分支,master 分支作为集成测试分支,看一下如何使用多分支流水线来管理。

🍑 演示一

演示1:多分支流水线的使用

(1)提交develop分支:

$ git checkout -b develop
$ git push --set-upstream origin develop

(2)禁用 pipeline 项目

(3)Jenkins 端创建多分支流水线项目

  • 增加 git 分支源
  • 发现标签
  • 根据名称过滤,develop|master|v.*
  • 高级克隆,设置浅克隆

保存后,会自动检索项目中所有存在 Jenkinsfile 文件的分支和标签,若匹配我们设置的过滤正则表达式,则会添加到多分支的构建视图中。所有添加到视图中的分支和标签,会默认执行一次构建任务。

🍑 演示二

演示2:美化消息通知内容

  • 添加构建阶段记录
  • 使用 markdown 格式,添加构建分支消息

jenkins/pipelines/p6.yaml

pipeline {
    agent { label '172.21.51.68'}

    environment {
        IMAGE_REPO = "172.21.51.143:5000/myblog"
        DINGTALK_CREDS = credentials('dingTalk')
        TAB_STR = "\n                    \n                    "
    }

    stages {
        stage('printenv') {
            steps {
                script{
                    sh "git log --oneline -n 1 > gitlog.file"
                    env.GIT_LOG = readFile("gitlog.file").trim()
                }
                sh 'printenv'
            }
        }
        stage('checkout') {
            steps {
                checkout scm
                script{
                    env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('build-image') {
            steps {
                retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('push-image') {
            steps {
                retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('deploy') {
            steps {
                sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
                timeout(time: 1, unit: 'MINUTES') {
                    sh "kubectl apply -f manifests/"
                }
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😄👍 构建成功 👍😄  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${GIT_BRANCH}   \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """ 
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😖❌ 构建失败 ❌😖  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${GIT_BRANCH}  \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

🍑 演示三

演示3:通知 gitlab 构建状态

Jenkins 端做了构建,可以通过 gitlab 通过的 api 将构建状态通知过去,作为开发人员发起 Merge Request 或者合并 Merge Request 的依据之一。

注意一定要指定 gitLabConnection('gitlab'),不然没法认证到 Gitlab 端

jenkins/pipelines/p7.yaml

pipeline {
    agent { label '172.21.51.68'}
    
    options {
		buildDiscarder(logRotator(numToKeepStr: '10'))
		disableConcurrentBuilds()
		timeout(time: 20, unit: 'MINUTES')
		gitLabConnection('gitlab')
	}

    environment {
        IMAGE_REPO = "172.21.51.143:5000/demo/myblog"
        DINGTALK_CREDS = credentials('dingTalk')
        TAB_STR = "\n                    \n                    "
    }

    stages {
        stage('printenv') {
            steps {
                script{
                    sh "git log --oneline -n 1 > gitlog.file"
                    env.GIT_LOG = readFile("gitlog.file").trim()
                }
                sh 'printenv'
            }
        }
        stage('checkout') {
            steps {
                checkout scm
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS = env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('build-image') {
            steps {
                retry(2) { sh 'docker build . -t ${IMAGE_REPO}:${GIT_COMMIT}'}
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('push-image') {
            steps {
                retry(2) { sh 'docker push ${IMAGE_REPO}:${GIT_COMMIT}'}
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
        stage('deploy') {
            steps {
                sh "sed -i 's#{{IMAGE_URL}}#${IMAGE_REPO}:${GIT_COMMIT}#g' manifests/*"
                timeout(time: 1, unit: 'MINUTES') {
                    sh "kubectl apply -f manifests/"
                }
                updateGitlabCommitStatus(name: env.STAGE_NAME, state: 'success')
                script{
                    env.BUILD_TASKS += env.STAGE_NAME + "√..." + env.TAB_STR
                }
            }
        }
    }
    post {
        success { 
            echo 'Congratulations!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😄👍 构建成功 👍😄  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}   \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """ 
        }
        failure {
            echo 'Oh no!'
            sh """
                curl 'https://oapi.dingtalk.com/robot/send?access_token=${DINGTALK_CREDS_PSW}' \
                    -H 'Content-Type: application/json' \
                    -d '{
                        "msgtype": "markdown",
                        "markdown": {
                            "title":"myblog",
                            "text": "😖❌ 构建失败 ❌😖  \n**项目名称**:luffy  \n**Git log**: ${GIT_LOG}   \n**构建分支**: ${BRANCH_NAME}  \n**构建地址**:${RUN_DISPLAY_URL}  \n**构建任务**:${BUILD_TASKS}"
                        }
                    }'
            """
        }
        always { 
            echo 'I will always say Hello again!'
        }
    }
}

我们可以访问 gitlab,然后找到 commit 记录,查看同步状态:

在这里插入图片描述

提交 merge request,也可以查看到相关的任务状态,可以作为项目 owner 合并代码的依据之一:

在这里插入图片描述

🍑 总结

优势:

  • 根据分支展示,视图人性化
  • 自动检测各分支的变更

思考:

  • Jenkins 的 slave 端,没有任务的时候处于闲置状态,slave 节点多的话造成资源浪费
  • 是否可以利用 kubernetes 的 Pod 来启动 slave,动态 slave pod 来执行构建任务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/136144.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BEV视觉3D感知算法梳理

1. 基于BEV空间的自动驾驶感知任务 最近,基于BEV空间下的感知任务已经涌现出了众多优秀算法,并在多个自动驾驶公开数据集(KITTI,Waymo,nuScenes)上取得了非常不错的成绩。根据自动驾驶汽车上安装的传感器类…

【从零开始学习深度学习】37. 深度循环神经网络与双向循环神经网络简介

目录1. 深度循环神经网络2. 双向循环神经网络总结1. 深度循环神经网络 之前介绍的循环神经网络只有一个单向的隐藏层,在深度学习应用里,我们通常会用到含有多个隐藏层的循环神经网络,也称作深度循环神经网络。下图演示了一个有LLL个隐藏层的…

数字化时代,全方位解读商业智能BI

商业智能BI是一种通用的数据类技术解决方案,不会因为行业BI没有进行针对性开发而出现不适配、无法使用的情况。同时,也正因为商业智能BI核心是数据,只要企业有数据沉淀,不管是哪些行业BI商业智能都能发挥出作用。 不过考虑到不同…

文件IO操作开发笔记(一):使用Qt的QFile对磁盘文件存储进行性能测试以及测试工具

文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/128438303 红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

portraiture2023智能磨皮修饰滤镜插件中文版

在人像后期修图的时候免不了需要进行磨皮处理,很多人在挑选磨皮软件的时候都不知道该如何选择,今天的文章就来带大家看看磨皮软件哪个好,能磨皮的修图软件和插件!借助磨皮软件即使是新手也能做出高级的人像图片,下面挑选了几款好用…

Java 并发编程知识总结【五】

6. 线程中断与 LockSupport 6.1 线程中断机制 大厂(蚂蚁金服)面试题: 什么是中断? 首先,一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.…

Exynos_4412——中断控制器

目录 一、中断控制器 中断控制器的作用: 二、Exynos_4412下的中断控制器 它支持三种类型的中断 可以编程设置: 三、中断控制器详解 四、中断控制器编程 一、中断控制器 外设产生的中断信号,先要经过中断控制器,中断是异常…

如何解决软件项目管理中的冲突?

1、项目干系人间的良好沟通 项目干系人之间保持良好的沟通交流,是减少项目管理中冲突的重要手段。甲乙双方签订合同后,为保障项目的成功,在项目发生矛盾和困难时,需要双方相互理解和沟通,共同协商解决问题。 为了及时解…

Git(八) - IDEA 集成 GitHub

一、设置 GitHub 账号 二、分享工程到 GitHub 来到GitHub中发现已经帮我们创建好了git-test的远程仓库。 三、push 推送本地库到远程库 注意:push是将本地库代码推送到远程库,如果本地库代码跟远程库代码版本不一致, push的操作是会被拒绝的…

go 性能分析pprof和trace

runtime/pprof:采集程序(非 Server)的运行数据进行分析,用于可结束的代码块,如一次编解码操作等net/http/pprof:采集 HTTP Server 的运行时数据进行分析。用于不可结束的代码块,如 web 应用等 使…

​工程师如何对待开源

工程师如何对待开源 本文是笔者作为一个在知名科技企业内从事开源相关工作超过 20 年的工程师,亲身经历或者亲眼目睹很多工程师对待开源软件的优秀实践,也看到了很多 Bad Cases,所以想把自己的一些心得体会写在这里,供工程师进行…

linux的shell的概述

Shell 教程 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。 Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。 Ke…

各种颜色的代码

颜色代码对照表如下: 关于16进制颜色代码: 这有必要了解一颜色系统的概念: RGB:RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的&a…

MySQL的一些有意思的指令和函数

这个里面我准备记录一些比较有意思的MySQL的指令和函数,当然使用函数的时候我们要注意,会不会因为函数导致不走索引,走全表扫描的情况。 因为对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树…

文本分类(LSTM+PyTorch)

本文的配套代码已上传至github,链接在文末,同时附带中文数据集。 一、传统方法的基本步骤 预处理:首先进行分词,然后是除去停用词;将文本表示成向量,常用的就是文本表示向量空间模型;进行特征…

回调函数、qsort函数、sort函数与lambda表达式

目录 目录 1、回调函数 2、sort函数 3、lambda表达式 4、qsort与sort函数使用lambda表达式 1、回调函数 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一 个函数,当这个指针被用来调用其所指向的函…

凝心聚力 开源共建 | 统信软件参与成立OpenKunlun开源固件社区

11月22日,统信软件携手国内固件厂商、处理器厂商、外设板卡厂商等数十家产业同仁参与共建的OpenKunlun开源固件社区正式成立! OpenKunlun社区是在自愿、开源、平等和协作的基础上,由基础软硬件企业、高等院校、个人开发者共同参与的非营利性开…

STM32——STM32中断系统与EXTI外部中断

文章目录一、中断系统二、STM32中断系统三、NVIC(嵌套中断向量控制器)NVIC基本结构NVIC优先级分组四、EXTI(外部中断)EXTI简介EXTI基本结构AFIO复用IO口EXTI框图五、对射式红外传感器计次电路设计关键函数EXTI库函数文件&#xff…

SpringMVC与SpringBoot响应请求的流程

SpringMVC是基于Servlet的MVC模型,Model:一个或多个javabean对象,用于存储数据和业务逻辑;View:一个或多个jsp页面,拿到控制器提交的数据为模型提供数据显示;Controller:一个或多个s…

【消息中间件】RabbitMQ的工作模式

前 言 🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端 ☕专栏简介:深入、全面、系统的介绍消息中间件 🌰 文章简介:本文将介绍RabbitMQ的工作模式 &#x1f353…