springboot test_K8S+Jenkins实现SpringBoot项目CI/CD

59294223ba1704bd1e9bc4b876779714.png

Jenkins master位于k8s集群外,实现jenkins slave的动态构建、 k8s+jenkins中使用自定义maven镜像 两篇文章实现了K8S+Jenkins+Maven基础环境,通过此环境我们进一步实现SpringBoot项目的CI/CD。

K8S+Jenkins+Maven基础环境目前能够实现:

  1. Jenkins slave在K8S集群内的动态构建;
  2. Maven实现编译、打包、构建镜像并push到远程docker仓库;

剩下的工作需在Jenkins流水线中调用kubectl 命令实现SpringBoot项目在K8S中部署了。

要想Jenkins能够调用kubectl命令,需要安装相关插件,下面我们来介绍下。

Kuberntes相关插件

Jenkins中有两个插件可以实现与Kubernetes进行交互。

一、Kubernetes CLI

此插件允许在Jenkins Job中通过kubectl与k8s集群进行交互,主要是通过kubectl执行各种命令。

1.安装Kubernetes CLI插件

2.通过"Snippet Generator"生成指令

1d53f63d2fa324ab76c5d9263e565e57.png

通过"withKubeConfig: Configure Kubernetes CLI"来使用插件:

  • Credentials:使用前面文章在devops命令空间中的sa--jenkins
  • Kubernetes server endpoint:k8s api server;
  • Namespace:需要执行命令的命名空间;

3.添加需要执行的命令

withKubeConfig(caCertificate: '', clusterName: '', contextName: '', credentialsId: 'k8s-jenkins-slave', namespace: 'test', serverUrl: 'https://192.168.3.217:6443') {    // 自定义指定块    sh "kubectl get pod" }

4.执行流水线

pipeline {  agent {      label 'jenkins-slave-k8s'  }  stages {    stage('check out') {        steps{            git credentialsId: 'c69c70fd-98b8-4efd-9a3a-03e107260', url: 'https://xx.xx.com/helloworld.git'        }    }    stage('maven打包') {        steps {            container('maven') {                sh """                    mvn -version                """          }      }    }    stage('部署') {        steps {            withKubeConfig(caCertificate: '', clusterName: '', contextName: '', credentialsId: 'k8s-jenkins-slave', namespace: 'test', serverUrl: 'https://192.168.3.217:6443') {                // 自定义指令块                sh "kubectl get pod"             }        }    }  }}
b9af555078bebf54ce37962a25e60d78.png

由此可见,通过此插件可以在k8s中执行任何命令。

注意:

  1. 插件使用的认证server account:jenkins ,绑定的是cluster-admin角色,因此可以不同的namespace中执行命令。
  2. 如果构建过程中报错:"kubectl: not found",需从宿主机挂载kubectl命令。
f48b34d9b15d5cd7e49e80285baf7b69.png

二、Kubernetes Continuous Deploy

此插件用于将资源配置文件部署到k8s集群,主要是应用yaml配置文件。

1.安装Kubernetes Continuous Deploy插件

2.添加凭据

869c69c7fa42fe1afaa1b5176112c8c3.png

"Content"中的内容为"/root/.kube/config"内容,直接拷贝即可。

3.通过"Snippet Generator"生成指令

17c7a41ccacf37876a513750b734902d.png

通过"kubernetesDeploy: Deploy to Kubernetes"来具体使用插件:

  • Kubeconfig:使用上面创建的凭据;
  • Config Files:"kubectl apply -f" 所使用的yaml配置文件,如helloworld.yaml,具体位置可根据实际情况填写;
  • Kubernetes Namespace for secret:harbor仓库密钥所在的命名空间;
  • Secret Name:harbor仓库使用的secret;

注意:pod中的容器镜像存在于自建的远程harbor仓库,拉取镜像时需要进行认证,在k8s中我们将此密码在k8s以secret形式存放。

4.添加需要执行的命令

kubernetesDeploy configs: 'helloworld.yaml', kubeconfigId: 'k8s-cd-plugin', secretName: 'harbor', secretNamespace: 'test', ssh: [sshCredentialsId: '*', sshServer: ''], textCredentials: [certificateAuthorityData: '', clientCertificateData: '', clientKeyData: '', serverUrl: 'https://']#简化kubernetesDeploy configs: 'helloworld.yaml', kubeconfigId: 'k8s-cd-plugin', secretName: 'harbor', secretNamespace: 'test'

通过以上两个插件的简单使用对比,我选择"Kubernetes Continuous Deploy"插件进行部署,毕竟所有的资源都是以yaml来描述的;而"Kubernetes CLI"插件可以用来做一些具体的命令执行。

SpringBoot部署

K8S部署Springboot项目 一文我们已经实现了SpringBoot项目在K8S中部署,再结合Jenkins 的 “Kubernetes Continuous Deploy”插件,就可以打通K8S+Jenkins了。

在正式部署前,我们首先思考下以下几个问题:

  • 一份yaml文件如何适配测试、生产等多个环境?
  • yaml文件与源码一块托管在git中,如何避免运维因修改yaml导致的git冲突?

由于不同的环境依赖不同的hosts、JAVA_OPTS,也就意味着无法使用一份yaml匹配多环境。因此我希望放到git中的yaml最好是一个固定的模板文件,在流水线中通过环境变量的形式适配不同的环境。参考SpringBoot的分环境加载配置文件的功能,我们也将yaml按环境分配,如下:

# 生产环境helloworld-prod.yaml# 测试环境helloworld-test.yaml

在流水线中只需将JAVA_OPTS、镜像tag传递到模板中即可。

一、yaml配置文件

首先我们需要一份由Deployment、service、ingress组成的yaml文件,用于描述SpringBoot项目。在K8S部署Springboot项目 一文中为方便演示,我们将其分别拆分,但在生产中,我们需要将其合并为一个文件,便于统一管理。

注意:由于我们从模板生成最终的yaml,在此我们看模板配置文件。

# 以测试模板配置文件为例# vim helloworld-test.tplapiVersion: apps/v1kind: Deploymentmetadata:  name: helloworld  namespace: testspec:  replicas: 1  selector:    matchLabels:      app: helloworld  template:    metadata:      name: helloworld      labels:        app: helloworld    spec:      # hosts解析      hostAliases:        - ip: "10.11.10.11"          hostnames:           - "api1.test.cn"          - "api2.test.cn"        - ip: "10.11.10.12"          hostnames:           - "api3.test.cn"      containers:        - name: helloworld          # 环境变量          env:            - name: JAVA_OPTS              value: {JAVA_OPTS}          # 镜像tag          image: harbor.test.cn/helloworld/helloworld:{tag}          imagePullPolicy: IfNotPresent          livenessProbe:            httpGet:              path: /              port: 8080            initialDelaySeconds: 60            timeoutSeconds: 5          readinessProbe:            httpGet:              path: /              port: 8080            initialDelaySeconds: 60            timeoutSeconds: 5          ports:            - containerPort: 8080          resources:            limits:              cpu: "0.5"              memory: "500Mi"            requests:              cpu: "0.5"              memory: "500Mi"          volumeMounts:            - name: logdir              mountPath: /logs            - name: localtime              mountPath: /etc/localtime            - name: timezone              mountPath: /etc/timezone      imagePullSecrets:        - name: harbor      volumes:        - name: logdir          emptyDir: {}        - name: localtime          hostPath:            path: /etc/localtime        - name: timezone          hostPath:            path: /etc/timezone---apiVersion: v1kind: Servicemetadata:  name: helloworld  namespace: testspec:  type: NodePort  selector:    app: helloworld  ports:    - port: 8080      targetPort: 8080---apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: helloworld  namespace: testspec:  rules:    - host: hello.test.cn       http:        paths:          - path: /            backend:              serviceName: helloworld              servicePort: 8080

模板文件中我们设置了JAVA_OPTS、镜像tag变量,经流水线传递具体参数后,将生成最终的helloworld-test.yaml文件,以便"Kubernetes Continuous Deploy"插件调用。

二、流水线配置

Jenkins新建流水线项目并添加以下流水线:

pipeline {    agent {        label 'jenkins-slave-k8s'    }    environment {        branch = "test"        JAVA_OPTS = "-Xmx128m -Xms128m -Dspring.profiles.active=${branch}"    }    stages {      stage('check out') {          steps{              git branch: 'test', credentialsId: 'c69c23sdfd-98b8-4efd-9a3a-03e1073sdf260', url: 'https://xx.xx.com/helloworld.git'          }      }      stage('maven打包') {          steps {              container('maven') {                  sh """                      #获取git版本作为镜像tag                      tag=`git rev-parse HEAD`                      echo $tag                      mvn clean package docker:build -DdockerImageTags=$tag -Dmaven.test.skip=true -DpushImageTag                      #从模板生成最终yaml文件                      sed -e "s#{tag}#$tag#g;s#{JAVA_OPTS}#${JAVA_OPTS}#g" helloworld-test.tpl > helloworld-test.yaml                  """            }        }      }      stage('测试部署') {          when {              environment name: 'branch', value: 'test'          }          steps {              kubernetesDeploy configs: 'helloworld-test.yaml', kubeconfigId: 'k8s-cd-plugin', secretName: 'harbor', secretNamespace: 'test'          }      }    }}

要点:

  • 通过environment传递JAVA_OPTS变量;
  • 镜像tag无法通过获取环境变量GIT_COMMIT,因此只能通过命令获取;
  • 通过when来匹配不同环境的部署,由于不是多分支流水线,因此不能使用when { branch: 'test'},但能通过environment进行匹配判断;

最终部署结果如下:

a93d4326a32402076d553edd761883e5.png

如图:Jenkins的"Kubernetes Continuous Deploy"插件直接应用的yaml,如果换成"Kubernetes CLI"则需要执行"kubectl apply -f helloword-test.yaml",大家可根据自己的习惯选择不同的插件。

三、回滚

"kubectl apply -f helloword-test.yaml" 是一个滚动升级的过程,即当readinessProbe探针检查正常后才会加入到service的Endpoints提供服务;最终原来的pod将会被终止、删除。

既然滚动升级可以了,我们再来尝试下回滚:

# 查看deployment# kubectl get deploy -n testNAME                  READY   UP-TO-DATE   AVAILABLE   AGEhelloworld            1/1     1            1           4d18h# 查看版本历史,默认保存10个最近版本。# kubectl rollout history deploy helloworld -n testdeployment.apps/helloworld REVISION  CHANGE-CAUSE2         3         4         5         6         7         8         9         # 回滚至上一版本# kubectl rollout undo deploy/hellworlddeployment.apps/helloworld rolled back# 回滚指定版本# kubectl rollout undo deploy/hellworld --to-revision=3

总结

为实现整个SpringBoot项目CI/CD的整个过程,因文章篇幅问题,我们从基础环境的准备到本文分别总结了4篇文章,另外3篇为:

Jenkins master位于k8s集群外,实现jenkins slave的动态构建

k8s+jenkins中使用自定义maven镜像

K8S部署Springboot项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值