CI/CD流程设计及实现

目前我司的CICD的架构基本如图:

 

其实该架构是一个很常见的架构,但是我在这里主要考虑了如何最大化利用该架构 实现CICD的便捷使用以及后续如何快速集成到运维平台。

思考的问题:

1.因考虑到CICD的可靠性、安全性,需要将pipeline脚本和业务代码分离。

2.如何快速的批量生成项目

3.在使用pipeline scm的时候如何获取业务仓库的cpmmit-id(CI可以直接获取到,但CD 不拷贝业务代码的情况下如何获取? 目前开发测试环境使用commit作为版本号 线上预发用tag作为版本号)

4.发布到kubernetes平台的时候 一般都是k8s去harbor仓库自动拉取镜像,如果没有该镜像那么对于开发测试是无法感知到的。

解决:

目前我司用一个gitlab仓库来管理所有的pipeline脚本以及kubernetes的yml文件,jenkins使用pipeline SCM部署,这个时候有个问题就是业务代码如何克隆到该项目的workspace下进行编译构建,这个时候我们需要使用pipeline的dir函数去生成一个目录将业务代码clone到该目录下进行构建,例如java项目:

 

dir('project') {
    echo "cloning project from $projecturl with branch: $branch"
    final gitinfo = git([branch: "$branch", credentialsId: "$credentialsId", url: "$projecturl"])
    echo "gitinfo: $gitinfo"
    version = "${gitinfo.GIT_COMMIT}".substring(0, 6)
    echo "version:$version"
    imageName = "$imageName:$version"
}
stage('compile') {
    docker.image('maven:3-alpine').withRun('-v /data/.m2:/root/.m2') {
        dir('project') {
            echo "mvn clean package module $modulename"
            withAnt(jdk: 'jdk8') {
                sh "java -version"
                sh "which java"
                sh "which mvn"
                sh "mvn -version"
                echo "--------------------------------"
                sh "mvn clean package -pl $modulename -Dautoconfig.interactive=false -U -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -am"
            }
        }
    }
}
stage('build and push') {
    try {
        echo "build docker images and push to custom Registry"
        sh "docker version"
        docker.withRegistry('http://10.30.30.22:9080', '88a0c6e5-128b-49fb-89c4-7cbe7c8a7593') {
            dir('build') {
                def serviceImage = docker.build("$imageName", "-f Dockerfile --build-arg app=$modulename  .")
                /* Push the container to the custom Registry */
                serviceImage.push()
            }
        }
    } finally {
        dir('build') {
            /* Clean up */
            deleteDir()
        }
    }
}

2.如何快速生成项目

正常情况下 在生成项目的时候我们需要新建项目-配置SCM-选择分支-选择jenkinsfile文件,但这样太繁琐了 并且如果使用grovvy去批量生成项目的话需要更改的配置会非常多容易出错。

所以我在这里的设计是所有的脚本都依赖于project name,通过jenkins自带的JOB_NAME变量去区分不同的项目,并且所有项目的入口都是主的jenkinsfile,通过不同的JOB_NAME路由到不同项目的jenkinsfile。

如图该脚本路径永远是不会变的。

这里我们只需要更改所属分支就可以了

然后我们可以通过jenkins的脚本命令行-grovvy脚本批量生成项目

脚本内容如下:

def hi = Hudson.instance
def allView = hi.getView("all")

def devNestedView = hi.getView("dev");
def buildNestedView = devNestedView.getView("构建");
def javaListView = buildNestedView.getView("java");

println("====================source items======================")
for (item in javaListView.getItems()) {
    println("OUTPUT:  " + item.getName())
}
println("======================================================")

println("====================target items======================")
def targetTestNestedView = hi.getView("test");
def targetBuildNestedView = targetTestNestedView.getView("构建");
def targetJavaListView = targetBuildNestedView.getView("java");

//拷贝一个视图下的JOB
for (item in javaListView.getItems()) {
    //create the new project name
    newName = item.getName().replace("ci_dev", "ci_test")
    // copy the job, disable and save it
    def job
    try {
        //因为第一次导入后报错,所以添加了try-catch 跳过已存在的job
        job = Hudson.instance.copy(item, newName)
    } catch (IllegalArgumentException e) {
        println("WARN:  $newName job is exists")
        def newItem = allView.getItem(newName)
        if (!targetJavaListView.contains(newItem)) {
            //add job to view
            targetJavaListView.add(newItem)
        }
        continue
    } catch (Exception e) {
        println("ERROR:  " + item.getName() + " copy failed")
        continue
    }
    job.disabled = true
    job.save()

    //add job to view
    targetJavaListView.add(job)
    println(" INFO:  $item.name copied as $newName")
}
for (item in targetJavaListView.getItems()) {
    println("OUTPUT:  " + item.getName())
}
println("==================================================");

 

3.在使用pipeline scm的时候如何获取业务仓库的cpmmit-id(CI可以直接获取到,但CD 不拷贝业务代码的情况下如何获取? 目前开发测试环境使用commit作为版本号 线上预发用tag作为版本号)

在这种情况下现有的git插件只能获取到不同仓库的tag或者branch 但是不能获取到commit id,所以这里我在Active Choices Parameter插件使用了grovvy script的形式去获取git里的commit,效果:

 

 

 

 

 

脚本内容:

def command = "sh /root/getTags.sh development/bi-tools-service"

def proc = command.execute()

proc.waitFor()

def lw = "${proc.in.text}"

def lww= Arrays.asList(lw.split(","))

return lww

getTags.sh的脚本内容大致就是curl的形式获取gitlab的commit的列表,我这里因为是docker 所以直接取获取了harbor的api接口的列表。

4.发布到kubernetes平台的时候 一般都是k8s去harbor仓库自动拉取镜像,如果没有该镜像那么对于开发测试是无法感知到的。

在pipeline脚本先检测该镜像是否存在:

		stage("check images") {
		  sh "sh scripts/cd/getImage.sh ${environment}/${JOB_PATH}:${TAGId}"
		}
#!/bin/bash
USER="admin"
PASS="Harbor12345"
HURL="http://10.30.30.22:9080"
MTAG=`echo $1 | awk -F ":" '{print $1}'`
checkTag=`echo $1 | awk -F ":" '{print $2}'`
ttoken=$(curl -iksL -X GET -u $USER:$PASS $HURL/service/token?account=${USER}\&service=harbor-registry\&scope=repository:${MTAG}:pull|grep "token" |awk -F '"' '{print $4}')

#echo $ttoken
flag=0
tlist=$(curl -ksL -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $ttoken" ${HURL}/v2/${MTAG}/tags/list|awk -F '[' '{print $2}'|awk -F ']' '{print $1}'|sed 's/"//g')
tlist1=$(curl -ksL -X GET -H "Content-Type: application/json" -H "Authorization: Bearer $ttoken" ${HURL}/v2/${MTAG}/tags/list)
tlist2=`echo $tlist1|jq '.errors'`
if [[ $tlist2 == null ]]; then
   getTag=`echo $tlist1 | jq ".tags"|cut -d '[' -f 1 | cut -d ']' -f 1 | sed 's/[[:space:]]//g' | grep -v "^$" | sed -e 's/\"//g'|tr ',' '\n'`
   for i in $getTag
     do
       if [[ $checkTag == $i ]]; then
          echo "镜像匹配成功!"
          exit 0
       else
          flag=1
       fi
     done
   if [[ flag==1 ]];then
      echo "无法找到对应镜像:$MTAG:$checkTag"
      exit 1
   fi
else
   echo "无法找到对应镜像:$MTAG:$checkTag"
   exit 1
#   echo $tlist|sed 's/,/\n/g'
fi

 

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值