Jenkins + Docker + SpringCloud 微服务持续集成 - 高可用集群部署(三)

Jenkins + Docker + SpringCloud 高可用集群部署方案

微服务持续集成(一):https://blog.csdn.net/shm19990131/article/details/107552335

一、单机部署方案存在问题

  1. 一次只能选择一个微服务部署
  2. 只有一台生产者 docker 部署服务器
  3. 每个微服务只有一个实例,容错率低

二、高可用集群优化方案

  1. 在一个 Jenkins 工程中可以选择多个微服务同时发布。
  2. 在一个 Jenkins 工程中可以选择多台生产服务器同时部署
  3. 每个微服务都是以集群高可用形式部署

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

在这里插入图片描述

部署步骤

一、修改所有微服务配置,让其可以形成一个集群

可以根据自己的需求去修改,这里只是将 eureka变成主从,其余微服务读取eureka配置

1、修改 erueka 的 配置文件application.yml

  1 spring:
  2   application:
  3     name: EUREKA-HA
  4 
  5 ---
  6 server:
  7   port: 8000
  8 spring:
  9   profiles: eureka-server1
 10 eureka:
 11   instance:
 12     hostname: 192.168.168.14
 13   client:
 14     server-url:
 15        defaultZone: http://192.168.168.14:8000/eureka/,http://192.168.168.15:8000/eureka/
 16 
 17 ---
 18 server:
 19   port: 8000
 20 spring: 
 21   profiles: eureka-server2
 22 eureka:
 23   instance:
 24     hostname: 192.168.168.15
 25   client:
 26     server-url:
 27        defaultZone: http://192.168.168.14:8000/eureka/,http://192.168.168.15:8000/eureka/

在启动微服务的时候,加入参数:spring.profiles.active 来读取对应的配置。

2、其他微服务配置

其他所有子项目的配置文件,都需要指定两个 Eureka注册中心的 ip:port/eureka

eureka:
  client:  
    server-url:
      defaultZone: http://192.168.168.14:8000/eureka/,http://192.168.168.15:8000/eureka/


二、高可用集群部署 - pipeline 流水线参数设置

1、创建一个 Pipeline SCM 的流水线

在这里插入图片描述

2、安装集群必须的多选插件

Extended Choice Paranter

3、利用多选插件,设置 Pipeline 项目参数

分支参数:string Parameter

多选参数:Extended Choice Parameter

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

Number of Visible ltems :有几个微服务需要部署就填几。

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

注意,这里的逗号有讲究,不能是中文逗号,必须是英文无间隔的逗号。

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

以上是设置微服务集群部署的必要参数,这些参数都是将来用在 Jenkinsfile 脚本当中的,非常重要。


三、修改 Jenkinsfile ,实现高可用集群部署

修改 Jenkinsfile ,实现高可用集群部署

1、定义代码审查功能

node {
    
    //获取当前复选的项目名称
    def project_Names = "${project_name}".split(",")


	stage('拉取代码') {
		checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
	}
	stage('代码审查') {
		
        //循环获取项目名称,并生成数组
	    for(int i=0; i<projectNames.length;i++){
	    
	            //获取每个微服务的名字:microservice-base-eureka:8000
	            def projectInfo = projectNames[i];
	            
	            //切割出微服务名:microservice-base-eureka
	            def projectName = "${projectInfo}".split("@")[0]
	            
	            //切割出port:8000
	            def projectPort = "${projectInfo}".split("@")[1]
	            
        	    //定义当前jenkins的 sonarQubeScanner 工具
        	    def scannerHome = tool 'sonar-Scanner'
        	    
        	    //引用当前 JenkinsSonarQube
        	    withSonarQubeEnv('sonarqube') {
                       sh """
    	                  cd ${project_Name}
    	                ${scannerHome}/bin/sonar-scanner
    	            """
	        }
	    }
	}
1-2、修改 sonar-project.properties
###  注意大小写 

sonar.projectKey=cluster_eureka_server
sonar.projectName=cluster_eureka_server
sonar.projectVersion=1.0

#扫描路径 “.”代表全部内容
sonar.sources=.
#排除扫描路径
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.


sonar.java.source=1.8
sonar.java.target=1.8

sonar.sourceEncoding=UTF-8


2、构建镜像

父工程不变,改动的是父工程下的子工程。
stage('编译,安装父工程') {
	    sh "/usr/local/maven/bin/mvn -f microservice-base-common install"
	    sh "/usr/local/maven/bin/mvn -f microservice-base-common clean package"
	}
子工程Jenkinsfile文件如下:
stage('编译,安装公共子工程,制作镜像') {
		
		//循环遍历 微服务名,并生成数组
	    for(int i=0; i<projectNames.length;i++){
	    
	            //获取每个微服务的名字:microservice-base-eureka:8000
	            def projectInfo = projectNames[i];
	            
	            //切割出微服务名:microservice-base-eureka
	            def projectName = "${projectInfo}".split("@")[0]
	            
	            //切割出port:8000
	            def projectPort = "${projectInfo}".split("@")[1]
	
	
	            sh "/usr/local/maven/bin/mvn -f ${projectName} clean package dockerfile:build"
	        }
	    }


3、上传镜像至 Harbor 仓库

stage('镜像上传至Harbor仓库') {
	
	    for(int i=0; i<projectNames.length;i++){
	    
	            //获取每个微服务的名字:microservice-base-eureka:8000
	            def projectInfo = projectNames[i];
	            
	            //切割出微服务名:microservice-base-eureka
	            def projectName = "${projectInfo}".split("@")[0]
	            
	            //切割出port:8000
	            def projectPort = "${projectInfo}".split("@")[1]
        	    
        	    //定义镜像名字
        	    def imageName = "${projectName}:${tag}"
        	
        	    //为镜像打标签
        	    sh "docker tag ${imageName}  ${harbor_url}/${harbor_project}/${imageName}"
        	    
        	    //凭据登录Harbor
        	    withCredentials([usernamePassword(credentialsId:"${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
                    
                    	//引用用户名密码登录
                   	sh "docker login -u ${username} -p ${password} ${harbor_url}"
                    
                   	//镜像上传
                   	sh "docker push ${harbor_url}/${harbor_project}/${imageName} && echo 镜像上传成功"
                    
                   	//登出 Harbor
                    	sh "docker logout ${harbor_url}"
            }
        }
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Mg3iCmH-1596065354156)(C:\Users\86156\Pictures\jenkins\高级\批注 2020-07-29 194528.png


>

四、多台docker生产服务器部署 eureka 集群

需求:两台 docker 服务器 同时部署 eureka 微服务

eureka配置文件

  1 spring:
  2   application:
  3     name: EUREKA-HA
  4 
  5 ---
  6 server:
  7   port: 8000
  8 spring:
  9   profiles: eureka-server1
 10 eureka:
 11   instance:
 12     hostname: 192.168.168.14
 13   client:
 14     server-url:
 15        defaultZone: http://192.168.168.14:8000/eureka/,http://192.168.168.15:8000/eureka/
 16 
 17 ---
 18 server:
 19   port: 8000
 20 spring: 
 21   profiles: eureka-server2
 22 eureka:
 23   instance:
 24     hostname: 192.168.168.15
 25   client:
 26     server-url:
 27        defaultZone: http://192.168.168.14:8000/eureka/,http://192.168.168.15:8000/eureka/



br

1、传递公钥至所有的 dokcer 生产服务器

docker 生产服务器必须能从 Harbor上拉取镜像。

[root@jenkins ~]# ssh-copy-id 192.168.168.15
[root@jenkins ~]# ssh-copy-id 192.168.168.14

2、在 Jenkins 设置里配置 SSH密钥认证

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Up0g0JfZ-1596065354157)(C:\Users\86156\Pictures\jenkins\高级\批注 2020-07-29 194752.png)]

3、Jenkins - pipeline 设置多选参数,多选生产服务器

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

4、修改 Jenkinsfile 文件,设置多选生产服务器

//设置 gitlab 拉取凭证ID号的变量
def git_auth = "218fb747-c605-4fa0-80d3-c322cd42d7a9"
//设置 gitlab 拉取代码 URL 地址的变量
def git_url = "git@192.168.168.12:itheima_group/tensquare_front.git"

//镜像版本号
def tag = "latest"

//Harbor仓库的IP地址
def harbor_url = "192.168.168.14"

//Harbor凭证
def harbor_auth = "584bf0a9-d247-4c4f-9e29-b9291381dd45"

//Harbor仓库
def harbor_project = "tensquare"

node {
	//获取当前选择的项目名称
	def projectNames = "${project_name}".split(",")
	
	//获取当前选择的服务器名称
	def Servers = "${publish_server}".split(",")
	
......省略之前的步骤
	
    
    stage('镜像上传至Harbor仓库,并完成部署') {
	
	    for(int i=0; i<projectNames.length;i++){
	    
	            //获取每个微服务的名字:microservice-base-eureka:8000
	            def projectInfo = projectNames[i];
	            
	            //切割出微服务名:microservice-base-eureka
	            def projectName = "${projectInfo}".split("@")[0]
	            
	            //切割出port:8000
	            def projectPort = "${projectInfo}".split("@")[1]
	                
        	    //定义镜像名字
        	    def imageName = "${projectName}:${tag}"
        	
        	    //为镜像打标签
        	    sh "docker tag ${imageName}  ${harbor_url}/${harbor_project}/${imageName}"
        	    
        	    //凭据登录Harbor
        	    withCredentials([usernamePassword(credentialsId:"${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
                    
                    //引用用户名密码登录
                    sh "docker login -u ${username} -p ${password} ${harbor_url}"
                    
                    //镜像上传
                    sh "docker push ${harbor_url}/${harbor_project}/${imageName} && echo 镜像上传成功"
                    
                    //登出 Harbor
                    sh "docker logout ${harbor_url}"
                }
        
             //设置多机部署 eureka 应用。
 	     for(int j=0;j<Servers.length;j++){
			
			//获取当前遍历的服务器名称
			def ServerName = Servers[j]
		
            		//加上指定主机的参数格式:--spring.profiles.active=eureka-server1/eureka-server2
            		def activeProfile = "--spring.profiles.active="

            		//根据不同的服务器名称(docker/docker-slave),来区分 eureka服务部署的主机
            		if(ServerName == "docker"){
                		activeProfile = activeProfile+"eureka-server1"
            		}else if(ServerName == "docker-slave") {
                		activeProfile = activeProfile+"eureka-server2"
                	}
	
			// 部署应用
			sshPublisher(publishers: [sshPublisherDesc(configName: "${ServerName}", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins/deployCluster.sh $harbor_url $harbor_project $projectName $tag $projectPort $activeProfile", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }
}

在所有的 docker 生产服务器创建此脚本

/opt/jenkins/deployCluster.sh

#!/bin/sh
harbor_url=$1			#对应$harbor_url
harbor_project_name=$2		#对应$harbor_project
project_name=$3			#对应$projectName
tag=$4				#对应$tag
port=$5				#对应$projectPort 
profile=$6			#对应$activeProfile

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

echo "==========$imageName========="

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

echo "==========$containerId==========="

if [ "$containerId" != " " ];then
        #删除容器
        docker rm -f $containerId && echo "成功删除容器"
fi

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

echo "=========$imageId========="

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

#登录 Harbor
docker login -u shm -p QQ1136265636.com $harbor_url

#下载容器
docker pull $imageName

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

echo "新版本容器启动成功"

构建测试一下,同时勾选两个生产服务器,看看能不能同时部署上 eureka


五、总结

这种高可用集群部署方案,可以同时在 多个生产服务器 上,同时部署多个相同的微服务。达到高可用集群效果。

如下图,可以一次构建所有需求。

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

完整的 Jenkinsfile 文件

//设置 gitlab 拉取凭证ID号的变量
def git_auth = "218fb747-c605-4fa0-80d3-c322cd42d7a9"
//设置 gitlab 拉取代码 URL 地址的变量
def git_url = "git@192.168.168.12:itheima_group/tensquare_front.git"

//镜像版本号
def tag = "latest"

//Harbor仓库的IP地址
def harbor_url = "192.168.168.14"

//Harbor凭证
def harbor_auth = "584bf0a9-d247-4c4f-9e29-b9291381dd45"

//Harbor仓库
def harbor_project = "tensquare"

node {
	//获取当前选择的项目名称
	def projectNames = "${project_name}".split(",")
	
	//获取当前选择的服务器名称
	def Servers = "${publish_server}".split(",")
	
	stage('拉取代码') {
		checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
	}


	stage('代码审查') {

		for(int i=0; i<projectNames.length;i++){
	    
	            //获取每个微服务的名字:microservice-base-eureka:8000
	            def projectInfo = projectNames[i];
		    sh "echo ${projectNames}"
	            
	            //切割出微服务名:microservice-base-eureka
	            def projectName = "${projectInfo}".split("@")[0]
		    sh "echo ${projectName}"
	            
	            //切割出port:8000
	            def projectPort = "${projectInfo}".split("@")[1]
		    sh "echo ${projectPort}"
	    
		    //定义当前jenkins的 sonarQubeScanner 工具
		    def scannerHome = tool 'sonar-Scanner'
	    
	   	    //引用当前 JenkinsSonarQube
	    	    withSonarQubeEnv('sonarqube') {
	            	sh """
	                	cd ${projectName}
	                	${scannerHome}/bin/sonar-scanner
	            	"""
	    		}
		}	
	}
	
	stage('编译,安装父工程') {
	    sh "/usr/local/maven/bin/mvn -f microservice-base-common install"
	    sh "/usr/local/maven/bin/mvn -f microservice-base-common clean package"
	}
	
	stage('编译,安装公共子工程,制作镜像') {
	
	    for(int i=0; i<projectNames.length;i++){
	    
	            //获取每个微服务的名字:microservice-base-eureka:8000
	            def projectInfo = projectNames[i];
	            
	            //切割出微服务名:microservice-base-eureka
	            def projectName = "${projectInfo}".split("@")[0]
	
	
	            sh "/usr/local/maven/bin/mvn -f ${projectName} clean package dockerfile:build"
	        }
	   }
	   
	stage('镜像上传至Harbor仓库') {
	
	    for(int i=0; i<projectNames.length;i++){
	    
	            //获取每个微服务的名字:microservice-base-eureka:8000
	            def projectInfo = projectNames[i];
	            
	            //切割出微服务名:microservice-base-eureka
	            def projectName = "${projectInfo}".split("@")[0]
	            
	            //切割出port:8000
	            def projectPort = "${projectInfo}".split("@")[1]
	                
        	    //定义镜像名字
        	    def imageName = "${projectName}:${tag}"
        	
        	    //为镜像打标签
        	    sh "docker tag ${imageName}  ${harbor_url}/${harbor_project}/${imageName}"
        	    
        	    //凭据登录Harbor
        	    withCredentials([usernamePassword(credentialsId:"${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
                    
                    //引用用户名密码登录
                    sh "docker login -u ${username} -p ${password} ${harbor_url}"
                    
                    //镜像上传
                    sh "docker push ${harbor_url}/${harbor_project}/${imageName} && echo 镜像上传成功"
                    
                    //登出 Harbor
                    sh "docker logout ${harbor_url}"
                }
        
        	for(int j=0;j<Servers.length;j++){
			
			//获取当前遍历的服务器名称
			def ServerName = Servers[j]
		
            		//加上指定主机的参数格式:--spring.profiles.active=eureka-server1/eureka-server2
            		def activeProfile = "--spring.profiles.active="

            		//根据不同的服务器名称(docker/docker-slave),来区分 eureka服务部署的主机
            		if(ServerName == "docker"){
                		activeProfile = activeProfile+"eureka-server1"
            		}else if(ServerName == "docker-slave") {
                		activeProfile = activeProfile+"eureka-server2"
                	}
	
			// 部署应用
			sshPublisher(publishers: [sshPublisherDesc(configName: "${ServerName}", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins/deployCluster.sh $harbor_url $harbor_project $projectName $tag $projectPort $activeProfile", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
            }
        }
    }
}

六、前端网站与微服务对接

Nginx + Zuul集群,实现网关高可用架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGLbL9oJ-1596065354163)(C:\Users\86156\Pictures\jenkins\高级\批注 2020-07-29 210055.png)]

①搭建Nginx(已完成)

②修改Nginx 配置文件

upstream zuulServer{
	server	192.168.168.103:10020	weight=1;
	server	192.168.168.104:10020	weight=1;
}

server {
	listen	default_server;
	server_name _;
	root 	/usr/local/nginx/html

	location / {
		proxy_pass http://zuulServer/;
	}
}

systemctl restart nginx

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程介绍 【完善体系+精品资料】本课程总计115课时,打造全网最全的微服务体系课程;从微服务是什么、能够做什么开始讲起,绝对零基础入门到精通类型。课程整体脉络十分清晰,每个章节一个知识点,画图+源码+运行讲解,不信你学不会。1、课程先讲解了什么是单体架构、什么是微服务架构、他们之间有什么区别和联系,各自有什么优缺点。2、从本质入手,使用最简单的Spring Boot搭建微服务,让你认清微服务是一种思想和解决问题的手段,而不是新兴技术。3、讲解Spring Boot 与 Spring Cloud 微服务架构之间的联系,原生的RestTemplate工具,以及Actuator监控端点的使用。4、带着微服务所带来的各种优缺点,为大家引入服务发现与注册的概念和原理,从而引入我们的第一个注册中心服务Eureka。5、引入负载均衡的理念,区分什么是服务端负载均衡,什么是客户端负载均衡,进而引入Ribbon负载均衡组件的详细使用。6、为了解决微服务之间复杂的调用,降低代码的复杂度,我们引入了Feign声明式客户端,让你几行代码学习服务的远程调用。7、为了解决服务之间的稳定性,避免发生雪崩问题,我们引入了Hystrix断路器,服务降级和熔断机制。8、微服务集群十分庞大,监控起来是十分困难的,尤其是对每一个接口的熔断情况进行监控,因此我们引入了Turbine微服务监控。9、微服务的调用是杂乱无章的,可以网状调用,怎么做到统一的入口出口,统一的授权、加密、解密、日志过滤,我们引入了第一代网关Zuul。10、微服务的配置分散,每次要修改配置都要重启服务,因此我们引入了Config配置中心。11、跟上主流,Consul是当前主流的服务注册与发现、配置中心一体化的解决方案。12、阿里的Nacos服务注册与发现、配置中心在国内炙手可热,Nacos 经历过双十一的微服务中间件。13、Turbin做微服务监控还是太弱,我们需要更强大,可视化,操作性更强的监控系统,因此我引入了Spring Boot Admin体系。14、Zuul已经停止更新支持,Spring Cloud官方推荐的二代网关Spring Cloud Gateway更加强大。15、微服务的安全架构体系虽然复杂,但是是有学习条例的,什么是认证授权、什么是OAuth2.0的原理、 JWT、怎么样去开发实现。 课程资料 【独家资料】1、课程附带全部63个项目源码,其中Hoxton版本项目源码37个,Edgware版本项目26个,2、230页高清PDF正版课件。3、附带nacos、consul、cmder等视频配套软件。学习方法1、每一节课程均有代码,较好的方式为一边听我的讲解,一边使用我提供的项目代码进行观察和运行。2、课程体系庞大,但是并不杂乱,每个章节只针对一个知识点,减轻学习压力。3、坚持每天学习1~2个章节,可以在地铁、公交上用手机学习。【完善知识体系图】

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值