前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Jenkins+Docker+SpringCloud微服务持续集成(下)

Jenkins+Docker+SpringCloud微服务持续集成(下)

作者头像
大忽悠爱学习
发布2022-09-29 13:10:08
4700
发布2022-09-29 13:10:08
举报
文章被收录于专栏:c++与qt学习

Jenkins+Docker+SpringCloud微服务持续集成(下)


Jenkins+Docker+SpringCloud部署方案优化

● 前面部署方案存在的问题:

○ 一次只能选择一个微服务部署。

○ 只有一条生产部署服务器。

○ 每个微服务只有一个实例,容错率低。

● 优化方案:

○ 在一个Jenkins工程中可以选择多个微服务同时发布。

○ 在一个Jenkins工程中可以选择多台生产服务器同时部署。

○ 每个微服务都是以集群高可用的形式部署。


Jenkins+Docker+SpringCloud集群部署流程说明


修改所有微服务配置

修改注册中心的配置

  • application.yaml
代码语言:javascript
复制
# 集群版
spring:
  application:
    name: Eureka-HA

---
server:
  port: 10086
spring:
  # 指定当profile=eureka-server1
  profiles: eureka-server1
eureka:
  instance:
    # 指定当profile=eureka-server1,主机名是eureka-server1
    hostname: 192.168.18.103
  client:
    service-url:
      defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka

---
server:
  port: 10086
spring:
  profiles: eureka-server2
eureka:
  instance:
    hostname: 192.168.18.104
  client:
    service-url:
      defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka
  • 在启动微服务的时候,加入参数spring.profile.active来读取对应的配置。

其他微服务配置

除了Eureka注册中心以外,其他微服务的配置都需要加入所有Eureka的服务。

商品微服务的配置:

代码语言:javascript
复制
server:
  port: 9001 # 微服务的端口号

spring:
  application:
    name: service-product # 微服务的名称

# 配置 eureka
eureka:
  client:
    service-url: # Eureka Server的地址
      defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka
  instance:
    instance-id: service-product
    prefer-ip-address: true

订单微服务的配置:

代码语言:javascript
复制
server:
  port: 9002 # 微服务的端口号

spring:
  application:
    name: service-order # 微服务的名称

# 配置 eureka
eureka:
  client:
    service-url: # Eureka Server的地址
      defaultZone: http://192.168.18.103:10086/eureka,http://192.168.18.104:10086/eureka
  instance:
    instance-id: service-order
    prefer-ip-address: true

设计Jenkins集群项目的构建参数

Jenkins安装Extended Choice Parameter插件

创建流水线项目

添加参数


最后效果


把多个项目提交SonarQube进行代码审核

  • 修改Jenkinsfile文件,内容如下:
代码语言:javascript
复制
//定义git凭证ID
def git_auth = "7d5c4945-2533-41e2-bd47-5dd97eb37f38"
//git的url地址
def git_url = "git@192.168.18.100:develop_group/jenkinscloud.git"
//定义tag
def tag = "1.0"
// 定义Harbor的URL地址
def harbor_url = "192.168.18.102:85"
// 镜像库项目名称
def harbor_project = "xudaxian-mall"
// Harbor的登录凭证id
def harbor_auth = "b6cf3cb5-8a33-457d-93da-65c46f0135b2"
node {
    // == 修改部分 获取当前选择的项目名称 ==
    def selectedProjectNames = "${project_name}".split(",")
    // == 修改部分
    stage('拉取代码') {
        checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
    }
    stage('代码审查') {
        // == 修改部分
        for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
            //jenkinscloud-eureka@10086
            def projectInfo = selectedProjectNames[i];
            //当前的项目名称 jenkinscloud-eureka
            def currentProjectName = "${projectInfo}".split("@")[0]
            //当前的项目端口 10086
            def currentProjectPort = "${projectInfo}".split("@")[1]
             //定义当前Jenkins的SonarQubeScanner工具的环境
            def scannerHome = tool 'sonarqube-scanner'
            //引用当前Jenkins的SonarQube环境
            withSonarQubeEnv('sonarqube-8.6.0') {
              sh """
                   cd ${currentProjectName}
                   ${scannerHome}/bin/sonar-scanner
              """
            }
        }
        // == 修改部分

    }
    //如果有公共子工程
//     stage('编译,安装公共的子工程') {
//        sh "mvn -f jenkinscloud-common clean install"
//     }
    stage('编译,打包微服务工程') {
       // dockerfile:build 可以触发插件的执行
       sh "mvn -f ${project_name} clean install dockerfile:build "
    }

    stage('上传镜像') {
       //定义镜像的名称
       def imageName = "${project_name}:${tag}"
       //给镜像打上标签
       sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
       //把镜像推送到Harbor
       withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
           // 登录到Harbor
           sh "docker login -u ${username} -p ${password} ${harbor_url}"
           //镜像的上传
           sh "docker push ${harbor_url}/${harbor_project}/${imageName}"

           sh "echo '镜像上传到Harbor仓库中成功'"

       }
       //删除本地镜像
       sh "docker rmi -f ${imageName}"
       sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"

    }
    // 定义远程执行命令
    def execCommand = "/usr/local/deploy.sh $harbor_url $harbor_project $project_name $tag $port"
    stage('拉取镜像和发布应用') {
        // 远程部署调用进行项目部署
        sshPublisher(publishers: [sshPublisherDesc(configName: '192.168.18.103', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${execCommand}", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
    }
}

多个项目打包及构建镜像、上传私服

  • 修改Jenkinsfile文件,内容如下:
代码语言:javascript
复制
//定义git凭证ID
def git_auth = "7d5c4945-2533-41e2-bd47-5dd97eb37f38"
//git的url地址
def git_url = "git@192.168.18.100:develop_group/jenkinscloud.git"
//定义tag
def tag = "1.0"
// 定义Harbor的URL地址
def harbor_url = "192.168.18.102:85"
// 镜像库项目名称
def harbor_project = "xudaxian-mall"
// Harbor的登录凭证id
def harbor_auth = "b6cf3cb5-8a33-457d-93da-65c46f0135b2"
node {
    // == 获取当前选择的项目名称 ==
    def selectedProjectNames = "${project_name}".split(",")

    stage('拉取代码') {
        checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
    }
    stage('代码审查') {
        for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
            //jenkinscloud-eureka@10086
            def projectInfo = selectedProjectNames[i];
            //当前的项目名称 jenkinscloud-eureka
            def currentProjectName = "${projectInfo}".split("@")[0]
            //当前的项目端口 10086
            def currentProjectPort = "${projectInfo}".split("@")[1]
             //定义当前Jenkins的SonarQubeScanner工具的环境
            def scannerHome = tool 'sonarqube-scanner'
            //引用当前Jenkins的SonarQube环境
            withSonarQubeEnv('sonarqube-8.6.0') {
              sh """
                   cd ${currentProjectName}
                   ${scannerHome}/bin/sonar-scanner
              """
            }
        }
    }
    //如果有公共子工程
//     stage('编译,安装公共的子工程') {
//        sh "mvn -f jenkinscloud-common clean install"
//     }
    stage('编译,打包微服务工程') {
       // == 修改部分 ==
       for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
            //jenkinscloud-eureka@10086
           def projectInfo = selectedProjectNames[i];
           //当前的项目名称 jenkinscloud-eureka
           def currentProjectName = "${projectInfo}".split("@")[0]
           //当前的项目端口 10086
           def currentProjectPort = "${projectInfo}".split("@")[1]
          // dockerfile:build 可以触发插件的执行
          sh "mvn -f ${currentProjectName} clean install dockerfile:build "
       }
       // == 修改部分 ==

    }

    stage('上传镜像') {
         // == 修改部分 ==
         for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
           //jenkinscloud-eureka@10086
          def projectInfo = selectedProjectNames[i];
          //当前的项目名称 jenkinscloud-eureka
          def currentProjectName = "${projectInfo}".split("@")[0]
          //当前的项目端口 10086
          def currentProjectPort = "${projectInfo}".split("@")[1]
           //定义镜像的名称
           def imageName = "${currentProjectName}:${tag}"
           //给镜像打上标签
           sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
           //把镜像推送到Harbor
           withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
               // 登录到Harbor
               sh "docker login -u ${username} -p ${password} ${harbor_url}"
               //镜像的上传
               sh "docker push ${harbor_url}/${harbor_project}/${imageName}"

               sh "echo '镜像上传到Harbor仓库中成功'"

           }
           //删除本地镜像
           sh "docker rmi -f ${imageName}"
           sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"
         }
         // == 修改部分 ==
    }
    // 定义远程执行命令
    def execCommand = "/usr/local/deploy.sh $harbor_url $harbor_project $project_name $tag $port"
    stage('拉取镜像和发布应用') {
        // 远程部署调用进行项目部署
        // sshPublisher(publishers: [sshPublisherDesc(configName: '192.168.18.103', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${execCommand}", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
    }
}

完成微服务多服务器远程发布

● 远程部署服务器(192.168.18.103和192.168.18.104)已安装Docker,并信任Harbor私有仓库。

● 关闭了防火墙。

● 在Publish over SSH那边增加一台远程部署服务器。


在Jenkins项目中增加一个Extended Choice Parameter参数

  • 在Jenkins项目中增加一个Extended Choice Parameter参数的目的是可以选择部署到那个服务器,选择Check

在192.168.18.103和192.168.18.104服务器中创建deployCluster.sh

在远程部署服务器的/usr/local目录下,创建deployCluster.sh文件:

代码语言:javascript
复制
cd /usr/local
代码语言:javascript
复制
vim deployCluster.sh
代码语言:javascript
复制
#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
profile=$6

imageName=$harbor_url/$harbor_project_name/$project_name:$tag

echo "$imageName"

#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag}  | awk '{print $1}'`

if [ "$containerId" !=  "" ] ; then
    #停掉容器
    docker stop $containerId

    #删除容器
    docker rm $containerId
	
	echo "成功删除容器"
fi

#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name  | awk '{print $3}'`

if [ "$imageId" !=  "" ] ; then
      
    #删除镜像
    docker rmi -f $imageId
	
	echo "成功删除镜像"
fi


# 登录Harbor
docker login -u xudaxian -p Xudaxian12345678 $harbor_url

# 下载镜像
docker pull $imageName

# 启动容器
docker run -di -p $port:$port $imageName $profile

echo "容器启动成功"

设置权限:

代码语言:javascript
复制
chmod +x deployCluster.sh

修改Jenkinsfile文件

代码语言:javascript
复制
//定义git凭证ID
def git_auth = "7d5c4945-2533-41e2-bd47-5dd97eb37f38"
//git的url地址
def git_url = "git@192.168.18.100:develop_group/jenkinscloud.git"
//定义tag
def tag = "1.0"
// 定义Harbor的URL地址
def harbor_url = "192.168.18.102:85"
// 镜像库项目名称
def harbor_project = "xudaxian-mall"
// Harbor的登录凭证id
def harbor_auth = "b6cf3cb5-8a33-457d-93da-65c46f0135b2"
node {
    // == 获取当前选择的项目名称 ==
    def selectedProjectNames = "${project_name}".split(",")
    // 获取当前选择的服务器名称
    def selectedServers = "${publish_server}".split(",")

    stage('拉取代码') {
        checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
    }
    stage('代码审查') {
        for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
            //jenkinscloud-eureka@10086
            def projectInfo = selectedProjectNames[i];
            //当前的项目名称 jenkinscloud-eureka
            def currentProjectName = "${projectInfo}".split("@")[0]
            //当前的项目端口 10086
            def currentProjectPort = "${projectInfo}".split("@")[1]
             //定义当前Jenkins的SonarQubeScanner工具的环境
            def scannerHome = tool 'sonarqube-scanner'
            //引用当前Jenkins的SonarQube环境
            withSonarQubeEnv('sonarqube-8.6.0') {
              sh """
                   cd ${currentProjectName}
                   ${scannerHome}/bin/sonar-scanner
              """
            }
        }
    }
    //如果有公共子工程
//     stage('编译,安装公共的子工程') {
//        sh "mvn -f jenkinscloud-common clean install"
//     }
    stage('编译,打包微服务工程') {
       for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
            //jenkinscloud-eureka@10086
           def projectInfo = selectedProjectNames[i];
           //当前的项目名称 jenkinscloud-eureka
           def currentProjectName = "${projectInfo}".split("@")[0]
           //当前的项目端口 10086
           def currentProjectPort = "${projectInfo}".split("@")[1]
          // dockerfile:build 可以触发插件的执行
          sh "mvn -f ${currentProjectName} clean install dockerfile:build "
       }
    }

    stage('上传镜像') {
         for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
           //jenkinscloud-eureka@10086
          def projectInfo = selectedProjectNames[i];
          //当前的项目名称 jenkinscloud-eureka
          def currentProjectName = "${projectInfo}".split("@")[0]
          //当前的项目端口 10086
          def currentProjectPort = "${projectInfo}".split("@")[1]
           //定义镜像的名称
           def imageName = "${currentProjectName}:${tag}"
           //给镜像打上标签
           sh "docker tag ${imageName} ${harbor_url}/${harbor_project}/${imageName}"
           //把镜像推送到Harbor
           withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
               // 登录到Harbor
               sh "docker login -u ${username} -p ${password} ${harbor_url}"
               //镜像的上传
               sh "docker push ${harbor_url}/${harbor_project}/${imageName}"

               sh "echo '镜像上传到Harbor仓库中成功'"

           }
           //删除本地镜像
           sh "docker rmi -f ${imageName}"
           sh "docker rmi -f ${harbor_url}/${harbor_project}/${imageName}"
         }
    }

    stage('拉取镜像和发布应用') {
        for(int i  = 0 ; i< selectedProjectNames.length ; i++) {
               //jenkinscloud-eureka@10086
              def projectInfo = selectedProjectNames[i];
              //当前的项目名称 jenkinscloud-eureka
              def currentProjectName = "${projectInfo}".split("@")[0]
              //当前的项目端口 10086
              def currentProjectPort = "${projectInfo}".split("@")[1]
              for(int j =0;j<selectedServers.length;j++){
                  //获取当前遍历的服务器名称
                  def currentServerName = selectedServers[j]
                  //加上参数格式: --spring.profiles.active=eureka-server1/eureka-server2
                  def activeProfiles = "--spring.profiles.active="
                  if(currentServerName =="192.168.18.103"){
                     activeProfiles = activeProfiles + "eureka-server1"
                  }else if(currentServerName == "192.168.18.104"){
                     activeProfiles = activeProfiles + "eureka-server2"
                  }

                  // 定义远程执行命令
                  def execCommand = "/usr/local/deployCluster.sh $harbor_url $harbor_project $currentProjectName $tag $currentProjectPort $activeProfiles"
                  // 远程部署调用进行项目部署
                  sshPublisher(publishers: [sshPublisherDesc(configName: "${currentServerName}", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "${execCommand}", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
              }
        }


    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Jenkins+Docker+SpringCloud微服务持续集成(下)
  • Jenkins+Docker+SpringCloud部署方案优化
  • Jenkins+Docker+SpringCloud集群部署流程说明
    • 修改所有微服务配置
      • 修改注册中心的配置
      • 其他微服务配置
  • 设计Jenkins集群项目的构建参数
    • Jenkins安装Extended Choice Parameter插件
      • 创建流水线项目
        • 添加参数
          • 最后效果
            • 把多个项目提交SonarQube进行代码审核
              • 多个项目打包及构建镜像、上传私服
                • 完成微服务多服务器远程发布
                  • 在Jenkins项目中增加一个Extended Choice Parameter参数
                    • 在192.168.18.103和192.168.18.104服务器中创建deployCluster.sh
                      • 修改Jenkinsfile文件
                      相关产品与服务
                      容器镜像服务
                      容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档