云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

时间:2022-10-09 13:55:39

使用Jenkins自动化更新项目到K8S集群的方式

在前面的文章中,已经将know-system项目通过流水线自动化的打包成了Docker镜像,接下来,我们需要将这个镜像自动化的发布到K8S集群,完成项目的上线。

使用Jenkins自动化更新项目到K8S集群的方式

  • 1.将资源yaml文件也上传到代码仓库,项目打完镜像后,可以通过替换deployment资源我们指定image的字符串,把最新版本的镜 像替换到deployment资源中,最后执行kubectl apply -f ./完成更新。

  • 2.执行kubectl 命令更新deployment资源的镜像。

接下来会分别演示两种更新方式的pipeline流水线脚本的编写。

由于我们构建任务都是通过agent去运行的,agent部署在k8s node节点,继承了docker、kubectl命令,因此不必担心kubectl命令不能用。

一、针对项目有YAML编排文件的情况下编写的Pipeline脚本

1.实现思路

1.首先将know-system在k8s中进行部署,实现可以访问的状态。

2.将部署know-system的yaml文件复制到代码目录中,并将deployment资源中容器image对应的镜像改成一个字符串,这样pipeline更新时可以通过更换这个字符串,把最新的镜像版本替换到deployment资源中完成更新,最后将代码及部署文件推送到gitlab。

3.优化pipeline脚本,增加k8s部署步骤。

4.更新代码,使用流水线更新项目到k8s。

2.将know-system项目在K8S集群中部署

1)准备项目yaml文件

1.准备deployment资源
[root@k8s-master1 know-system]# cat nginx-depoly.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: know-system
  namespace: know-system
spec:
  replicas: 3
  selector:
    matchLabels:
      app: know-system
  template:
    metadata:
      labels:
        app: know-system
    spec:
      containers:
      - name: nginx
        image: harbor.jiangxl.com/project/nginx-project:v1-code
        ports:
        - containerPort: 80
        volumeMounts:
        - name: nginx-data
          mountPath: /data/code
        - name: nginx-config
          mountPath: /data/nginx/conf/conf.d/
      volumes:
        - name: nginx-config
          configMap:
            name: nginx-configmap
        - name : nginx-data
          persistentVolumeClaim:
            claimName: pvc-know
            readOnly: false

2.准备configmap资源
[root@k8s-master1 know-system]# cat nginx-configmap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-configmap
  namespace: know-system
data:
  know.jiangxl.com.conf: |
    server {
      listen 80;
      server_name know.jiangxl.com;
      location / {
        root /data/code/know_system;
        index index.html;
      }
    }

3.准备svc资源
[root@k8s-master1 know-system]# cat nginx-svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: know-system
spec:
  selector:
    app: know-system
  type: NodePort
  ports:
  - port: 80		
    targetPort: 80

2)创建所有资源

[root@k8s-master1 know-system]# kubectl apply -f ./
configmap/nginx-configmap unchanged
deployment.apps/know-system configured
service/nginx-service configured

3)查看项目首页

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

3.将项目的YAML编排文件上传到Gitlab中

1.将部署文件复制到代码目录
[root@k8s-master1 know_system]# mkdir deploy
[root@k8s-master1 know_system]# cp /root/k8s1.19/know-system/* deploy/

2.修改deployment资源中的image
#将image对应的镜像改成一个字符串,pipeline更新时可以通过更换这个字符串把最新的镜像替换到deployment资源中
[root@k8s-master1 know_system]# vim deploy/nginx-depoly.yaml 
        image: {{updateimage}}

2.提交至gitlab
[root@k8s-master1 know_system]# git add .
[root@k8s-master1 know_system]# git commit -m "deploy"
[root@k8s-master1 know_system]# git push origin master

4.编写Pipeline流水线脚本将项目更新到K8S

pipeline {
    agent { label 'Jenkins-slave1-107' }                //让该pipeline始终运行在Jenkins-slave1-107 Jenkins agent节点上,因为这个节点所在的服务器可以运行k8s集群的docker、kubelet命令

    environment {                                   //environment主要用于定义环境变量,可以把一些常用到的值做成环境变量
        IMAGE_REPO="harbor.jiangxl.com/project"
    }

	parameters {                               //定义参数化构建流程
		gitParameter(name: 'VERSION',defaultValue: 'master',type: 'BRANCH',description: '选择要更新的分支')             //定义一个gitparamters参数化构建过程,用于选择更新的代码
		string(name: 'project',defaultValue: 'know-system',description: '项目名称',trim: true)                  //定义一个空白字符串,声明项目名称
	}	
    stages {                        //定义pipeline执行阶段
        stage('运维确认信息') {                                 //阶段1,使用一个交互式,让运行确认更新信息,如果有误可直接退出更新,避免更新错误
            steps {
                input message: """                          
                jobname: ${project}
                branch: ${VERSION}""", ok: "更新"                       //交互式输出一个更新的项目和分支号
            }
        }
        stage('拉取项目代码') {                                  //阶段2,用于拉取git上对应的项目代码
            steps {
				checkout([$class: 'GitSCM', branches: [[name: '$VERSION']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root', url: 'http://192.168.16.106:30080/root/know_system.git']]])
            }
        }  
        stage('构建项目镜像') {			                        //阶段3.用于将项目代码更新到docker初始镜像中,主要步骤就是生产一个dockerfile,将代码复制到镜像中,最后根据Dockerfile构建出镜像
            steps {
				sh """              
                pwd
				echo "
FROM harbor.jiangxl.com/project/nginx-project:v1-code

RUN mkdir /data/code/know_system
COPY  ./* /data/code/know_system/
EXPOSE 80
				" >Dockerfile
				"""                             //编写一个Dockerfile,定义初始镜像,并将更新的代码复制到容器的指定路径

 				sh 'docker build -t ${IMAGE_REPO}/${project}:master-v${BUILD_ID} .'		//最终镜像的名称就是harbor.jiangxl.com/project/know-system:master-v1                
            }
        }   

        stage('推送镜像到harbor仓库') {             //阶段4,将构建好的镜像推送至harbor仓库中,便于k8s拉取更新程序
            steps {
 				sh 'docker push ${IMAGE_REPO}/${project}:master-v${BUILD_ID}'		//推送镜像到harbor仓库
            }
        }           
        stage('将项目更新到k8s') {                     //阶段5,主要是更新k8s中项目使用的容器,将最新构建的镜像替换到项目pod中,然后更新pod
            steps {                                     //使用kubectl命令更新项目
 				sh "sed -i 's#{{updateimage}}#${IMAGE_REPO}/${project}:master-v${BUILD_ID}#g' deploy/*"		    //将deployment资源中我们写死的镜像版本字符串,替换成刚刚推送至harbor仓库的镜像版本
                sh 'kubectl apply -f deploy/'                   //当镜像版本替换后,更新资源的yaml文件即可完成项目更新
            }
        }                  
    }
    post {
    	success {				//构建成功了发送一个构成成功的消息到钉钉
    			echo "构建成功,发送消息到钉钉"
    			sh """
    			curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
 -H 'Content-Type: application/json' \
 -d '{"msgtype": "text","text": {"content":"????????构建成功????????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
    			"""
    	}
    	failure {				//构建失败了发送一个构成成功的消息到钉钉
    			echo "构建失败,发送消息到钉钉"
    			sh """
    			curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
 -H 'Content-Type: application/json' \
 -d '{"msgtype": "text","text": {"content":"????❌构建失败❌????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
 				"""
    	}
    	always {					//无论成功还是失败都执行此步骤
    		echo "构建流程结束"
    	}
    }
}

5.将Pipeline脚本粘贴到流水线任务中

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

6.构建master分支完成项目上线

1)选择更新信息

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

2)运维确认信息

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

3)pipeline任务更新成功

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

4)在blue ocean查看此次更新的镜像版本

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

5)在rancher上观察项目是否更新成最新的镜像版本

更新流程顺利完成!

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

二、针对K8S集群中的项目没有编排文件的Pipeline编写

1.实现思路

1.基于a中的pipeline脚本,多增加几个参数化构建string类型的构建流程,声明项目所在的namespace、项目使用的资源控制器类型、项目使用的容器名称。

2.通过kubectl set image方式更新资源镜像,其中需要指定项目所在的namespace、资源控制器类型、容器名称,由于这些值将来可能会发生变化,因此就需要通过参数化构建形成以变量方式来调度。

2.编写Pipeline流水线脚本

pipeline {
    agent { label 'Jenkins-slave1-107' }                //让该pipeline始终运行在Jenkins-slave1-107 Jenkins agent节点上,因为这个节点所在的服务器可以运行k8s集群的docker、kubelet命令

    environment {                                   //environment主要用于定义环境变量,可以把一些常用到的值做成环境变量
        IMAGE_REPO="harbor.jiangxl.com/project"
    }

	parameters {                               //定义参数化构建流程
		gitParameter(name: 'VERSION',defaultValue: 'master',type: 'BRANCH',description: '选择要更新的分支')             //定义一个gitparamters参数化构建过程,用于选择更新的代码
		string(name: 'project_namespace',defaultValue: 'know-system',description: '项目所在的命名空间',trim: true)               //声明项目所在的命名空间
        string(name: 'project_kind',defaultValue: 'deployment',description: '项目资源所使用的pod控制器',trim: true)             //声明项目资源使用的pod控制器类型
        string(name: 'container_name',defaultValue: 'nginx',description: '项目所使用的pod容器名称',trim: true)                  //声明项目使用pod的容器名称
        string(name: 'project',defaultValue: 'know-system',description: '项目名称',trim: true)                                       //声明项目名称
	}	
    stages {                        //定义pipeline执行阶段
        stage('运维确认信息') {                                 //阶段1,使用一个交互式,让运行确认更新信息,如果有误可直接退出更新,避免更新错误
            steps {
                input message: """                          
                jobname: ${project}
                branch: ${VERSION}""", ok: "更新"                       //交互式输出一个更新的项目和分支号
            }
        }
        stage('拉取项目代码') {                                  //阶段2,用于拉取git上对应的项目代码
            steps {
				checkout([$class: 'GitSCM', branches: [[name: '$VERSION']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root', url: 'http://192.168.16.106:30080/root/know_system.git']]])
            }
        }  
        stage('构建项目镜像') {			                        //阶段3.用于将项目代码更新到docker初始镜像中,主要步骤就是生产一个dockerfile,将代码复制到镜像中,最后根据Dockerfile构建出镜像
            steps {
				sh """              
                pwd
				echo "
FROM harbor.jiangxl.com/project/nginx-project:v1-code

RUN mkdir /data/code/know_system
COPY  ./* /data/code/know_system/
EXPOSE 80
				" >Dockerfile
				"""                             //编写一个Dockerfile,定义初始镜像,并将更新的代码复制到容器的指定路径

 				sh 'docker build -t ${IMAGE_REPO}/${project}:master-v${BUILD_ID} .'		//最终镜像的名称就是harbor.jiangxl.com/project/know-system:master-v1                
            }
        }   

        stage('推送镜像到harbor仓库') {             //阶段4,将构建好的镜像推送至harbor仓库中,便于k8s拉取更新程序
            steps {
 				sh 'docker push ${IMAGE_REPO}/${project}:master-v${BUILD_ID}'		//推送镜像到harbor仓库
            }
        }           
        stage('将项目更新到k8s') {                     //阶段5,主要是更新k8s中项目使用的容器,将最新构建的镜像替换到项目pod中,然后更新pod
            steps {                                     //由于项目是通过rancher创建,没有任何yaml文件,因此通过使用kubectl命令更新项目
                sh 'kubectl -n ${project_namespace} set image ${project_kind} ${project} ${container_name}=${IMAGE_REPO}/${project}:master-v${BUILD_ID} --record'                 //通过kubectl命令升级控制器所使用的镜像版本,kubectl -n 命名空间 set image 控制器类型 控制器名称 容器名称=新的镜像版本
            }
        }                  
    }
    post {
    	success {				//构建成功了发送一个构成成功的消息到钉钉
    			echo "构建成功,发送消息到钉钉"
    			sh """
    			curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
 -H 'Content-Type: application/json' \
 -d '{"msgtype": "text","text": {"content":"????????构建成功????????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
    			"""
    	}
    	failure {				//构建失败了发送一个构成成功的消息到钉钉
    			echo "构建失败,发送消息到钉钉"
    			sh """
    			curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
 -H 'Content-Type: application/json' \
 -d '{"msgtype": "text","text": {"content":"????❌构建失败❌????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
 				"""
    	}
    	always {					//无论成功还是失败都执行此步骤
    		echo "构建流程结束"
    	}
    }
}

3.将Pipeline脚本复制到Jenkins中

粘贴进去之后,首先先运行一下任务,让pipeline中定义的参数化构建生效。
云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

4.构建master分支完成项目更新

1)填写好项目信息开始构建

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

2)运维确认信息

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

3)项目更新成功钉钉消息也已经发送

此次更新的镜像版本号是53

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

4)查看rancher上项目是否成功更新到53

项目更新成功

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群

5.查看blue ocean上的流程展示

云原生DevOps篇:使用Pipeline流水线将know-system项目自动化发版到Kubernetes集群