K8S搭建DevOps环境二

K8S搭建DevOps环境二

  • Jenkins Pipeline介绍
    • 说明
    • 谁在工作?
    • 流程
  • 使用Pipeline构建JAVA项目
    • 创建java项目
  • jenkins文件说明
    • agent
      • 参数化构建
      • 环境参数配置
      • pipeline 阶段步骤
        • 代码拉取
        • 代码扫描检查和测试
        • 构建和推送镜像
        • 推送lastest到仓库
        • 部署到测试环境
        • 版本镜像推送
        • 是否部署到生产环境
    • 创建jenkins部署项目
      • 参数化配置
      • 构建触发器-Gitee Webhook 配置
      • 流水线
    • 构建

Jenkins Pipeline介绍

说明

上篇文章已经初步搭建起来了DevOps环境了,并且创建了一个简单的项目进行演示了,这篇文章就真正的部署一个java的项目,来演示下一套完整的DevOps的流程是怎么样的,这里只演示一个简单的流程,项目也简单,就是一个spring boot的简单应用,流程如下:

1、创建一个spring boot项目,编写代码、jenkinsfile文件、Dockfile文件; 2、代码写好以后上传到gitee上;
3、在jenkins上创建流水线项目,通过pipeline来构建整个流程。

谁在工作?

K8S搭建DevOps环境二_第1张图片
一个大体的流程入上图:
jenkins作为一个pod在k8s上运行,所有的任务都是由jenkins的master进行编排,流水线的编排工作也是在master上,当构建启动以后,会在对应的节点将创建一个slave的pod容器,这个pod容器作为jenkins的slave容器,可以使用宿主机的k8s客户端命令,也就是kubectl **命令,而整个构建过程是需要挂载的,比如说下载的代码放哪里?mavn的依赖包放哪里?所有需要有挂载,我这里一直使用的nfs,nfs在之前的文章中已经写了如何创建。
完整的流程如下:

  1. Git content(源码清单管理)
    a) Source code(编写代码)
    b) Jenkinsfile/Dockerfile/Deploy yaml(编写dockerfile jenkins pipeline等文件) 1 . Git repository(代码管理仓库,有三种)
    a) GitHub
    b) Gitee
    c) GitLab
  2. Docker registry-Images(镜像管理)
    a) Docker Hub
    b) Aliyun Hub c) Private
  3. K8s – deploy enviroment(pod容器管理)
    a) Testing
    b) Productions

每一个都需要相应的用户名和密码进行连接,需要在 jenkins 进行配置
大体步骤: General(基础配置)–》源码管理–》构建触发器–》构建环境–》构建–》构建

流程

K8S搭建DevOps环境二_第2张图片
开发人员把做好的 devops-java-sample 项目代码通过 git 推送到 gitee,然后 Jenkins 通过 gitee webhook下来,(前提是配置好),自动从拉取 gitee 上面拉取代码然后进行 build,编译、生成镜像、然后把镜像推送到 Harbor 仓库;然后在部署的时候通过 k8s 拉取 Harbor 上面的代码进行创建容器和服务,最终发布完成,然后可以用外网访问。(ps:看着我讲这么简单,但心里有许多小鹿在心里乱撞,没关系,下面将会好好的分享给大家)当然啦,上面只是粗略的,请看下图才更加形象。
K8S搭建DevOps环境二_第3张图片

使用Pipeline构建JAVA项目

创建java项目

我这里java项目已经提前创建好了,反正就是在idea中很简单的创建了一个java项目,项目gitee地址为:

https://gitee.com/scjava/devops-demo.git

项目如下:
K8S搭建DevOps环境二_第4张图片
deploy:是该项目的deployment文件,就是当镜像推送到仓库成功以后,创建部署的yaml文件目录
src:是源码文件,很简单,就一个启动类和一个controller
Dockerfile:docker 的build文件,当源码从gitee上拉取下来以后打包成jar过后,build镜像的时候的文件;
jenkinsfile:jenkins的流水线文件
比较重要的文件就这么几个,代码很简单,就写了一个Controller,内容如下:
K8S搭建DevOps环境二_第5张图片

jenkins文件说明

这把重点说下jenkins的流水线文件,可能初学者不是很清楚这个jenkins文件编写语法,文件内容如下:
下面将会对其进行分段说明

pipeline {

  agent {
   label 'maven'
  }
    
   parameters { 
        string(name: 'TAG_NAME',defaultValue: '1.3',description: '')
        choice choices: ['devops-java-sample', 'gateway', 'order', 'product'], name: 'APP_NAME'
    }

    environment {
        DOCKER_CREDENTIAL_ID = 'aliyun-register'
        GITEE_CREDENTIAL_ID = 'GITEE'
        KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
        REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
        DOCKERHUB_NAMESPACE = 'bml-services'
        GITEE_ACCOUNT = 'scjava'
        BRANCH_NAME = 'master'
        }

    stages {
        stage ('checkout scm') {
            steps {
               // checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitee-id', url: 'https://gitee.com/liuyik8s/devops-java-sample.git']]])
               sh 'pwd'
               sh  'sleep 2'
            }
        }
 
        stage('checking'){
            steps {
                sh '''
                pwd
                echo "webhook"
                echo "webhook"
                ls -l
                sleep 2
                echo "$[app]"
                '''
            }    
      }

        stage('Unit Testing'){
          steps {
            echo "Unit Testing..."
          }
    }
    
       stage ('unit test') {
            steps {
                container ('maven') {
     //              sh 'mvn clean  -gs `pwd`/configuration/settings.xml test'
                }
            }
        }
 
        stage ('build & push') {
            steps {
                container ('maven') {
                    sh 'mvn  -Dmaven.test.skip=true -gs `pwd`/configuration/settings.xml clean package'
                    sh 'sleep 1'
                    sh 'env'
                    sh 'ls -l target'
                    sh 'docker build -f Dockerfile-online -t $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME .'
                    withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$DOCKER_CREDENTIAL_ID" ,)]) {
                        sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
                        sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME'
                    }
                }
            }
        }
    
        stage('push latest'){
           when{
             branch 'master'
           }
           steps{
                container ('maven') {
                  sh 'docker tag  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest '
                  sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest '
                }
           }
       }
      
       stage('deploy to dev') {
          when{
            branch 'master'
          }
          steps {
             container ('maven'){
       //     input(id: 'deploy-to-dev', message: 'deploy to dev?')
              sh "ls -l deploy/dev-ol"
              sh "sleep 1"
              sh "ls -l deploy/dev-ol"
              sh "cat deploy/dev-ol/*.yaml"
              sh "sleep 1"
             
             sh '''
             echo "changing parameter"
             cp deploy/dev-ol/devops-sample.yaml k8s.yaml
             
             sed -i "s#TAG_NAME#$BUILD_NUMBER#g" k8s.yaml
             sed -i "s#REGISTRY#$REGISTRY#g" k8s.yaml
             sed -i "s#DOCKERHUB_NAMESPACE#$DOCKERHUB_NAMESPACE#g" k8s.yaml
             sed -i "s#APP_NAME#$APP_NAME#g" k8s.yaml
             sed -i "s#BRANCH_NAME#$BRANCH_NAME#g" k8s.yaml

             '''
           //  sh 'kubectl delete -f k8s.yaml -n testing'
             sh "sleep 10"
             sh "cat k8s.yaml"
             sh 'kubectl apply -f k8s.yaml -n testing'
           }
          }
        }

        stage('push with tag'){
          
            steps {
              container ('maven') {
         //       input(id: 'release-image-with-tag', message: 'release image with tag?')
//                   withCredentials([usernamePassword(credentialsId: "$GITEE_CREDENTIAL_ID", passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
//                     sh 'git config --global user.email "[email protected]" '
//                     sh 'git config --global user.name "[email protected]" '
//                     sh 'git tag -a $TAG_NAME -m "$TAG_NAME" '
//                     sh 'git push http://$GIT_USERNAME:[email protected]/$GITEE_ACCOUNT/$APP_NAME.git --tags --ipv4'
//                     }
            
                  sh 'docker tag  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME '
                  sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME '
               }
           }
        }
 
       stage('deploy to production') {
       
          steps {
           container ('maven') {
            input(id: 'deploy-to-production', message: 'deploy to production?')
           // sh 'kubectl delete -f k8s.yaml -n production'
             sh "env"
             sh "sleep 10"
             sh "cat k8s.yaml"
             sh 'kubectl apply -f k8s.yaml -n production'
          }
        }
     }

    }


}

agent

agent {
   label 'maven'
  }

这个是在jenkins的云配置上配置的那个容器的标签,我们取名是maven,忘记的可以去看下上篇文章

参数化构建

parameters { 
     string(name: 'TAG_NAME',defaultValue: '1.3',description: '')
     choice choices: ['devops-java-sample', 'gateway', 'order', 'product'], name: 'APP_NAME'
 }

这里的意思是说进行参数化构建,比如说应用名称和应用版本,这个根据自身应用需要进行配置,上面配置了两个参数,一个是文本参数,一个范围参数,就是可以构造的时候可以自由选择,并且设置了默认值

环境参数配置

environment {
    DOCKER_CREDENTIAL_ID = 'aliyun-register'
    GITEE_CREDENTIAL_ID = 'GITEE'
    KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
    REGISTRY = 'registry.cn-hangzhou.aliyuncs.com'
    DOCKERHUB_NAMESPACE = 'bml-services'
    BRANCH_NAME = 'master'
    }

DOCKER_CREDENTIAL_ID :配置的阿里云的id,这个id是jenkins上配置凭证里面自己设置的ID;
GITEE_CREDENTIAL_ID :类似,就是在jenkins上配置的gitee的ID;
KUBECONFIG_CREDENTIAL_ID: K8S配置ID REGISTRY :镜像仓库地址 DOCKERHUB_NAMESPACE
:阿里云仓库的命名空间 BRANCH_NAME:gitee的分支名称

pipeline 阶段步骤

代码拉取
stage ('checkout scm') {
    steps {
       // checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitee-id', url: 'https://gitee.com/liuyik8s/devops-java-sample.git']]])
       sh 'pwd'
       sh  'sleep 2'
    }
}

这里我注释了,因为代码拉取的我让jenkins上配置的去做,待会儿就可以看到,如果说代码拉取这些要pipeline来做,也可以在脚本上写,反正都是可以的。

代码扫描检查和测试
stage('checking'){
      steps {
          sh '''
          pwd
          echo "webhook"
          echo "webhook"
          ls -l
          sleep 2
          echo "$[app]"
          '''
      }    
}
 stage('Unit Testing'){
      steps {
        echo "Unit Testing..."
      }
}

我这里只是模拟代码扫描,扫描是否有bug,根据需要进行,我这里模拟过程,这里可以将一些单元测试攻击和代码扫描攻击集成进来,然后编写脚本进行执行

构建和推送镜像
stage ('build & push') {
    steps {
        container ('maven') {
            sh 'mvn  -Dmaven.test.skip=true -gs `pwd`/configuration/settings.xml clean package'
            sh 'sleep 1'
            sh 'env'
            sh 'ls -l target'
            sh 'docker build -f Dockerfile-online -t $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME .'
            withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$DOCKER_CREDENTIAL_ID" ,)]) {
                sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
                sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME'
            }
        }
    }
}

1、mvn编译代码成jar
2、docker build成镜像;
3、docker login到镜像仓库;
4、docker本地打个标签,然后推送版本到镜像仓库;

推送lastest到仓库
stage('push latest'){
    when{
      branch 'master'
    }
    steps{
         container ('maven') {
           sh 'docker tag  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest '
           sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest '
         }
    }
}

这个意思就是说每次打版本以后作为最新的一个版本latest也推送到镜像仓库

部署到测试环境
stage('deploy to dev') {
   when{
     branch 'master'
   }
   steps {
      container ('maven'){
//     input(id: 'deploy-to-dev', message: 'deploy to dev?')
       sh "ls -l deploy/dev-ol"
       sh "sleep 1"
       sh "ls -l deploy/dev-ol"
       sh "cat deploy/dev-ol/*.yaml"
       sh "sleep 1"
      
      sh '''
      echo "changing parameter"
      cp deploy/dev-ol/devops-sample.yaml k8s.yaml
      
      sed -i "s#TAG_NAME#$BUILD_NUMBER#g" k8s.yaml
      sed -i "s#REGISTRY#$REGISTRY#g" k8s.yaml
      sed -i "s#DOCKERHUB_NAMESPACE#$DOCKERHUB_NAMESPACE#g" k8s.yaml
      sed -i "s#APP_NAME#$APP_NAME#g" k8s.yaml
      sed -i "s#BRANCH_NAME#$BRANCH_NAME#g" k8s.yaml

      '''
    //  sh 'kubectl delete -f k8s.yaml -n testing'
      sh "sleep 10"
      sh "cat k8s.yaml"
      sh 'kubectl apply -f k8s.yaml -n testing'
    }
   }
 }

将dev中的做好的yaml文件复制到根路径,然后通过 sed i “s//g”来替换里面的参数,比如镜像地址,应用版本这些
Sed 命令简要介绍
sed -i 就是直接对文本文件进行操作的
sed -i ‘s/原字符串/新字符串/’ /home/1.txt
sed -i ‘s/原字符串/新字符串/g’ /home/1.txt
需要使用双引号,如果替换值为环境变量
sed -i “s#BUILD_NUMBER#$BUILD_NUMBER#g” k8s.yaml
sed -i ‘sBUILD_NUMBER/TAG_NAME’ k8s.yaml
使用 sed 命令修改 YAML 文件中的变量值。

最后执行这个yaml文件到命名空间testing中

版本镜像推送
stage('push with tag'){
          
            steps {
              container ('maven') {
         //       input(id: 'release-image-with-tag', message: 'release image with tag?')
//                   withCredentials([usernamePassword(credentialsId: "$GITEE_CREDENTIAL_ID", passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
//                     sh 'git config --global user.email "[email protected]" '
//                     sh 'git config --global user.name "[email protected]" '
//                     sh 'git tag -a $TAG_NAME -m "$TAG_NAME" '
//                     sh 'git push http://$GIT_USERNAME:[email protected]/$GITEE_ACCOUNT/$APP_NAME.git --tags --ipv4'
//                     }
            
                  sh 'docker tag  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$TAG_NAME $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME '
                  sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:$TAG_NAME '
               }
           }
        }

这里又推送了一个版本镜像到仓库,还在gitee上打了一个版本标签,只是这里我暂时注释掉了

是否部署到生产环境
stage('deploy to production') {
  
     steps {
      container ('maven') {
       input(id: 'deploy-to-production', message: 'deploy to production?')
      // sh 'kubectl delete -f k8s.yaml -n production'
        sh "env"
        sh "sleep 10"
        sh "cat k8s.yaml"
        sh 'kubectl apply -f k8s.yaml -n production'
     }
   }
}

让运维人员选择是否部署到生产,如果部署到生产则执行yaml

创建jenkins部署项目

K8S搭建DevOps环境二_第6张图片
创建一个流水线的java项目,名字随便取

参数化配置

参数化也可以在这里配置,这里最好配置好,否则就是用jenkinsfile里面的默认值,这里配置了就可以根据情况需要输入不同的参数
K8S搭建DevOps环境二_第7张图片
K8S搭建DevOps环境二_第8张图片
对应到jenkinsfile里面的两个参数

构建触发器-Gitee Webhook 配置

gitee的webhook是需要安装插件的,安装 Generic Webhook Trigger 插件在“系统设置– 插件管理– 可选插件”界面搜索: Generic Webhook Trigger,可以看到,点击安装,然后重启。
K8S搭建DevOps环境二_第9张图片
安装完就重启了:
K8S搭建DevOps环境二_第10张图片
安装好了,再进行java这个项目的配置就可以看到有个选项:
K8S搭建DevOps环境二_第11张图片
K8S搭建DevOps环境二_第12张图片
在gitee上配置这个地址过后,当开发人员提交版本代码以后就会自动触发jenkins的自动化部署,这个在ci/cd上是很有用,完全不用人工干预就做到自动化构建和部署,除了这里还需要创建用户的token,比如我的jenkins用户是bml,那么在用户管理这里:
K8S搭建DevOps环境二_第13张图片
我的token生成了要马上复制自己保存,因为没有地方可以查询:
bml:1111a0a4944bf9add20578b2545080b56d
K8S搭建DevOps环境二_第14张图片
点击管理
K8S搭建DevOps环境二_第15张图片因为我这里是本地的虚拟机,所以配置了了也没有用,回头自己搭建一个gitlab来测试。

流水线

K8S搭建DevOps环境二_第16张图片
这里定义的流水线是从gitee上下载,如果这里选了,在脚本里面就不用写拉取代码的步骤了,比如:
K8S搭建DevOps环境二_第17张图片
反正看自己选择,想在哪里写就在哪里写
K8S搭建DevOps环境二_第18张图片

最后是脚本路径,在项目里面这个脚本是放在根目录的,这样代码拉取下来过后,在根目录就可以找到这个文件了,就可以进行构建了,还记得上篇文章我们配置了pvc agent-workspace吗?这个就是用来存储这些构建项目的文件和jar包的,采用的nfs存储,因为我这里构建过了,所以可以看下:
在这里插入图片描述在nfs里面:
在这里插入图片描述
都是有的,所以挂载的目录就是nfs的这个目录,所以在文章开头说的一个完整的构建过程就说完了,下面就开始构建:

构建

我们是参数化构建,如果直接点击左边的build with Parameters,如下
K8S搭建DevOps环境二_第19张图片
这里就可以设置你想设置的参数,我只是演示了两个参数,真正构建如下:
K8S搭建DevOps环境二_第20张图片
K8S搭建DevOps环境二_第21张图片

这是我构建过的记录,在构建的最左下角有构建记录,可以点击进去看下:
K8S搭建DevOps环境二_第22张图片
还可以看下输出,这个构建是可以通过可视化的方式展示流水线的步骤和日志的,是非常好的一种方式
K8S搭建DevOps环境二_第23张图片
这上面的名称就是在上面我们每个讲解的阶段名称,鼠标移到上面还可以看日志,比如看下编译代码的日志:
K8S搭建DevOps环境二_第24张图片
K8S搭建DevOps环境二_第25张图片
点击可进入详细的日志:
K8S搭建DevOps环境二_第26张图片
构建成功以后,在容器里的命名空间testing如下:
K8S搭建DevOps环境二_第27张图片
在浏览器输入我们应用的地址:
K8S搭建DevOps环境二_第28张图片
镜像仓库:
K8S搭建DevOps环境二_第29张图片
K8S搭建DevOps环境二_第30张图片
可以看到有很多的版本;这就是一个算是比较复杂的Devops搭建过程

你可能感兴趣的:(K8S,devops,docker,java)