VM部署实践 02 CI 流水线设计
Jenkins作业
Jenkins作业 |
文件夹: anyops |
作业命名: 后端 anyops-devops-service 前端 anyops-devops-ui |
现在就可以在该项目下面创建子项目了。
CI构建规范
CI构建规范 |
前端项目采用npm打包后统一放到dist目录下, 静态文件以tgz打包。(将静态文件打包上传到制品库) |
后端项目采用maven打包后统一放到target目录下,以jar包。 |
CI/CD流水线设计
总体目标:
我们将CI和CD分成两条流水线作业。
CI:用户输入了分支之后,然后流水线下载代码,然后去构建生成包,之后扫描生成了报告。然后将这个包传到了制品仓库里面,这就是CI要做的一些事情。
传到仓库之后又会有一条CD的流水线,也是需要用户手动去触发的,拿到版本号去下载哪个包,将包下载下来,通过ansible或者slatstack发布到主机,然后通过脚本启动起来,然后做一些健康检查,甚至还有一些回滚的操作。
- CI作业: 用户输入版本分支后下载代码,进行构建扫描最终将制品上传到制品仓库, 生成版本文件。
- CD作业: 用户输入发布版本和选择要发布的主机IP后,下载制品,将制品和服务启动脚本cp到目标机器的发布目录, 远程执行启动脚本启动服务并进行健康检查。
质量规则(项目扫描之前配置好)
后期在做Java代码扫描的时候用的是anyops
质量阈(项目扫描之前配置好)
builds.groovy
package org.devops
// 构建函数
def Build(buildTools,buildType){
switch(buildType){
case "maven":
sh "${buildTools["maven"]}/bin/mvn clean package"
break
case "gradle":
sh "${buildTools["gradle"]}/bin/gradle build -x test"
break
case "golang":
sh "${buildTools["golang"]}/bin/go build demo.go"
break
case "npm":
sh """ ${buildTools["npm"]}/bin/npm install && ${buildTools["npm"]}/bin/npm run build """
break
default :
println("buildType ==> [maven|gralde|golang|npm]")
break
}
}
mytools.groovy
package org.devops
def GetCode(srcType,branchName,gitHttpURL,credentialsId){
if (srcType == "git"){
println("下载代码 --> 分支: ${branchName}")
checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]],
extensions: [],
userRemoteConfigs: [[credentialsId: "${credentialsId}",
url: "${gitHttpURL}"]]])
}
}
sonarqube.groovy
package org.devops
//封装HTTP
def HttpReq(reqType,reqUrl,reqBody){
def sonarServer = "http://139.198.170.122:9000/api"
response = httpRequest authentication: 'e89c6fa4-d9a2-4042-b3a5-8b00ff372d92',
httpMode: reqType,
contentType: "APPLICATION_JSON",
consoleLogResponseBody: true,
ignoreSslErrors: true,
requestBody: reqBody,
url: "${sonarServer}/${reqUrl}"
//quiet: true
return response
}
//搜索Sonar项目
def SerarchProject(projectName){
apiUrl = "projects/search?projects=${projectName}"
response = HttpReq("GET",apiUrl,'')
response = readJSON text: """${response.content}"""
result = response["paging"]["total"]
if(result.toString() == "0"){
return "false"
} else {
return "true"
}
}
//获取Sonar质量阈状态
def GetProjectStatus(projectName){
apiUrl = "project_branches/list?project=${projectName}"
response = HttpReq("GET",apiUrl,'')
response = readJSON text: """${response.content}"""
result = response["branches"][0]["status"]["qualityGateStatus"]
//println(response)
return result
}
//创建Sonar项目
def CreateProject(projectName){
apiUrl = "projects/create?name=${projectName}&project=${projectName}"
response = HttpReq("POST",apiUrl,'')
println(response)
}
//配置项目质量规则
def ConfigQualityProfiles(projectName,lang,qpname){
apiUrl = "qualityprofiles/add_project?language=${lang}&project=${projectName}&qualityProfile=${qpname}"
response = HttpReq("POST",apiUrl,'')
println(response)
}
//获取质量阈ID
def GetQualtyGateId(gateName){
apiUrl= "qualitygates/show?name=${gateName}"
response = HttpReq("GET",apiUrl,'')
response = readJSON text: """${response.content}"""
result = response["id"]
return result
}
//配置项目质量阈
def ConfigQualityGates(projectName,gateName){
gateId = GetQualtyGateId(gateName)
apiUrl = "qualitygates/select?gateId=${gateId}&projectKey=${projectName}"
response = HttpReq("POST",apiUrl,'')
println(response)println(response)
}
jenkinsfile
// 加载名称为devopslib的共享库的master版本
@Library("devopslib@master") _
//导入共享库中的方法类
def mytools = new org.devops.mytools()
def builds = new org.devops.builds()
def sonar = new org.devops.sonarqube()
//定义sonar里面的链接
def homepage = "http://139.198.170.122:81/anyops/anyops-devops-service"
def ci = "http://139.198.170.122:8080/job/anyops"
//定义构建工具类型与路径map
def buildTools = [ "maven": "/usr/local/apache-maven-3.8.1",
"gradle": "/usr/local/gradle-6.8.3/",
"golang": "/usr/local/go",
"npm" : "/usr/local/node-v14.16.1-linux-x64/",
"sonar": "/usr/local/sonar-scanner-4.6.0.2311-linux/"]
//定义UI上面的参数(用户去选择构建那个项目的那个分支的构建类型)
String branchName = "${env.branchName}"
String gitHttpURL = "${env.gitHttpURL}"
String buildType = "${env.buildType}"
String credentialsId = "${env.credentialsId}"
String skipSonar = "${env.skipSonar}"
// 以下是流水线阶段
pipeline {
agent { label "build" }
options {
skipDefaultCheckout true
}
stages {
stage("GetCode"){
steps{
script{
// 调用GetCode方法进行代码下载
mytools.GetCode("git",branchName,gitHttpURL,credentialsId)
}
}
}
stage("Build"){
steps {
script {
// 调用Build方法进行代码构建
builds.Build(buildTools, buildType)
}
}
}
stage("SonarScan"){
when {
environment name: 'skipSonar', value: 'false'
}
steps {
script {
//定义项目名称
projectName= "${env.JOB_NAME}".split("/")[1]
//搜索项目
result = sonar.SerarchProject(projectName)
println(result)
//判断项目是否存在
if(result == "false"){
println("${projectName}----->项目不存在,准备创建项目${projectName}")
sonar.CreateProject(projectName)
}else{
println("${projectName}----->项目已存在!")
}
println(projectName)
qpname = "${projectName}".split("-")[0]
println(qpname)
//配置项目质量规则
sonar.ConfigQualityProfiles(projectName,"java",qpname)
//配置质量阈
sonar.ConfigQualityGates(projectName,qpname)
//扫描
sh """
${buildTools["sonar"]}/bin/sonar-scanner -Dsonar.host.url=http://139.198.170.122:9000 \
-Dsonar.projectKey="${projectName}" \
-Dsonar.projectName="${projectName}" \
-Dsonar.projectVersion=1.0 \
-Dsonar.login=admin \
-Dsonar.password=admin \
-Dsonar.ws.timeout=30 \
-Dsonar.projectDescription="my first project!" \
-Dsonar.links.homepage="${homepage}" \
-Dsonar.links.ci="${ci}" \
-Dsonar.sources=src/main \
-Dsonar.sourceEncoding=UTF-8 \
-Dsonar.java.binaries=target/classes \
-Dsonar.java.test.binaries=target/test-classes \
-Dsonar.java.surefire.report=target/surefire-reports
"""
sleep 10
//获取扫描结果
result = sonar.GetProjectStatus(projectName)
println(result)
if (result.toString() == "ERROR"){
error "代码质量阈失败,请及时修复"
} else {
println(result)
}
}
}
}
}
post {
always {
script{
echo "always......"
}
}
success {
script {
echo "success....."
}
}
}
}
目录 返回
首页