CI/CD-云主机场景CI篇-[jenkinslib库|Gitlab API使用|环境库]
此次在CI/CD实践中引入集成模板库,和环境库
## 定义一个模板文件
集成模板库名称:hwf-app-jenkinslib
- 有了这个库以后,所有项目的jenkinsfile,class,property都可以统一在一起,对应项目目录里只需要存放项目就可以了,jenkins执行的时候checkout项目
jenkinsfile
@Library("hwf-jenkins@main") _ import hwf.devops.* // 导入库 def checkout = new Checkout() def build = new Build() def unittest = new UnitTest() def sonar = new Sonar() def nexuspackage = new Nexuspackage() def gitlab = new Gitlab() currentBuild.description = "Trigger by Gitlab \n branch: ${env.branchName} \n user: ${env.commitUser} " currentBuild.displayName = "${env.commitId}" env.releaseVersion = "${env.branchName}".split("-")[-1] env.appName = "${JOB_NAME}".split('/')[-1] // Day5/acmp-myapp-service env.repoName = "${JOB_NAME}".split("/")[0] pipeline { agent { label "build" } stages{ stage("Checkout"){ steps{ script { println("GetCode") checkout.GetCode("${env.srcUrl}", "${env.branchName}") } } } stage("Build"){ steps{ script{ println("Build") build.CodeBuild("${env.buildTool}") } } } stage("UnitTest"){ steps{ script{ unittest.CodeTest("${env.buildTool}") } } } stage("SonarScan"){ steps { script{ groupName = "${JOB_NAME}".split("/")[0] projectName = "${JOB_NAME}".split("/")[-1] //devops03/devops03-maven-service sonar.CodeSonar("${env.buildTool}", projectName, groupName) } } } stage("Nexuspackage"){ steps{ script{ repoName = "${JOB_NAME}".split("/")[0] //hwf-app/ projectName = "${JOB_NAME}".split("/")[-1].split("_")[0] //hwf-app/hwf-app-service version = "${env.branchName}".split("-")[-1] //RELEASE-1.1.1 targetDir = "${projectName}/${version}/" //hwf-app/hwf-app-service/1.1.1 println("upload nexus") if ("${env.buildTool}" == "maven"){ filePath="./demo/target" sh "ls -l demo/target/" pkgName=sh returnStdout: true, script: "cd demo/target/;ls *.jar;cd ../../" pkgName = pkgName.trim() newPkgName="${projectName}-${version}.jar" sh "cd demo/target; mv ${pkgName} ${newPkgName}" type = "application/java-archive" } if ("${env.buildTool}" == "npm"){ filePath="./npm/dist" newPkgName = "${projectName}-${version}.tar.gz" sh """ ls -l pwd cd ${filePath} [ -f ${newPkgName} ] && rm -fr ${newPkgName} echo "${version}" >index.html tar zcf ${newPkgName} * """ type = "application/x-gzip" } env.artifactUrl = nexuspackage.PushRawArtifacts(repoName,targetDir, filePath, newPkgName, type ) println("${env.artifactUrl}") } } } // 生成版本文件 stage("ReleaseFile"){ steps { script { //下载版本库文件 devops02-env/release.yaml response = gitlab.GetRepoFile(17,"release.yaml", "main") //println(response) //替换文件中内容 yamlData = readYaml text: """${response}""" println(yamlData) yamlData.version = "${env.releaseVersion}" yamlData.artifact = "${env.artifactUrl}" yamlData.repoName = "${env.repoName}" yamlData.appname = "${env.appName}" println(yamlData.toString()) sh "rm -fr test.yaml" writeYaml charset: 'UTF-8', data: yamlData, file: 'test.yaml' newYaml = sh returnStdout: true, script: 'cat test.yaml' println(newYaml) //更新gitlab文件内容 base64Content = newYaml.bytes.encodeBase64().toString() // 会有并行问题,同时更新报错 try { gitlab.UpdateRepoFile(17,"${env.appName}%2f${env.branchName}.yaml",base64Content, "main") } catch(e){ gitlab.CreateRepoFile(17,"${env.appName}%2f${env.branchName}.yaml",base64Content, "main") } } } } } }
Build.groovy
package hwf.devops //Maven def MavenBuild(){ def buildTools = ["maven": "/data/apache-maven-3.8.3"] sh "${buildTools["maven"]}/bin/mvn clean package -DskipTests -f demo/pom.xml \ -s settings.xml" } //Gradle def GradleBuild(){ def buildTools = ["gradle": "/data/gradle-7.2"] sh "${buildTools["gradle"]}/bin/gradle clean && ${buildTools["gradle"]}/bin/gradle build -x test" } //Ant def AntBuild(configPath="./build.xml"){ sh "ant -f ${configPath}" } //Golang def GoBuild(){ def buildTools = ["go": "/data/go" ] sh "${buildTools["go"]}/bin/go build demo.go" } //Npm def NpmBuild(){ def buildTools = ["npm": "/data/node-v14.18.0-linux-x64" ] sh """ cd npm export PATH=\$PATH:${buildTools["npm"]}/bin ${buildTools["npm"]}/bin/npm install ${buildTools["npm"]}/bin/npm run build """ } //Yarn def YarnBuild(){ sh "yarn install && yarn build " } //Main def CodeBuild(type){ switch(type){ case "maven": MavenBuild() break; case "gradle": GradleBuild() break; case "npm": NpmBuild() break; case "yarn": YarnBuild() break; default: error "No such tools ... [maven/ant/gradle/npm/yarn/go]" break } }
Checkout.groovy
package hwf.devops //下载代码 def GetCode(srcUrl, branchName){ checkout([$class: 'GitSCM', branches: [[name: branchName]], extensions: [], userRemoteConfigs: [[ credentialsId: '6ac312c6-9282-42ec-89a3-680356304ea2', url: srcUrl]]]) }
Nexuspackage.groovy
package hwf.devops def PushRawArtifacts(repoName,targetDir, filePath, pkgName, type ){ withCredentials([usernamePassword(credentialsId: '8a3c99b1-a165-4ac6-a972-2355e6cc14a7', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) { sh """ curl -X POST "http://192.168.1.110:8081/nexus/service/rest/v1/components?repository=${repoName}" \ -H "accept: application/json" \ -H "Content-Type: multipart/form-data" \ -F "raw.directory=${targetDir}" \ -F "raw.asset1=@${filePath}/${pkgName};type=${type}" \ -F "raw.asset1.filename=${pkgName}" \ -u "${USER}":"${TOKEN}" """ // 返回包下载地址 artifactUrl = "http://192.168.1.110:8081/nexus/repository/${repoName}/${targetDir}${pkgName}" return artifactUrl } }
Sonar.groovy
package hwf.devops def SonarRequest(apiUrl,method){ withCredentials([string(credentialsId: "16ed65f2-1b1e-4fbb-b976-a5fd60698d60", variable: 'SONAR_TOKEN')]) { sonarApi = "http://192.168.1.110:9000/api" response = sh returnStdout: true, script: """ curl --location \ --request ${method} \ "${sonarApi}/${apiUrl}" \ --header "Authorization: Basic ${SONAR_TOKEN}" """ // json格式化 try { response = readJSON text: """ ${response - "\n"} """ } catch(e){ response = readJSON text: """{"errors" : true}""" } return response } } //查找项目 def SearchProject(projectName){ apiUrl = "projects/search?projects=${projectName}" response = SonarRequest(apiUrl,"GET") if (response.paging.total == 0){ return false } return true } //创建项目 def CreateProject(projectName){ apiUrl = "projects/create?name=${projectName}&project=${projectName}" response = SonarRequest(apiUrl,"POST") try{ if (response.project.key == projectName ) { println("Project Create success!...") return true } }catch(e){ println(response.errors) return false } } // 更新质量阈 def UpdateQualityProfiles(lang, projectName, profileName){ apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${profileName}" response = SonarRequest(apiUrl,"POST") if (response.errors != true){ println("ERROR: UpdateQualityProfiles ${response.errors}...") return false } else { println("SUCCESS: UpdateQualityProfiles ${lang} > ${projectName} > ${profileName}" ) return true } } def SonarJava(projectName, groupName ){ withCredentials([string(credentialsId: '9a2fd415-eebb-403b-9116-db07f9ae2605', variable: 'AUTH_TOKEN')]) { sh """ sonar-scanner -Dsonar.host.url=http://192.168.1.110:9000 \ -Dsonar.projectKey=${projectName} \ -Dsonar.projectName=${projectName} \ -Dsonar.projectVersion=${BUILD_ID} \ -Dsonar.login=${AUTH_TOKEN} \ -Dsonar.ws.timeout=30 \ -Dsonar.projectDescription="my first project!" \ -Dsonar.links.homepage=http://192.168.1.110:9080/${groupName}/${projectName} \ -Dsonar.links.ci=http://192.168.1.110:8080/job/${groupName}/job/${projectName}/ \ -Dsonar.sources=./demo/src \ -Dsonar.sourceEncoding=UTF-8 \ -Dsonar.java.binaries=./demo/target/classes \ -Dsonar.java.test.binaries=./demo/target/test-classes """ } } def SonarWeb(projectName, groupName ){ withCredentials([string(credentialsId: '9a2fd415-eebb-403b-9116-db07f9ae2605', variable: 'AUTH_TOKEN')]) { sh """ sonar-scanner -Dsonar.host.url=http://192.168.1.110:9000 \ -Dsonar.projectKey=${projectName} \ -Dsonar.projectName=${projectName} \ -Dsonar.projectVersion=${BUILD_ID} \ -Dsonar.login=${AUTH_TOKEN} \ -Dsonar.ws.timeout=30 \ -Dsonar.projectDescription="my first project!" \ -Dsonar.links.homepage=http://192.168.1.110:9080/${groupName}/${projectName} \ -Dsonar.links.ci=http://192.168.1.110:8080/job/${groupName}/job/${projectName}/ \ -Dsonar.sources=./npm/src \ -Dsonar.sourceEncoding=UTF-8 """ } } //Main def CodeSonar(type, projectName, groupName){ if (SearchProject(projectName)){ println("${projectName} exists....") } else { // 项目不存在 println("${projectName} not found....") //创建项目 CreateProject(projectName) } //质量配置 profileMap = ["maven": "java", "npm": "js"] UpdateQualityProfiles(profileMap[type], projectName, groupName) switch(type){ case "maven": SonarJava(projectName, groupName) break; case "gradle": SonarJava(projectName, groupName) break; case "npm": SonarWeb(projectName, groupName) break; default: println("No such tools ... [maven/ant/gradle/npm/yarn/go]") break } }
UnitTest.groovy
package hwf.devops //Maven def MavenTest(){ def buildTools = ["maven": "/data/apache-maven-3.8.3"] sh """ ${buildTools["maven"]}/bin/mvn test -f demo/pom.xml -s settings.xml """ } //Gradle def GradleTest(){ def buildTools = ["gradle": "/data/gradle-7.2"] sh """ ${buildTools["gradle"]}/bin/gradle test junit 'build/test-results/test/*.xml' """ } //Ant //def AntBuild(configPath="./build.xml"){ // sh "ant -f ${configPath}" //} //Golang //def GoTest(){ //sh " go test" //} //Npm def NpmTest(){ def buildTools = ["npm": "/data/node-v14.18.0-linux-x64" ] sh """ export PATH=\$PATH:${buildTools["npm"]}/bin ${buildTools["npm"]}/bin/npm test" """ } //Yarn //def YarnTest(){ // sh "yarn test " //} //Main def CodeTest(type){ switch(type){ case "maven": MavenTest() break; case "gradle": GradleTest() break; default: println("No such tools ... [maven/ant/gradle/npm/yarn/go]") break } }
jenkins CI流水线设置
hwf-app-service
- srcUrl
- http://192.168.1.110:9080/hwf-app/hwf-app-service.git
- Repository URL
- http://192.168.1.110:9080/hwf-app/hwf-app-jenkinslib.git
hwf-app-web
- srcUrl
- http://192.168.1.110:9080/hwf-app/hwf-app-web.git
- Repository URL
- http://192.168.1.110:9080/hwf-app/hwf-app-jenkinslib.git
## CI生成版本文件
0.获取gitlab本地模板文件(gitlab下载文件API接口)
1.将配置信息写入本地的一个文件中 (yaml语法更改)
2.将文件上传到gitlab (gitlab上传文件API接口)
## CD 获取版本文件
1.从gitlab上面下载版本文件
2.读取本地的这个版本文件进行发布
Gitlab.groovy
package hwf.devops // 封装HTTP def HttpReq(reqType, reqUrl,reqBody ){ def gitServer = "http://192.168.1.110:9080/api/v4" withCredentials([string(credentialsId: '515d16fb-c888-4649-af09-f1a8bf57b211', variable: 'GITLABTOKEN')]) { response = httpRequest acceptType: 'APPLICATION_JSON_UTF8', consoleLogResponseBody: true, contentType: 'APPLICATION_JSON_UTF8', customHeaders: [[maskValue: false, name: 'PRIVATE-TOKEN', value: "${GITLABTOKEN}"]], httpMode: "${reqType}", url: "${gitServer}/${reqUrl}", wrapAsMultipart: false, requestBody: "${reqBody}" } return response } //获取文件内容 def GetRepoFile(projectId,filePath, branchName ){ //GET /projects/:id/repository/files/:file_path/raw apiUrl = "/projects/${projectId}/repository/files/${filePath}/raw?ref=${branchName}" response = HttpReq('GET', apiUrl, "") return response.content } //更新文件内容 def UpdateRepoFile(projectId,filePath,fileContent, branchName){ apiUrl = "projects/${projectId}/repository/files/${filePath}" reqBody = """{"branch": "${branchName}","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}""" response = HttpReq('PUT',apiUrl,reqBody) println(response) } //创建文件 def CreateRepoFile(projectId,filePath,fileContent, branchName){ apiUrl = "projects/${projectId}/repository/files/${filePath}" reqBody = """{"branch": "${branchName}","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}""" response = HttpReq('POST',apiUrl,reqBody) println(response) }
##jenkins 创建gitlab api凭据
jenkins创建凭据
jenkinsfile使用token方法
执行流水线错误解方法:
执行流水线报错解决方法
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod org.codehaus.groovy.runtime.EncodingGroovyMethods encodeBase64 byte[]
- 点击连接,进去会允许就可以了
流水线运行成功
创建环境库
库名称:hwf-app-env
- 被画横线的是不用创建的,流水线跑起来会自动生成项目目录
release.yaml
version: __NULL__ appname: __NULL__ repoName: __NULL__ artifact: __NULL__
继续阅读

我的微信
这是我的微信扫一扫
评论