逃脱只会部署集群系列 —— 基于sharedLibrary的CI/CD流程构建

目录

一、sharedLibrary介绍

1、什么是sharedLibrary

2、Library工作模式

3、Library代码结构

二、提前准备工作

1、jenkins添加harbor登录凭证

2、jenkins配置library

3、jenkins独立配置robot流水线

4、jenkins配置gitlab

三、涉及功能点实现

1、library整体环境准备

1、jenkinsfile全局配置

2、异常捕获

3、计时器与循环  

4、library解析yaml文件

2、library集成镜像构建及推送

1、jenkinsfile调用片段

2、docker login实现

3、build or push完成推送消息 

3、library集成k8s服务部署

 四、源码

1、原出处

2、简化版


一、sharedLibrary介绍

1、什么是sharedLibrary

        由于公司内部项目众多,大量的项目使用同一套流程做CICD

  • 那么势必会存在大量的重复代码

  • 一旦某个公共的地方需要做调整,每个项目都需要修改

        主要通过使用groovy实现Jenkins的sharedLibrary的开发,以提取项目在CICD实践过程中的公共逻辑,提供一系列的流程的接口供公司内各项目调用。

        开发完成后,对项目进行Jenkinsfile的改造,最后仅需通过简单的Jenkinsfile的配置,即可优雅的完成CICD流程的整个过程,此方式已在大型企业内部落地应用。

2、Library工作模式

        由于流水线被组织中越来越多的项目所采用,常见的模式很可能会出现。 在多个项目之间共享流水线有助于减少冗余并保持代码 "DRY"。

流水线支持引用 "共享库" ,可以在外部源代码控制仓库中定义并加载到现有的流水线中。

@Library('my-shared-library') _

在实际运行过程中,会把library中定义的groovy功能添加到构建目录中:

/var/jenkins_home/jobs/test-maven-build/branches/feature-CDN-2904.cm507o/builds/2/libs/my-shared-library/vars/devops.groovy

3、Library代码结构

共享库的目录结构如下:

(root)
+- src                     # Groovy source files
|   +- org
|       +- foo
|           +- Bar.groovy  # for org.foo.Bar class
+- vars
|   +- foo.groovy          # for global 'foo' variable
|   +- foo.txt             # help for 'foo' variable

src 目录应该看起来像标准的 Java 源目录结构。当执行流水线时,该目录被添加到类路径下。

vars 目录定义可从流水线访问的全局变量的脚本。 每个 *.groovy 文件的基名应该是一个 Groovy (~ Java) 标识符, 通常是 camelCased

二、提前准备工作

1、jenkins添加harbor登录凭证

        无论是传统流水线还是library构建,登陆或者钉钉token等私密数据都建议采用全局凭证方式调用,类似k8s中的secret资源对象。

逃脱只会部署集群系列 —— 基于sharedLibrary的CI/CD流程构建_第1张图片

2、jenkins配置library

        [系统管理] -> [系统设置] -> [ **Global Pipeline Libraries** ],配置jenkins调用library,library可以看作是gitlab上面的一套独立代码类。

逃脱只会部署集群系列 —— 基于sharedLibrary的CI/CD流程构建_第2张图片

逃脱只会部署集群系列 —— 基于sharedLibrary的CI/CD流程构建_第3张图片

3、jenkins独立配置robot流水线

        robot集成测试一般用于测试流水线,不适合放在项目中,我们将测试用户单独创建一个流水线,library直接调用即可

逃脱只会部署集群系列 —— 基于sharedLibrary的CI/CD流程构建_第4张图片

逃脱只会部署集群系列 —— 基于sharedLibrary的CI/CD流程构建_第5张图片

4、jenkins配置gitlab

逃脱只会部署集群系列 —— 基于sharedLibrary的CI/CD流程构建_第6张图片

三、涉及功能点实现

1、library整体环境准备

1、jenkinsfile全局配置

@Library('rui-devops') _    #jenkins调用library

pipeline {
    agent { label 'jnlp-slave'}    #k8s动态生成jenkins-slave
    options {
                timeout(time: 20, unit: 'MINUTES')    #循环检测超时
                gitLabConnection('gitlab')    #调用gitlab
        }
    environment {
        IMAGE_REPO = "192.168.0.121:5000/myblog/myblog"    #镜像地址
        IMAGE_CREDENTIAL = "credential-registry"    #用户密码模式全局变量,harbor登录
        DINGTALK_CREDS = credentials('dingTalk')    #token模式全局变量,钉钉通知token
        PROJECT = "myblog"
    }

2、异常捕获

def exceptionDemo(){
    try {
        def val = 10 / 0
        println(val)
    }catch(Exception e) {
        println(e.toString())
        throw e
    }
}
exceptionDemo()

3、计时器与循环  

        主要用于集群更新容器版本后,循环检测pog启动状态是否为running

import groovy.time.TimeCategory

use( TimeCategory ) {
    def endTime = TimeCategory.plus(new Date(), TimeCategory.getSeconds(15))
    def counter = 0
    while(true) {
        println(counter++)
        sleep(1000)
        if (new Date() >= endTime) {
            println("done")
            break
        }
    }
}

4、library解析yaml文件

        library代码中需要获取容器yaml文件中的变量,例如获取namespace、label、副本数等,可以导入三方类org.yaml.snakeyaml.Yaml实现

import org.yaml.snakeyaml.Yaml

def readYaml(){
    def content = new File('myblog.yaml').text
    Yaml parser = new Yaml()
    def data = parser.load(content)
    def kind = data["kind"]
    def name = data["metadata"]["name"]
    println(kind)
    println(name)
}
readYaml()

2、library集成镜像构建及推送

1、jenkinsfile调用片段

stage('docker-image') {
            steps {
                container('tools') {
                    script{
                        devops.docker(
                            "${IMAGE_REPO}",
                            "${GIT_COMMIT}",
                            IMAGE_CREDENTIAL
                        ).build().push()
                    }
                }
            }

2、docker login实现

    //groovy获取jenkins全局凭证ID,并将对应的账号密码赋值给自定义变量
    withCredentials([usernamePassword(credentialsId: this.credentialsId, usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')])
    sh "docker login ${regs} -u $USERNAME -p $PASSWORD"

3、build or push完成推送消息 

sh "docker push ${this.fullAddress}"
//把当前推送的镜像地址记录在环境变量中
env.CURRENT_IMAGE = this.fullAddress
isSuccess = true

    // check if build success
    def stage = env.STAGE_NAME + '-push'
    if(isSuccess){
        updateGitlabCommitStatus(name: "${stage}", state: 'success')
        this.msg.updateBuildMessage(env.BUILD_TASKS, "${stage} OK...  √")

3、library集成k8s服务部署

检查myblog应用的pod是否部署正常,人工检查的大致步骤:

  1. kubectl -n luffy get pod,查看pod列表

  2. 找到列表中带有myblog关键字的running的pod

  3. 查看上述running pod数,是否和myblog的deployment中定义的replicas副本数一致

  4. 若一致,则检查结束,若不一致,可能稍等几秒钟,再次执行相同的检查操作

  5. 如果5分钟了还没有检查通过,则大概率是pod有问题,通过查看日志进一步排查

如何通过library代码实现上述过程:

  1. library如何获取myblog的pod列表?

    • 首先要知道本次部署的是哪个workload,因此需要调用者传递workload的yaml文件路径

    • library解析workload.yaml文件,找到如下值:

      • pod所在的namespace

      • pod中使用的labels标签

    • 使用如下命令查找该workload关联的pod

      $ kubectl -n  get po -l  -l 
      ​
      # 如查找myblog的pod
      $ kubectl -n luffy get po -l app=myblog
  2. 如何确定步骤1中的pod的状态?

    # 或者可以直接进行提取状态
    $ kubectl -n luffy get po -l app=myblog -ojsonpath='{.items[0].status.phase}'
    ​
    # 以json数组的形式存储
    $ kubectl -n luffy get po -l app=myblog -o json
    ​
  3. 如何检测所有的副本数都是正常的?

    # 以json数组的形式存储
    $ kubectl -n luffy get po -l app=myblog -o json
    ​
    # 遍历数组,检测每一个pod查看是否均正常(terminating和evicted除外)
    
  4. 如何实现在5分钟的时间内,若pod状态符合预期,则退出检测循环,若不符合预期则继续检测

    use( TimeCategory ) {
      def endTime = TimeCategory.plus(new Date(), TimeCategory.getMinutes(timeoutMinutes,5))
      while (true) {
        if (new Date() >= endTime) {
            //超时了,则宣告pod状态不对
            updateGitlabCommitStatus(name: 'deploy', state: 'failed')
            throw new Exception("deployment timed out...")
        }
        //循环检测当前deployment下的pod的状态
        try {
          if (this.isDeploymentReady()) {
              readyCount++
              if(readyCount > 5){
                updateGitlabCommitStatus(name: 'deploy', state: 'success')
                break;
              }
          }else {
              readyCount = 0
          }catch (Exception exc){
              echo exc.toString()
          }
          //每次检测若不满足所有pod均正常,则sleep 5秒钟后继续检测
          sleep(5)
        }
      }

 四、源码

1、原出处

原作者源码,有能力者可以直接git clone学习

YongxinLi/jenkins-shared-library

2、简化版

自己练习时简化的代码,基本功能实现,主要去除了多项目逻辑判断,sonarqube代码扫描、通知方式判断等,添加了一些注释。

配套源码:

CSDNhttps://mp.csdn.net/mp_download/manage/download/UpDetailed

配套镜像:

王宏瑞 (wanghongruihaha) - Gitee.comhttps://gitee.com/wanghongruihaha

docker pull registry.cn-hangzhou.aliyuncs.com/devlop01/myblog:v1
docker pull registry.cn-hangzhou.aliyuncs.com/devlop01/mysql:v1
docker pull registry.cn-hangzhou.aliyuncs.com/devlop01/tools:v1

你可能感兴趣的:(kubernetes,Jenkins,ci/cd,kubernetes,k8s,jenkins,devops)