【k8s】Jenkins实现Java springboot应用CI、CD实践 【二】

一、运行Jenkins流水线流程思路:

场景1:常规java应用,使用jenkins pipeline 交付到Kubernetes集群中

1、准备好java代码、Dockerfile、 deploy. yaml资源清单文件

CI阶段:
1、获取代码
2、漏洞扫描
3、检测漏洞扫描结果,如果正常则继续、否则就终止
4、使用maven进行编译,打包
5、制作Docker镜像、推送到Harbor仓库
6、交付应用到K8S


CD阶段:
1、获取完整的镜像名称;从Harbor中获取 (curl命令去获取)
2、将完整的镜像名称替换到deploy.yaml这个资源清单中;
3、直接部署到K8S的生产环境名称空间;
4、询问是否需要回退;

二 - java代码提交

1、下载代码

代码地址: https://gitee.com/oldxuedu/springboot-helloworld
wget https://gitee.com/oldxuedu/springboot-helloworld/repository/blazearchive/master.zip

做域名解析 如 10.240.0.201  gitlab.oldxu.net

在这里插入图片描述

2、创建新仓库,推送到gitlab仓库
在这里插入图片描述
在这里插入图片描述

[root@master01 springboot-CICD]# cd springboot-helloworld-master/
[root@master01 springboot-helloworld-master]# 
[root@master01 springboot-helloworld-master]# ls
deploy.yaml  Dockerfile  entrypoint.sh  pom.xml  push_jar.sh  README.md  src


git init
git add remote origin http://gitlab.oldxu.net/root/springboot.git
git add .

git config --global user.email "123456@qq.com"
git config --global user.name  "oldxu"

git commit -m "初始化"
git push -u origin master

在这里插入图片描述

deploy.yaml 需要替换的变量:
	{NameSpace}
	{Image}
	{host}

三、Pipeline流水线-获取代码

3.0 本小段流程思路:

			1、获取代码
				调用git来获取即可;   
						1、slavePod如何访问Gitlab
							1、通过gitlab的service地址去访问项目;
							2、通过Coredns配置自定义域名解析;(*本文采用该方式)
						
						2、Gitlab项目是私有的 如何处理;
							需要 在jenkins上配置好对应gitlab认证的信息;
				
				才能使用pipeline去获取代码
				  environment{
					Gitlab_Id = "gitlab-root-token"
					Gitlab_Pro = "http://gitlab.oldxu.net/root/springboot.git"
				}


				stage('获取代码') {
				  steps {
					container('maven') {
					  checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: "${Gitlab_Id}", url: "${Gitlab_Pro}"]]])
					}
				  }
				}

3.1 修改coredns

#过Coredns配置自定义域名解析;

kubectl edit configmap -n kube-system coredns

根据实际情况加上:
 hosts {
          192.168.79.31 gitlab.oldxu.net 
          192.168.79.32 gitlab.oldxu.net 
          192.168.79.33 gitlab.oldxu.net
          fallthrough  
}

在这里插入图片描述
在这里插入图片描述

3.2 Jenkins -> 系统管理 -> 全局凭据 -> New credentials

将gitlab的登录信息添加
http://jenkins.oldxu.net:30080/manage/credentials/store/system/domain/_/
在这里插入图片描述

3.3 Jenkins -> 流水线语法 -> 生成对应的gitlab下拉项目的代码

选中checkout from version control
在这里插入图片描述
在这里插入图片描述

checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root-token', url: 'http://gitlab.oldxu.net:30080/root/springboot.git']])

3.4 编写对应pipeline代码:

主要看environment和stage的 ,

pipeline{
  agent{
    kubernetes{
      cloud 'kubernetes'
      yaml '''
        apiVersion: v1
        kind: Pod
        spec:
          imagePullSecrets:
          - name: harbor-admin
          volumes:
          - name: data
            nfs:
              server: 192.168.79.33
              path: /data/maven
          - name: dockersocket
            hostPath:
              path: /run/docker.sock            
              
          containers:
          - name: maven
            image: harbor.oldxu.net/ops/maven:3.8.6
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            volumeMounts:
            - name: data
              mountPath: /root/.m2
          
          - name: nodejs
            image: harbor.oldxu.net/ops/nodejs:14.20
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            
          - name: sonar
            image: harbor.oldxu.net/ops/sonar-scanner:2.3.0
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            
          - name: docker
            image: harbor.oldxu.net/ops/docker:20.10
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            volumeMounts:
            - name: dockersocket
              mountPath: /run/docker.sock
              
          - name: kubectl
            image: harbor.oldxu.net/ops/kubectl:1.18.0
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
      '''
    } // kubernetes end
  }//agent end
  
environment{
    Gitlab_Id="gitlab-root-token"
    Gitlab_Pro="http://gitlab.oldxu.net:30080/root/springboot.git"
}

  stages{
    stage('获取代码'){
        steps{
            container('maven'){
                checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: "${Gitlab_Id}", url: "${Gitlab_Pro}"]])
                sh 'pwd && ls -l'
            }
        
        }
    }
    
    stage('docker'){
        steps{
            container('docker'){
               sh 'docker ps'
            }
                
        }          
    }
        
 
  }//stages end
} //pipeline end

结果:
在这里插入图片描述

四、Pipeline流水线-漏洞扫描

4.0 本小段流程思路(1、漏洞扫描 sonarqube来实现):

				1、dns解析,slavePod需要访问sonarqube服务端;<--> jenkins  
				2、让Jenkins集成Sonarqube  ???why		sqa_01d17b84079611472bbfcf89f2a67e7556510fda
				3、sonar-scanner客户端工具; (获取这个工具的实现方式以及实现参数等等)
				4、编写Stage;

4.1 修改coredns

kubectl edit cm -n kube-system coredns

 hosts {
          192.168.79.31 gitlab.oldxu.net sonar.oldxu.net jenkins.oldxu.net
          192.168.79.32 gitlab.oldxu.net sonar.oldxu.net jenkins.oldxu.net
          192.168.79.33 gitlab.oldxu.net sonar.oldxu.net jenkins.oldxu.net
          fallthrough  
}

4.2 Jenkins集成Sonarqube

Sonarqube申请令牌 (http://sonar.oldxu.net:30080/account/security)
我的账号 -> 安全 -> 添加令牌
在这里插入图片描述
在这里插入图片描述

系统管理 -> 系统配置 -> Sonarqube
添加凭证:

在这里插入图片描述
sonarqube servers的配置:
在这里插入图片描述

4.3 sonar-scanner客户端工具

打开sonarqube网页, 项目 -> 手工
在这里插入图片描述
“分析你的项目”

#这个指令是要去到 代码路径上执行/分析
sonar-scanner \
  -Dsonar.projectKey=springboot \
  -Dsonar.sources=. \
  -Dsonar.host.url=http://sonar.oldxu.net:30080 \
  -Dsonar.login=sqa_62e525a80cecb1a6d0ebe0cafcd52c41b0e5729c

代码路径指的是:
在这里插入图片描述
在这里插入图片描述

4.4、编写Stage;

//这里与上面给复制的代码还是有几处不一样的。
    stage('代码扫描'){
        steps{
            withSonarQubeEnv('sonar-k8s'){  //对应配置中的 sonorqube servers
                container('sonar'){
                    sh 'pwd && ls -l'
                    sh 'sonar-scanner \
                        -Dsonar.projectKey=springboot \
                        -Dsonar.java.binaries=src \
                        -Dsonar.sources=.'
                }
            }
          
        }
    }

检测漏洞扫描结果,如果正常则继续、否则就终止

1、配置Sonarqube,让其将结果通知给Jenkins
						http://admin:admin123@jenkins.oldxu.net/sonarqube-webhook
						
2、编写Stage,判断Sonarqube返回的检查结果,如果ok,则继续,否则就终止步骤的执行;

http://sonar.oldxu.net:30080/admin/webhooks
sonarqube网页 -> 配置 -> 网络调用 -> 创建

名称:jenkins
URL:http://admin:admin12345@jenkins.oldxu.net:30080/sonarqube-webhook
#注意要写对URL ,不然会一直卡5分钟,然后暂停检测

在这里插入图片描述
流水线语法:waitForQualityGate
在这里插入图片描述
可根据具体情况调整“质量阈”的条件指标
在这里插入图片描述
代码:

stage('检查漏洞扫描结果'){
        steps{
            container('sonar'){
                script{
                    timeout(5){
                        def qg = waitForQualityGate()
                        if (qg.status != 'OK'){
                            error "Sonarqube 代码检查失败, error的原因 ${qg.status}"
                        }
                    }
                }
            }
        }
    }

运行结果:
在这里插入图片描述

五、Pipeline流水线-代码编译

5.0 使用maven进行编译,打包

    stage('编译代码'){
        steps{
            container('maven'){
                sh 'mvn package -Dmaven.test.skip=true'
                sh 'pwd && ls -l'
            }
        }
    
    }
        

在这里插入图片描述

六、Pipeline流水线-制作Docker镜像

6.0 本小段思路

制作Docker镜像、推送到Harbor仓库  (Dockerfile文件)
				1、配置域名解析,让SlavePod能够访问到Harbor
				2、配置凭据,确保后续在推送到Harbor仓库时,认证没有问题;
				
				3、docker build  根据dockerfilee生成Docker的镜像
				4、推送到Harbor仓库

在这里插入图片描述

6.1、配置域名解析,让SlavePod能够访问到Harbor

kubectl edit cm -n kube-system coredns
加上 192.168.79.34 harbor.oldxu.net

6.2、配置凭据,确保后续在推送到Harbor仓库时,认证没有问题;

http://jenkins.oldxu.net:30080/manage/credentials/store/system/domain/_/
Dashboard -> 系统管理 -> 凭据 -> 系统 -> 全局凭据 (unrestricted)
在这里插入图片描述
在这里插入图片描述

6.3 编写stage

3、docker build  根据dockerfilee生成Docker的镜像
4、推送到Harbor仓库

流水线语法: 加载刚才创建的harbor-auth用户名和密码
withCredentials: Bind credentials to variables -> Username and password (separated)
在这里插入图片描述

[root@master01 springboot-helloworld-master]# ls
deploy.yaml  Dockerfile  entrypoint.sh  pom.xml  push_jar.sh  README.md  src
[root@master01 springboot-helloworld-master]# git log -n1 --pretty=format:'%h'
4131cad

编写生成tag的流水线语法
在这里插入图片描述

sh returnStdout: true, script: '''git log -n1 --pretty=format:\'%h\'
#sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim()

sh returnStdout: true, script: '''date +%Y%m%d_%H%M%S
#sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim()

//注意单引号和双引号的使用

environment{
    Gitlab_Id="gitlab-root-token"
    Gitlab_Pro="http://gitlab.oldxu.net:30080/root/springboot.git"
    
    //harbor相关的全局变量
    Url = "harbor.oldxu.net"
    Pro = "base"
    ImageName = "${Url}/${Pro}/springboot"
    HARBOR_ID = "harbor-auth"
}//environment end

stage('生成镜像Tag'){
        steps{
            container('maven'){
                script{
                    //本次git提交的commid  (git log -n1 --pretty=format:'%h')
                    env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim()
                    //构件时间
                    env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim()
                    //完整的镜像Tag (c106654_20221115_133911)
                    env.ImageTag = COMMITID + "_" BuildTime
                }
                
                sh 'echo "镜像的Tag: ${ImageTag}"'
            }
        }
    }

    stage('制作docker镜像'){
        steps{
          container('docker'){
            withCredentials([usernamePassword(credentialsId: "${HARBOR_ID}", passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USER')]) {
                //登陆harbor
                sh 'echo "${HARBOR_PASSWORD}" | docker login ${Url} -u "${HARBOR_USER}" --password-stdin '
                
                // 构建 / 推送  / 删除本地镜像
                sh 'docker build -t ${ImageName}:${ImageTag} .'
                sh 'docker push ${ImageName}:${ImageTag}'
                sh 'docker rmi ${ImageName}:${ImageTag}'
            }
          }
         }
    }


运行效果:
在这里插入图片描述

七、Pipeline流水线-交付应用至K8S

7.0 本小段思路

				1、将应用交付到哪个K8S集群;  (slavepod能够与对应的集群通信就行)
				2、如何连接上对应的K8S集群;
				
				
				
				1、配置Jenkins,将config文件制作为一个Scretfile;
				2、编写Stage,在Stage引用这个config文件; 就可以操作对应的集群了;
					{namespace}
					{Image}
					{host}

		
				3、部署的名称空间需要提前创建  (k8s namespace dev)
				4、需要创建对应的Harbor认证Secrets harbor-admin  (k8s的kubectl create secret docker-registry harbor-admin )

deploy.yaml内容:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-dev
  namespace: {namespace}			#修改为{}特殊字符,后期好替换
spec:
  replicas: 3
  selector:
    matchLabels:
      app: spring-dev
  template:
    metadata:
      labels:
        app: spring-dev
    spec:
      imagePullSecrets:
      - name: harbor-admin
      containers:
      - name: springboot-dev
        image: {Image}			# 修改为{}特殊字符,后期好替换
        ports:
        - name: http
          containerPort: 8080
        env:            # 传递初始堆内存和最大堆内存占用
        - name: XMS_OPTS
          valueFrom:
            resourceFieldRef:
              resource: requests.memory
        - name: XMX_OPTS
          valueFrom:
            resourceFieldRef:
              resource: limits.memory
        resources:
          requests:
            memory: 150Mi
          limits:
            memory: 300Mi
        readinessProbe:         # 就绪探针;如果端口不存活,则从负载均衡中移除
          tcpSocket:
            port: http          # http是一个名字;它会获取这个名字对应的端口;
          initialDelaySeconds: 10
          failureThreshold: 3
        livenessProbe:          # 存活探针;获取url,状态码不对那么则触发重启操作
          httpGet:
            path: /
            port: http
          initialDelaySeconds: 10
          failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
  name: spring-dev-svc
  namespace: {namespace}
spec:
  selector:
    app: spring-dev
  ports:
  - port: 8080
    targetPort: 8080

---
#apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: springboot-ingress
  namespace: {namespace}
spec:
  ingressClassName: "nginx"
  rules:
  - host: "{host}"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          serviceName: spring-dev-svc
          servicePort: 8080
          #service:
          #  name: spring-dev-svc
          #  port:
          #    number: 8080

7.1 配置Jenkins,将config文件制作为一个Scret file;

#master节点,下载config文件
sz ~/.kube/config

Jenkins新增凭证(secret file)
http://jenkins.oldxu.net:30080/manage/credentials/store/system/domain/_/
在这里插入图片描述
流水线语法:
在这里插入图片描述

withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
    // some block
}

7.2 编写pipeline

environment{
   
    //对外暴露的域名
    Ingress_Host = "spring-dev.oldxu.net"
}//environment end

    stage('交付至k8s'){
        steps{
            container('kubectl'){
                withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
                    sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
                                     
                    //替换
                    sh 'sed  -i "s#{namespace}#dev#g" deploy.yaml'
                    sh 'sed  -i "s#{Image}#${ImageName}:${ImageTag}#g" deploy.yaml'
                    sh 'sed  -i "s#{host}#${Ingress_Host}#g" deploy.yaml'
                    sh 'cat deploy.yaml'
                    
                    sh 'kubectl apply -f deploy.yaml'
                }
            }
        }
    }

运行结果:

在这里插入图片描述
网页访问:
在这里插入图片描述

更新代码:验证再次发版:

修改代码的HomeController.java内容。
在这里插入图片描述

八、Pipeline流水线-全自动CI过程及测试

Jenkins的pipeline配置 -> 构建触发器 -> 勾上“build when a change …” ,生成secret令牌
在这里插入图片描述
高级
在这里插入图片描述

gitlab配置 开启外发请求
菜单 -> 管理员 -> 管理中心 -> 设置 -> 网络 -> 外发请求 -> 勾上两个“允许”
http://gitlab.oldxu.net:30080/admin/application_settings/network
在这里插入图片描述
springboot项目 -> 设置 -> webhook
参考地址:http://gitlab.oldxu.net:30080/root/springboot/-/hooks
在这里插入图片描述
可测试
在这里插入图片描述
在这里插入图片描述

更新代码,看看会不会触发自动发版CI
在这里插入图片描述

springboot-CI完整的pipeline代码

pipeline{
  agent{
    kubernetes{
      cloud 'kubernetes'
      yaml '''
        apiVersion: v1
        kind: Pod
        spec:
          imagePullSecrets:
          - name: harbor-admin
          volumes:
          - name: data
            nfs:
              server: 192.168.79.33
              path: /data/maven
          - name: dockersocket
            hostPath:
              path: /run/docker.sock            
              
          containers:
          - name: maven
            image: harbor.oldxu.net/ops/maven:3.8.6
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            volumeMounts:
            - name: data
              mountPath: /root/.m2
          
          - name: nodejs
            image: harbor.oldxu.net/ops/nodejs:14.20
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            
          - name: sonar
            image: harbor.oldxu.net/ops/sonar-scanner:2.3.0
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            
          - name: docker
            image: harbor.oldxu.net/ops/docker:20.10
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
            volumeMounts:
            - name: dockersocket
              mountPath: /run/docker.sock
              
          - name: kubectl
            image: harbor.oldxu.net/ops/kubectl:1.18.0
            imagePullPolicy: IfNotPresent
            command: ["cat"]
            tty: true
      '''
    } // kubernetes end
  }//agent end
  
environment{
    Gitlab_Id="gitlab-root-token"
    Gitlab_Pro="http://gitlab.oldxu.net:30080/root/springboot.git"
    
    //harbor相关的全局变量
    Url = "harbor.oldxu.net"
    Pro = "base"
    ImageName = "${Url}/${Pro}/springboot"
    HARBOR_ID = "harbor-auth"
    
    //对外暴露的域名
    Ingress_Host = "spring-dev.oldxu.net"
}//environment end

  stages{
    stage('获取代码'){
        steps{
            container('maven'){
                checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: "${Gitlab_Id}", url: "${Gitlab_Pro}"]])
                sh 'pwd && ls -l'
            }
        
        }
    }
    
    stage('代码扫描'){
        steps{
            withSonarQubeEnv('sonar-k8s'){  //对应配置中的 sonorqube servers
                container('sonar'){
                    sh 'pwd && ls -l'
                    sh 'sonar-scanner \
                        -Dsonar.projectKey=springboot \
                        -Dsonar.java.binaries=src \
                        -Dsonar.sources=.'
                }
            }
            
        }
    }
    
    stage('检查漏洞扫描结果'){
        steps{
            container('sonar'){
                script{
                    timeout(5){
                        def qg = waitForQualityGate()
                        if (qg.status != 'OK'){
                            error "Sonarqube 代码检查失败, error的原因 ${qg.status}"
                        }
                    }
                }
            }
        }
    }
    
    stage('编译代码'){
        steps{
            container('maven'){
                sh 'mvn package -Dmaven.test.skip=true'
                sh 'pwd && ls -l'
            }
        }
    }
    
    stage('生成镜像Tag'){
        steps{
            container('maven'){
                script{
                    //本次git提交的commid  (git log -n1 --pretty=format:'%h')
                    env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim()
                    //构件时间
                    env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim()
                    //完整的镜像Tag (c106654_20221115_133911)
                    env.ImageTag = COMMITID + "_" + BuildTime
                }
                
                sh 'echo "镜像的Tag: ${ImageTag}"'
            }
        }
    }
    
    stage('制作docker镜像'){
        steps{
          container('docker'){
            withCredentials([usernamePassword(credentialsId: "${HARBOR_ID}", passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USER')]) {
                //登陆harbor
                sh 'echo "${HARBOR_PASSWORD}" | docker login ${Url} -u "${HARBOR_USER}" --password-stdin '
                
                // 构建 / 推送  / 删除本地镜像
                sh 'docker build -t ${ImageName}:${ImageTag} .'
                sh 'docker push ${ImageName}:${ImageTag}'
                sh 'docker rmi ${ImageName}:${ImageTag}'
            }
          }
         }
    }
    
    stage('交付至k8s'){
        steps{
            container('kubectl'){
                withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
                    sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
                    
                    //替换
                    sh 'sed  -i "s#{namespace}#dev#g" deploy.yaml'
                    sh 'sed  -i "s#{Image}#${ImageName}:${ImageTag}#g" deploy.yaml'
                    sh 'sed  -i "s#{host}#${Ingress_Host}#g" deploy.yaml'
                    sh 'cat deploy.yaml'
                    
                    sh 'kubectl apply -f deploy.yaml'
                }
            }
        }
    }
        
 
  }//stages end
} //pipeline end

九、PipelineCD流水线-获取Harbor镜像Tag

9.0 CD阶段的思路

CD阶段:
			1、获取完整的镜像名称;   从Harbor中获取  (curl命令去获取)
			
				shell命令写出来;
				curl -s -uadmin:Harbor12345 -H'Content-Type: application/json' -X GET https://harbor.oldxu.net/v2/base/springboot/tags/list | sed -r 's#(\{.*\[)(.*)(\]\})#\2#g' | xargs -d "," -n1 | xargs -n1 | sort -t "_" -k2 -k3 -nr | head -5

				级联变量的方式来提取对应的tag;
					
					三个变量:
						Harbor_Url
						Harbor_Pro
						Image_Name
						Image_Tag
						
				def get_tag = [ "bash", "-c", "curl -s -uadmin:Harbor12345 -H 'Content-Type: application/json' -X GET https://${Harbor_Url}/v2/${Harbor_Pro}/${Image_Name}/tags/list | sed -r 's#(\\{.*\\[)(.*)(\\]\\})#\\2#g' | xargs -d ',' -n1 | xargs -n1 | sort -t '_' -k2 -k3 -nr | head -5"]

				return get_tag.execute().text.tokenize("\n")

			
			
			2、生产环境中已经是部署了对应的项目的;
			2、kubectl set image;
			3、直接部署到K8S的生产环境名称空间;
			4、询问是否需要回退;
				kubectl rollout undo deployment springboot -n prod

9.1 操作过程

安装active choices插件。 新建springboot-CD流水线,使用参数化构建过程

参数化构建过程
#1 Harbor_Url
添加参数 -> 选Active Choices Parameter
Name 填 Harbor_Url
Script -> Groovy Script 填 return ["harbor.oldxu.net","harbor-dev.oldxu.net","harbor-prod.oldxu.net"]

#2 Harbor_Pro
添加参数 -> 选Active Choices Parameter
Name 填 Harbor_Pro
Script -> Groovy Script 填 return ["base","app","springcloud","ops"]

#3 Image_Name 
添加参数 -> 选Active Choices Parameter
Name 填 Image_Name 
Script -> Groovy Script 填 return ["springboot","java","springcloud","shopping"]

在这里插入图片描述

#4 Image_Tag
添加参数 -> 选 Active Choices Reactive Parameter

Groovy Script填写:
def get_tag = [ "bash", "-c", "curl -s -uadmin:Harbor12345 -H 'Content-Type: application/json' -X GET https://${Harbor_Url}/v2/${Harbor_Pro}/${Image_Name}/tags/list | sed -r 's#(\\{.*\\[)(.*)(\\]\\})#\\2#g' | xargs -d ',' -n1 | xargs -n1 | sort -t '_' -k2 -k3 -nr | head -5"]
return get_tag.execute().text.tokenize("\n")

#
Referenced parameters框填写:Harbor_Url,Harbor_Pro,Image_Name 

在这里插入图片描述

build with parameters效果

在这里插入图片描述

编写CD - pipeline

pipeline{
    agent{
        kubernetes{
            cloud 'kubernetes'
            yaml '''
              apiVersion: v1
              kind: Pod
              spec:
                imagePullSecrets:
                - name: harbor-admin
                containers:
                - name: kubectl
                  image: harbor.oldxu.net/ops/kubectl:1.18.0
                  imagePullPolicy: IfNotPresent
                  command: ["cat"]
                  tty: true
            '''
        }
    }
    
    environment{
        Full_Image = "${Harbor_Url}/${Harbor_Pro}/${Image_Name}:${Image_Tag}"
    }//environment end
    
    stages{
        stage('输出完整的镜像名称'){
            steps{
                sh 'echo 镜像名称-tag: ${Full_Image}'
            }
            
        }
    }
    
}//pipeline end

在这里插入图片描述

十、PipelineCD流水线-部署应用至K8S生产环境

kubectl create namespace prod
kubectl create secret docker-registry harbor-admin --docker-username=admin --docker-password=Harbor12345 --docker-server=harbor.oldxu.net -n prod

先在生产环境部署 deploy-prod.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot
  namespace: prod			#修改为{}特殊字符,后期好替换
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-prod
  template:
    metadata:
      labels:
        app: spring-prod
    spec:
      imagePullSecrets:
      - name: harbor-admin
      containers:
#      - name: springboot-prod   
      - name: springboot    #注意这里的名字,要与 kubectl set images的一致
        image: harbor.oldxu.net/base/springboot:fa71353_20230521_175420			# 修改为{}特殊字符,后期好替换
        ports:
        - name: http
          containerPort: 8080
        env:            # 传递初始堆内存和最大堆内存占用
        - name: XMS_OPTS
          valueFrom:
            resourceFieldRef:
              resource: requests.memory
        - name: XMX_OPTS
          valueFrom:
            resourceFieldRef:
              resource: limits.memory
        resources:
          requests:
            memory: 150Mi
          limits:
            memory: 300Mi
        readinessProbe:         # 就绪探针;如果端口不存活,则从负载均衡中移除
          tcpSocket:
            port: http          # http是一个名字;它会获取这个名字对应的端口;
          initialDelaySeconds: 10
          failureThreshold: 3
        livenessProbe:          # 存活探针;获取url,状态码不对那么则触发重启操作
          httpGet:
            path: /
            port: http
          initialDelaySeconds: 10
          failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
  name: spring-prod-svc
  namespace: prod
spec:
  selector:
    app: spring-prod
  ports:
  - port: 8080
    targetPort: 8080
---
#apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: springboot-ingress
  namespace: prod
spec:
  ingressClassName: "nginx"
  rules:
  - host: "spring-prod.oldxu.net"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          serviceName: spring-prod-svc
          servicePort: 8080
          #service:
          #  name: spring-prod-svc
          #  port:
          #    number: 8080

在这里插入图片描述
如果dev环境没问题,则手动发布到prod环境
在这里插入图片描述
构建:
在这里插入图片描述
在这里插入图片描述

+ kubectl set image deployment/springboot springboot=harbor.oldxu.net/base/springboot:ccf31a9_20230521_213116 -n prod

9.2 对应pipeline代码:

 stage('部署应用至生产 K8S'){
            steps{
                withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
                    container('kubectl'){
                        sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
                        sh 'kubectl set image deployment/${Image_Name} ${Image_Name}=${Full_Image} -n prod'
                    }
                }
    
            
            }
        }

十一、PipelineCD流水线-应用回滚

	4、询问是否需要回退;
				kubectl rollout undo deployment springboot -n prod

流水线语法:

input message: '是否回退到上个版本', parameters: [choice(choices: ['No', 'Yes'], name: 'rollback')]

在这里插入图片描述
验证:发布与回滚
在这里插入图片描述
选择yes ,回滚
在这里插入图片描述

+ kubectl rollout undo deployment springboot -n prod

在这里插入图片描述

springboot-CD的完整代码

pipeline{
    agent{
        kubernetes{
            cloud 'kubernetes'
            yaml '''
              apiVersion: v1
              kind: Pod
              spec:
                imagePullSecrets:
                - name: harbor-admin
                containers:
                - name: kubectl
                  image: harbor.oldxu.net/ops/kubectl:1.18.0
                  imagePullPolicy: IfNotPresent
                  command: ["cat"]
                  tty: true
            '''
        }
    }
    
    environment{
        Full_Image = "${Harbor_Url}/${Harbor_Pro}/${Image_Name}:${Image_Tag}"
       
    }//environment end
    
    stages{
        stage('输出完整的镜像名称'){
            steps{
                sh 'echo 镜像名称-tag: ${Full_Image}'
           

            }
            
        }
        
        stage('部署应用至生产 K8S'){
            steps{
                withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
                    container('kubectl'){
                        sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
                        sh 'kubectl set image deployment/${Image_Name} ${Image_Name}=${Full_Image} -n prod'
                    }
                }
    
            
            }
        }
        
        stage('快速回滚'){
            steps{
              withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
                container('kubectl'){
                    script{
                        timeout(time: 1, unit: 'HOURS'){
                            def UserInput = input message: '是否回退到上个版本', parameters: [choice(choices: ['No', 'Yes'], name: 'rollback')]
                            if (UserInput == "Yes"){
                               sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
                               sh 'kubectl rollout undo deployment $Image_Name -n prod'
 
                            }
                            
                        }
                    }
                }
              }

            }
        }
        
    }//stages end
       
}//pipeline end

END 5.8~5.21 ELK+CICD

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值