1:部署完成之后检测pod状态,获取同名pod的个数,一个就执行检测,多个就直接报失败,设置超时时间内检测
stage("get pod and test to rollouting"){
steps{
script {
def namespace="${params.namespace}";
def depName="dep-${params.moduleCode}";
timeout(240) {
while(true) {
def result = sh(script: "kubectl get pod -n " +namespace+ " --kubeconfig=/root/.kube/dev-config |grep " +depName+"-*|wc -l", returnStdout:true).trim()
sh "echo ${result}"
if("${result}" == "1"){
sleep (10)
sh "kubectl get pod -n " +namespace+ " --kubeconfig=/root/.kube/dev-config |grep " +depName+ " > appname.txt"
def data = readFile(file: "appname.txt")
println data
def list =data.split(' ')
sh "kubedog rollout track -n " +namespace+ " pod " +list[0]+ " --kube-config=/root/.kube/dev-config && kubectl logs --since=2m " +list[0]+ " -n " +namespace+ " --kubeconfig=/root/.kube/dev-config || kubectl rollout undo deployment/"+depName+ " -n " +namespace+ " --kubeconfig=/root/.kube/dev-config"
sh "break"
}else{
sleep (10)
def result1 = sh(script: "kubectl get pod -n " +namespace+ " --kubeconfig=/root/.kube/dev-config |grep " +depName+"-*|wc -l", returnStdout:true).trim()
sh "echo ${result1}"
if("${result1}" == "1"){
sh "kubectl get pod -n " +namespace+ " --kubeconfig=/root/.kube/dev-config |grep " +depName+ " > appname.txt"
def data = readFile(file: "appname.txt")
println data
def list =data.split(' ')
sh "kubedog rollout track -n " +namespace+ " pod " +list[0]+ " --kube-config=/root/.kube/dev-config && kubectl logs --since=2m " +list[0]+ " -n " +namespace+ " --kubeconfig=/root/.kube/dev-config || kubectl rollout undo deployment/"+depName+ " -n " +namespace+ " --kubeconfig=/root/.kube/dev-config"
sh "break"
}else{
sh "echo '继续检测中.....'"
}
}
}
}
}
}
}
2:选分支拉取代码
stage("git pull code") {
steps {
//clear workspace
cleanWs()
script {
//pull code
print "repoBranch : ${params.repoBranch}"
checkout([$class: 'GitSCM', branches: [[name: "${params.repoBranch}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${params.repoCred}", url: "${params.repoUrl}"]]])
}
}
}
3:kubernetes之服务回滚
stage("rollout pod"){
steps{
script{
def namespace="${params.namespace}";
def controller="${params.controller}";
def depName="${params.depName}";
sh "kubectl get " +controller+ " -n " +namespace+ " |grep " +depName+ " > controllerName.txt"
def data = readFile(file: "controllerName.txt")
println data
def list =data.split(' ')
sh "kubectl rollout undo " +controller+"/"+list[0]+ " -n " +namespace
//sh "kubedog rollout track -n " +namespace+ " " +controller+ " " +list[0]+ " && echo 'undo start success' || echo 'undo start faild'"
}
}
}
4:gradle结合sonar编译加扫描
stage("gradle and sonar"){
steps{
script {
def timeStamp=new Date().format("yyyy-MM-dd");
def targetDir="${WORKSPACE}/${params.targetDir}";
dir(targetDir){
withSonarQubeEnv('sonarqube-jenkins') {
print "repoBranch : ${params.repoBranch}"
sh "gradle clean build --parallel -x test sonarqube -Dsonar.projectKey=${params.projectKey} -Dsonar.projectName=${params.projectKey} -Dsonar.sourceEncoding=UTF-8 -Dsonar.analysis.buildNumber=${env.BUILD_NUMBER} -Dsonar.analysis.jobName=${env.JOB_NAME} -Dsonar.java.binaries=build/classes -Dsonar.analysis.isFortify=true -Dsonar.projectDate="+timeStamp
}
}
}
}
}
5:docker镜像编译
pipeline {
agent any
environment {
def tag = sh(script: "echo `date +%s`", returnStdout: true).trim()
}
stage("docker build"){
steps{
//def IMAGE_URL="10.10.0.100:8081/test-docker-dev/${params.IMAGE_NAME}:${tag};
sh "cd ${WORKSPACE}/ && docker build -t 10.10.0.100:8081/test-docker-dev/${params.IMAGE_NAME}:${tag} -f Dockerfile ."
sh "docker push 10.10.0.100:8081/test-docker-dev/${params.IMAGE_NAME}:${tag}"
}
}
}
6:灵活部署yaml资源,如存在就打上原始标注,不存在就部署并打上标注,方便后期回滚
stage("k8s build"){
steps{
script{
def filePath="${params.ymlPath}";
def namespace="${params.namespace}";
def depName="${params.depName}";
def imageUrl="${params.imageUrl}";
def imageTag="${params.imageTag}";
//def artifactVersion="${params.artifactVersion}";
def imageName="${params.imageName}"
def namesp="devops-test"
def nFile="${WORKSPACE}/management-deployment-svc.yaml"
def data = readFile(file: filePath)
data=data.replaceAll("imageUrl",imageUrl+"/"+imageName)
data=data.replaceAll("imageTag",imageTag)
data=data.replaceAll("depName",depName)
//data=data.replaceAll("artifactVersion",artifactVersion)
println(data)
writeFile(file: nFile, text: data)
def resulting = sh(script: "kubectl annotate deployment/"+depName+ " kubernetes.io/change-cause=image-tag:initial -n " +namespace , returnStatus: true)
if ("${resulting}" == 0){
sh "kubectl annotate deployment/"+depName+ " kubernetes.io/change-cause=image-tag:initial -n " +namespace
sh "kubectl apply -f " +nFile
sh "kubectl annotate deployment/"+depName+ " kubernetes.io/change-cause=image-tag:"+imageTag+ " -n " +namespace
}else{
sh "kubectl apply -f " +nFile
sh "kubectl annotate deployment/"+depName+ " kubernetes.io/change-cause=image-tag:"+imageTag+ " -n " +namespace
}
}
}
}
7:maven结合sonar扫描
stage("mavne and sonar"){
steps{
withSonarQubeEnv('sonarqube-jenkins') {
sh "mvn -U -s ${params.mavenXml} -f ${params.pomXml} clean compile -P dev -Dmaven.test.skip=true sonar:sonar -Dsonar.projectKey=${params.projectKey} -Dsonar.projectName=${params.projectKey} -Dsonar.sourceEncoding=UTF-8 -Dsonar.java.binaries=target/ -Dsonar.exclusions=src/test/** -Dsonar.sources=src/ -Dsonar.language=java -Dsonar.analysis.jobName=${env.JOB_NAME} -Dsonar.analysis.buildNumber=${env.BUILD_NUMBER} -Dsonar.analysis.isFortify=true"
}
script {
timeout(1) {
sleep(5)
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"
}
}
}
}
}
8:npm,maven,gradle,python四种编译结合,传参选择
stage("gradle or maven or npm or python"){
steps{
script {
if("${params.compileType}" == "maven"){
def targetDir="${WORKSPACE}/${params.targetDir}";
dir(targetDir){
if("${params.needSonarScan}" == "no"){
if ("${params.settingXml}" == "" && "${params.pomXml}" == "") {
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U clean package -Dmaven.test.skip=true"
}
}else if("${params.settingXml}" != "" && "${params.pomXml}" == ""){
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U -s ${params.settingXml} clean package -Dmaven.test.skip=true"
}
}else if("${params.settingXml}" == "" && "${params.pomXml}" != ""){
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U -f ${params.pomXml} clean package -Dmaven.test.skip=true"
}
}else {
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U -s ${params.settingXml} -f ${params.pomXml} clean package -Dmaven.test.skip=true"
}
}
}else{
withSonarQubeEnv('sonarqube-jenkins') {
if ("${params.settingXml}" == "" && "${params.pomXml}" == "") {
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U clean package -Dmaven.test.skip=true sonar:sonar -Dsonar.projectKey=${params.moduleCode} -Dsonar.projectName=${params.moduleCode} -Dsonar.sourceEncoding=UTF-8 -Dsonar.java.binaries=target/ -Dsonar.exclusions=src/test/** -Dsonar.sources=src/ -Dsonar.language=java -Dsonar.analysis.jobName=${env.JOB_NAME} -Dsonar.analysis.buildNumber=${env.BUILD_NUMBER} -Dsonar.analysis.isFortify=true"
}
}else if("${params.settingXml}" != "" && "${params.pomXml}" == ""){
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U -s ${params.settingXml} clean package -Dmaven.test.skip=true sonar:sonar -Dsonar.projectKey=${params.moduleCode} -Dsonar.projectName=${params.moduleCode} -Dsonar.sourceEncoding=UTF-8 -Dsonar.java.binaries=target/ -Dsonar.exclusions=src/test/** -Dsonar.sources=src/ -Dsonar.language=java -Dsonar.analysis.jobName=${env.JOB_NAME} -Dsonar.analysis.buildNumber=${env.BUILD_NUMBER} -Dsonar.analysis.isFortify=true"
}
}else if("${params.settingXml}" == "" && "${params.pomXml}" != ""){
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U -f ${params.pomXml} clean package -Dmaven.test.skip=true sonar:sonar -Dsonar.projectKey=${params.moduleCode} -Dsonar.projectName=${params.moduleCode} -Dsonar.sourceEncoding=UTF-8 -Dsonar.java.binaries=target/ -Dsonar.exclusions=src/test/** -Dsonar.sources=src/ -Dsonar.language=java -Dsonar.analysis.jobName=${env.JOB_NAME} -Dsonar.analysis.buildNumber=${env.BUILD_NUMBER} -Dsonar.analysis.isFortify=true"
}
}else {
withMaven(globalMavenSettingsConfig: "${env.mavenSettingsId}") {
sh "mvn -U -s ${params.settingXml} -f ${params.pomXml} clean package -Dmaven.test.skip=true sonar:sonar -Dsonar.projectKey=${params.moduleCode} -Dsonar.projectName=${params.moduleCode} -Dsonar.sourceEncoding=UTF-8 -Dsonar.java.binaries=target/ -Dsonar.exclusions=src/test/** -Dsonar.sources=src/ -Dsonar.language=java -Dsonar.analysis.jobName=${env.JOB_NAME} -Dsonar.analysis.buildNumber=${env.BUILD_NUMBER} -Dsonar.analysis.isFortify=true"
}
}
}
}
}
}
}
script {
if("${params.compileType}" == "npm"){
def targetDir="${WORKSPACE}/${params.targetDir}";
dir(targetDir){
sh "npm install --unsafe-perm=true --allow-root --registry=https://registry.npm.taobao.org && npm run build:prod"
}
}
}
script {
if("${params.compileType}" == "gradle"){
def targetDir="${WORKSPACE}/${params.targetDir}";
dir(targetDir){
if("${params.needSonarScan}" == "no"){
print "repoBranch : ${params.repoBranch}"
sh "gradle clean build --parallel -x test"
}else{
withSonarQubeEnv('sonarqube-jenkins') {
print "repoBranch : ${params.repoBranch}"
sh "gradle clean build --parallel -x test sonarqube -Dsonar.projectKey=${params.moduleCode} -Dsonar.projectName=${params.moduleCode} -Dsonar.sourceEncoding=UTF-8 -Dsonar.branch.name=${params.repoBranch} -Dsonar.analysis.buildNumber=${env.BUILD_NUMBER} -Dsonar.analysis.jobName=${env.JOB_NAME} -Dsonar.java.binaries=build/classes -Dsonar.analysis.isFortify=true"
}
}
}
}
}
script {
if("${params.compileType}" == "python"){
def targetDir="${WORKSPACE}/${params.targetDir}";
dir(targetDir){
sh "pwd && ls -l"
sh "source /etc/profile && pyinstaller -F httpsrv.py"
}
}
}
script{
if("${params.needSonarScan}" == "yes"){
timeout(1) {
sleep(5)
def qg = waitForQualityGate()
if (qg.status != 'OK') {
error "未通过Sonarqube的代码质量阈检查,请及时修改!failure: ${qg.status}"
}
}
}
}
}
}
9:kubernetes部署最终版
stage("kubernetes yaml build"){
steps{
script{
def ymlPath="${params.ymlPath}";
def namespace="${params.namespace}";
def appName="${params.appName}";
def depName="${params.depName}";
def appPort="${params.appPort}";
def cmName="${params.cmName}";
def svcName="${params.svcName}";
def svcPort="${params.svcPort}";
def imageName="${params.imageName}";
def imageTag="${params.imageTag}";
def envKubeconfig="${params.envKubeconfig}";
def nFile="${WORKSPACE}/deployment-svc.yaml"
def data = readFile(file: ymlPath)
data=data.replaceAll("#namespace#",namespace)
data=data.replaceAll("#appName#",appName)
data=data.replaceAll("#depName#",depName)
data=data.replaceAll("#appPort#",appPort)
data=data.replaceAll("#cmName#",cmName)
data=data.replaceAll("#svcName#",svcName)
data=data.replaceAll("#svcPort#",svcPort)
data=data.replaceAll("#imageName#",imageName)
data=data.replaceAll("#imageTag#",imageTag)
println(data)
writeFile(file: nFile, text: data)
def resulting = sh(script: "kubectl get deployment " +depName+ " -n " +namespace+ " --kubeconfig="+envKubeconfig , returnStatus: true)
sh "echo ${resulting}"
if ("${resulting}" == "0"){
sh "kubectl annotate deployment/"+depName+ " kubernetes.io/change-cause=image-tag:initial -n " +namespace+ " --kubeconfig="+envKubeconfig
sh "kubectl apply -f " +nFile+ " --kubeconfig="+envKubeconfig
sh "curl -X PUT -u user:passwd -T ${WORKSPACE}/deployment-svc.yaml https://10.10.10.10:8081/artifactory/test-docker-dev/"+imageName+"/"+imageTag+"/"
sh "kubectl annotate deployment/"+depName+ " kubernetes.io/change-cause=image-tag:"+imageTag+ " -n " +namespace+ " --kubeconfig="+envKubeconfig
}else{
sh "kubectl apply -f " +nFile+ " --kubeconfig="+envKubeconfig #envKubeconfig是不同环境的config文件,可以对不同环境操作
sh "curl -X PUT -u user:passwd -T ${WORKSPACE}/deployment-svc.yaml https://10.10.10.10:8081/artifactory/test-docker-dev/"+imageName+"/"+imageTag+"/" #每次部署完,将yaml文件传入jfrog保存,方便下次根据yaml指定镜像名镜像标签回滚
sh "kubectl annotate deployment/"+depName+ " kubernetes.io/change-cause=image-tag:"+imageTag+ " -n " +namespace+ " --kubeconfig="+envKubeconfig #每次部署完成,给deployment打上标签,方便回滚以及知道当前版本
}
}
}
}
10:K8S服务回滚和检测pod状态
stage("New kubernetes server building"){
steps{
script{
def environment = "${params.environment}"
def url = "${env.DEVOPS_URL}/rTaskRunRecord/getYamlAndRecordVariable"
def jsonParamsHttp = [:];
jsonParamsHttp.put("env", environment);
jsonParamsHttp.put("taskId", "${env.JOB_NAME}");
jsonParamsHttp.put("buildNumber", "${env.BUILD_NUMBER}");
jsonParamsHttp.put("pipelineId", "${env.pipelineId}");
def postResult = httpRequestStage(url,jsonParamsHttp);
serYamlData = jsonParseText(postResult.result).data
sh "touch ${WORKSPACE}/server.yaml;echo '@depData@' > ${WORKSPACE}/server.yaml"
def depYmlPath="${WORKSPACE}/server.yaml"
def nFile="${WORKSPACE}/deployment.yaml"
def data = readFile(file: depYmlPath)
data=data.replaceAll("@depData@",serYamlData)
writeFile(file: nFile, text: data)
sh "cat " +nFile
def depName = null
def namespace = null
def yamlContent = serYamlData
def yamlList = yamlConvertToList(yamlContent)
if(null != yamlList){
for(def map : yamlList){
def kind = map.get("kind")
if("Deployment" == kind){
def metadata = (Map)map.get("metadata")
depName = metadata.get("name")
namespace = metadata.get("namespace")
break
}
}
}
println("==================================================")
println("部署检测所需参数: depName=" + depName + ", namespace=" + namespace)
println("==================================================")
if(null == depName || null == namespace){
error "解析部署包名与命名空间失败, 请检查yaml解析脚本"
}
sh "kubectl apply -f " +nFile+ " --validate=false --kubeconfig=/root/.kube/" +environment+ "-config"
println("等待60s后, 开始检测服务")
sleep 60
def i=0;
while(true) {
if(i>=10){
sh """
echo "服务启动失败,开始回滚........"
kubectl rollout undo deployment ${depName} -n ${namespace} \
--kubeconfig=/root/.kube/${environment}-config
echo "服务回滚完成"
"""
error "服务启动失败,完成回滚"
}
i++;
def result = sh(script: "kubectl get pod -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config |grep " +depName+"-[0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z]* |wc -l", returnStdout:true).trim()
sh "echo ${result}"
if("${result}" == "1"){
sleep 10
sh "kubectl get pod -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config |grep " +depName+ " > appname.txt"
def fileData = readFile(file: "appname.txt")
println fileData
def list =fileData.split(' ')
sh "kubedog rollout track -n "+namespace+" pod " +list[0]+ " --kube-config=/root/.kube/"+environment+"-config && kubectl logs --since=4m " +list[0]+ " -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config || kubectl rollout undo deployment/"+depName+ " -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config"
break;
}else{
sleep 10
sh "kubectl get pod -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config |grep " +depName
def result1 = sh(script: "kubectl get pod -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config |grep " +depName+"-[0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z][0-9/a-z]* |wc -l", returnStdout:true).trim()
sh "echo ${result1}"
if("${result1}" == "1"){
sh "kubectl get pod -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config |grep " +depName+ " > appname.txt"
def fileData = readFile(file: "appname.txt")
println fileData
def list =fileData.split(' ')
sh "kubedog rollout track -n "+namespace+" pod " +list[0]+ " --kube-config=/root/.kube/"+environment+"-config && kubectl logs --since=4m " +list[0]+ " -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config || kubectl rollout undo deployment/"+depName+ " -n "+namespace+" --kubeconfig=/root/.kube/"+environment+"-config"
break;
}else{
sh "echo '继续检测中.....'"
}
}
}
}
}
}
11:一键导入变量并引用yaml文件
stage("envsubst kubernetes yaml build"){
steps{
script{
def replicas="${params.replicas}";
sh "curl -O -u user:passwd https://10.10.10.10:8081/artifactory/test-docker-dev/yaml/dep-svc-sso-app.yaml"
sh " envsubst < dep-svc-sso-app.yaml | kubectl apply -f - --kubeconfig=/root/.kube/dev-config"
}
}
}