文章目录
Spring Cloud
0. 基础介绍
1. 简介
是一系列框架的有序集合,利用springboot的开发便利性(默认优于配置)简化了
分布式系统开发。
- 服务发现注册
- 配置中心
- 消息总线
- 负载均衡
- 熔断器
- 数据监控
- 等等
2. 与springboot的关系
- springboot 专注于快速高效的开发单个微服务
- springcloud 关注全局的服务治理
- springboot 可以离开springcloud单独开发
- springcloud 离不开springboot,属于依赖关系
- springboot 开发版本需和springcloud版本对应
3. 主要框架
- 服务发现:Eureka
- 服务调用:Feign
- 熔断器: Hystrix
- 服务网关: Zuul
- 分布式配置: Spring Cloud Config
- 消息总线: Spring Cloud Bus
dubbo相当于spring cloud的子集
3.1. Eureka 服务发现
- 类似于dubbo 和 zokeerper
- 包含两个组件:Eureka Server和Eureka Client
1. Eureka Server
提供服务注册服务,各个节点服务启动后,会在Eureka Server中注册,则server会在服务注册表中
存储所有可用服务节点的信息,这些信息会在管理界面中看到。
即一个微服务想让其他服务发现,就要让自己成为Eureka Client(客户端),即注册到服务端。
2. Eureka Client
是一个java客户端,用于简化和server的交互。
客户端应用启动后,会定时向服务端发送一个心跳(默认周期为30秒),若server端在多个心跳周期内没有发现某个
节点(客户端)的心跳,则服务端会从服务注册表中将该节点(客户端)移除(默认为90秒)。
3. Eureka Server开发
1. 在父工程中pom中添加版本锁定
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
需注意springboot版本和springcloud版本对应,否则会报错
参考版本对应
2. 新建模块作为服务发现的服务端
- pom 添加依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies>
- 配置文件配置
server: port: 8099 eureka: client: register-with-eureka: false #是否把当前模块注册到服务器中,本身就是服务器,所以为false fetch-registry: false #是否从Eureka中获取注册信息 service-url: #Eureka客户端与服务端交互的地址 defaultZone: http://localhost:${server.port}/eureka/
- 创建启动类
添加注解@EnableEurekaServer
4. Eureka Client开发
- 在已开发模块中添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
- 修改配置文件
- 启动类
添加注解@EnableEurekaClient
3.2. Feign 实现服务间的调用
前提是先能发现服务才可调用
1. 先搞清逻辑,A模块调用B模块,则操作A模块
-
pom文件导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
创建要调用模块(B模块)的客户端接口
@FeignClient("base-jpa") //FeignClient用于指定从哪个服务调用功能 public interface BaseJpaClient { //将需要的方法声明到该接口中 @GetMapping("/label/{labelId}") public Result findById(@PathVariable("labelId") String labelId); }
-
启动类添加注解
- @EnableDiscoveryClient
- @EnableFeignClients //采用Feign的方式去发现
-
调用
如:在controller中调用public class A{ @Autowired private BaseJpaClient baseJpaClient; @GetMapping("/label/{labelId}") public Result findByLabelId(@PathVariable String labelId){ return baseJpaClient.findById(labelId); } }
-
默认支持负载均衡
3.3. 熔断器(Hystrix)
雪崩效应
使得系统再出现依赖服务失效的时候,通过隔离系统所依赖的服务,防止服务级联失败,
同时提供失败回退机制,更好的应对失效
- feign本身就支持hystrix,所以无需再引入依赖
1.使用
- 针对调用的其他服务客户端(client),创建实现类
- 在客户端(client)上的注解@FeignClient中添加信息如下
@FeignClient(value = "base-jpa", fallback = BaseJpaClientImpl.class) public interface BaseJpaClient{}
- 在配置文件中添加
feign: hystrix: enabled: true #打开熔断器
当依赖的服务断掉后,调用该服务的方法会走指定的返回类(即fallback指定的类),当
依赖的服务重新连接上后,调用该服务则继续该有的执行,而不会走fallback。
3.4. 路由网关 Zuul
1. 提出问题
- 不同的微服务有不同的网络地址,外部的客户端可能需要调用多个服务的接口才能实现功能,
- 若客户端直接和微服务通信,则会出现如下问题
1. 客户端会多次请求不同微服务,增加了客户端的复杂性
2. 存在跨域请求,在一定场景下处理增加了复杂性
3. 认证复杂,每一个服务都需要独立认证
2. 项目应用 路由转发
- pom文件导入依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> </dependencies>
- 配置文件
server: port: 8092 spring: application: name: pro-web eureka: client: service-url: #Eureka客户端与服务端交互的地址 defaultZone: http://localhost:8099/eureka/ instance: prefer-ip-address: true #模块之间支持跨域 zuul: routes: #指定微服务及访问的路径跳转到的模块 pro-base: #指定微服务 path: /base/** #指定微服务的访问路径 serviceId: pro-base #上面指定的路径则跳转到该模块,即指定Eureka注册中心的服务id
- 创建启动类
@SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class WebApplication {}
3. 网关过滤器
参考pro_manager的ManagerFilter类
3.5.集中配置组件SpringCloud Config
- config server
- config client
[外链图片转存失败(img-C83hO9xC-1568598984359)(/images/springcloud_config%20框架结构.png)]
1.config server
用于集中管理应用程序各个模块下的配置
- 将各模块的配置文件通过A-B的方式命名,然后统一到git或svn等平台管理,并将地址留用
- 文件命名规范:{application}-{profile}.yml或{application}-{profile}.properties
- application为应用名称,profile为开发环境,如开发,测试,生产等
- 在项目中创建配置中心微服务模块
- pom导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
- 配置文件
server: port: 9080 spring: application: name: pro-web cloud: config: server: git: uri: https://gitee.com/git账号/项目名.git #配置文件存放git的访问路径
- 启动类
@SpringBootApplication @EnableConfigServer public class ConfigApplication {}
- 测试访问获取
访问http://localhost:9080/git中的文件名
- pom导入依赖
2.config client
- 在某个模块中应用
- 将该模块的配置文件放在git中,模块中删除该文件
- 在pom文件中添加依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
- 添加一个配置文件bootstrap.yml,配置连接config服务的信息
- bootstrap的优先级高于application
- 一般情况下bootstrap.yml中配置的信息为系统级信息,application中配置的应用级信息
spring: cloud: config: name: base #git中该微服务的配置文件的名称前缀 profile: dev #git中该微服务的配置文件的名称后缀 label: master # git主干 uri: http://localhost:9080 #指定配置服务的访问路径
3.6.消息总件 Bus
在微服务模块中添加一个监听,监听配置文件是否改变,若改变,重新获取配置文件,并编译项目
[外链图片转存失败(img-kEdx7aEV-1568598984361)(/images/springcloud_bus%20框架结构.png)]
1.简介
2. 应用
1. 服务端
在配置中心微服务模块中做如下操作
- pom文件添加依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-bus</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency> </dependencies>
- 配置文件application.xml
spring: rabbitmq: host: localhost #bus需要消息队列 management: #暴露触发消息总线的地址 endpoints: web: exposure: include: bus-refresh
2. 客户端
- pom引入依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-bus</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-stream-binder-rabbit</artifactId> </dependency> <dependency><!-- 监听 --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
- 配置文件(上传到git的文件)添加配置
spring: rabbitmq: host: localhost #bus需要消息队列
- 测试
- 启动Eureka、config(上面的服务端)及配置了bus的客户端
- 访问客户端的某个请求
- 修改git中该客户端的配置文件
- 以post的方式访问http://localhost:9080/actuator/bus-refresh,相当于发送一条消息到消息队列,注意该路径为配置中心服务模块的路径
- 此时监听器监听到消息队列有消息,会重新获取配置文件并编译项目
- 再次访问客户端的某个请求,会发现配置修改后
- 自定义配置
当某个模块中的配置文件中有自定义的配置文件,此时更新了配置文件中自定义属性的值后,再次访问值不会改变,
若想使其随着配置文件改变而改变,可以在controller上添加注解@RefreshScope
3.7.微服务容器部署和持续集成jenkins
所有操作需有前提,1已有Linux服务器,且安装了docker,若想本地操作,可安装xshell等远程操作工具
1.Dockerfile(手动发布镜像)
1. 简介
- 是由一系列命令和参数构成的脚本。能够把本地的代码发布到服务器成一个镜像的形式。
- 这些命令应用于基础镜像并最终创建一个新的镜像
2. 作用
- 对于开发人员:为开发团队提供完全一致的开发环境
- 对于测试人员:通过dockerfile文件可以直接创建一个新的镜像来工作
- 对于运维人员:在部署时,可以实现应用的无缝移植
3. 常用命令
image:镜像,tag:版本号
- FROM image_name:tag ->表示当前要制作的镜像依赖于tag版本的image_name(镜像名称)
- MAINTAINER user_name ->声明镜像的创建者
- ENV key value ->设置环境变量(键值对),可以有多条
- RUN command ->是Dockerfile的核心部分,执行指定命令,可以有多条
- ADD source_dir/file_dest_dir/file ->将宿主机(本地电脑)的文件复制到容器内,若是压缩文件,会复制后自动解压
- COPY source_dir/file_dest_dir/file ->将宿主机(本地电脑)的文件复制到容器内,若是压缩文件,会只复制不解压
- WORKDIR path_dir ->设置工作目录
- EXPOSE port1 port2 ->指定端口号,使容器内的应用可通过端口和外界交互
- CMD argument ->在构建容器时使用,会被docker run后的argument覆盖
- ENTRYPOINT argument ->在构建容器时使用,不会被docker run后的argument覆盖
4. 使用脚本创建镜像
以创建JDK 镜像为例
- 创建目录(在xshell中或直接在服务器上Linux下)
也可用xftp图形化界面直接创建文件mkdir -p /usr/local/docker_jdk8
- 下载jdk8.tar.gz并上传到中的上面目录中
- 创建文件Dockerfile
- 该文件必须与第2步中的文件在同一目录下
- 该文件名称必须为Dockerfile
- 文件内容(示例)
#依赖镜像名称和id(版本) FROM centos:7 #声明创建者 MAINTAINER bj #切换工作目录 WORKDIR /usr #运行命令 创建目录 RUN mkdir /usr/local/java #注意ADD后的文件是相对路径 ADD jdk8.tag.gz /usr/local/java/ #设置环境变量 ENV JAVA_HOME /usr/local/java/jdk8 ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tool.jar:$JRE_HOME/lib:$CLASSPATH ENV PATH $JAVA_HOME/bin:$PATH
- 切换目录到第一步创建的目录下
cd /usr/local/docker_jdk8
- 执行如下命令构建镜像
docker build -t = 'jdk1.8' .
上面的命令表示构建一个叫jdk1.8的镜像在当前目录下,注意最后的空格和点表示当前目录
- 执行命令查看创建的镜像
docker images
- 创建容器(先到根目录然后执行如下命令)
docker run -id --name = myjdk8 jdk1.8
- –name 表示为容器指定名称
- jdk1.8 指定要创建容器的镜像是哪个,若有多个版本的镜像,可通过 镜像:版本号的方式来指定
- 查看已创建的容器
docker ps
2. 私有仓库
是指对于一个应用可能在多处需要使用,每次使用都需要构建镜像,创建容器,通过私有仓库,
可以一次构建镜像将其放入私有仓库,需要使用的时候,直接下载镜像,创建容器即可,而无需再次构建。
1. 私有仓库搭建与配置
-
获取私有仓库的镜像
docker pull registry
-
启动私有仓库容器
docker run -di --name=registry -p 5000:5000 registry
- 打开浏览器 输入地址 http://ip地址:5000/v2/_catalog,此处的ip地址为服务器的ip地址
- 浏览器可看到{“repositories”:[]},表示私有仓库搭建成功并且内容为空。
-
修改 daemon.json
vim /etc/docker/daemon.json
添加内容{“insecure-registries”:[“ip地址:5000”]},用于让 docker信任私有仓库地址
注意:
看该文件是否修改镜像下载地址,默认国外地址下载较慢,可修改为如下国内地址(或其他){"registry-mirrors":["https:docker.mirrors.ustc.edu.cn"]}
该文件只有一个大括号,多个内容通过逗号分隔
-
重启docker
systemctl daemon-reload systemctl restart docker
2.上传镜像到私有仓库
- 先启动私有仓库
#查看已有容器 docker ps -a #启动私有仓库的容器 docker start 仓库容器名
- 查看已有镜像或者下载所需镜像
#查看已有镜像 docker images #下载所需镜像 docker pull 镜像名
- 修改标记Tag,即标记此镜像为私有仓库中的镜像
docker tag 镜像 服务端ip地址:5000/私有仓库中该镜像的名称
此时通过docker images查看镜像会发现有两个该镜像,一个是原有的,一个是标记后的镜像
- 上传镜像到私有仓库
docker push 服务端ip地址:5000/私有仓库中该镜像的名称
- 查看私有仓库
通过浏览器查看 http://服务端ip地址:5000/v2/_catalog 可以看到刚上传的镜像
3. DockerMaven插件
1.微服务部署的方式
- 手动部署:先基于源码打包生成jar(或war)包,将包上传至虚拟机并拷贝到jdk容器
- 通过maven插件自动部署
2.Maven 自动部署的步骤
- 修改宿主机的Docker配置,让其可以远程访问
vi /lib/systemd/system/docker.service
其中ExecStart后面添加-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
- 重启docker和私有仓库
- 在项目模块中操作
- pom文件导入插件
<build> <!-- 当前工程的名称 --> <finalName>config</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>docker-maven-plugin</artifactId> <configuration> <!-- 镜像的名称标记 --> <imageName>服务器ip地址:5000/${project.artifactId}/${project.version}</imageName> <!-- 基础镜像 --> <baseImage>jdk1.8</baseImage> <!-- 进入后执行java -jar *.jar 打包命令 --> <entryPoint>["java", "-jar", "/{project.build.finalName}.jar"]</entryPoint> <resources> <resource> <targetPath>/</targetPath> <directory>${project.build.directory}</directory> <include>${project.build.finalName}</include> </resource> </resources> <dockerHost>http://服务器ip:2375</dockerHost> </configuration> </plugin> </plugins> </build>
- 确保该项目模块所需的依赖都已启动,如rabbitmq等
- 在idea打开Terminal视图,在project中选中模块,拖到Terminal视图
注意默认idea没有加载Terminal,需通过file-》设置-》plugins-》选中Terminal,重启idea才可使用
- 执行命令mvn clean package docker:build -Dpushimage (依次为清理->打包->构建镜像->上传到私有仓库)
- 在服务器上通过命令查看镜像 docker images
- 启动容器 docker run -di --name=指定容器名 -p 端口号:指定端口号 镜像名:版本号
- pom文件导入插件
4.持续集成 jenkins
前提条件:代码托管到git或svn或码云等代码管理平台上
1.Gogs git图形化界面
-
下载gogs镜像 docker pull gogs/gogs
-
创建容器
docker run -d --name=gogs -p 10022:22 -p 3000:3000 -v /var/gogsdata:/data gogs/gogs
注意
- 第一个-p是内部使用,第二个-p是对外访问的,
- -v表示文件挂载, 表示把冒号后面的文件挂载到冒号前面指定的路径
-
在外部浏览器访问http://服务器ip地址:3000
- 选择数据库,可以选择Sqllite
- 修改域名和应用URL,指定服务器ip地址,
- 注册账号并登陆
- 创建仓库(即项目)
-
上传代码
- 在idea中的vcs菜单中选择启动版本控制合并,然后选择git
- 选中项目右键选择Git->Repository->Remotes
- 在URL中录入第三步创建仓库(项目)的地址,连接远程
- 选中项目右键选择Git->add 添加
- 选中项目右键选择Git->Commit Directory提交到本地
- 选中项目右键选择Git->Repository->Push提交到远程,此处需录入远程的用户名和密码
2.运用Jenkins实现持续集成
1. Jenkins
- Jenkins安装
- jdk安装 直接安装到宿主机上而不是创建容器
- jdk8-linux.rpm上传到服务器(可以是虚拟机)
- 执行安装命令
rpm -ivh jdk8-linux.rpm
rpm方式安装的,其根目录为usr/java/jdk
- Jenkins的安装与启动
- 下载或直接上传,执行命令 wget https://pkg.jenkins.io/redhat/jenkins-…noarch.rpm
- 安装 rpm -ivh jenkins的rpm安装包
- 安装maven
可以本地准备好上传或上传后在修改- 修改conf目录下的setting中指定仓库地址
- jdk安装 直接安装到宿主机上而不是创建容器
- 配置
- 通过vi /etc/sysconfig/jenkins打开配置文件
- 修改用户和端口
JENKINS_USER="root" JENKINS_PORT=指定端口
- 启动服务
systemctl start jenkins
- 浏览器访问 http://服务器ip地址:指定的端口
- 此时需要登录密码,此密码在服务器/var/lib/jenkins/secrets/initialAdminPassword文件中
- 安装插件maven和git 是必须的,可能不成功
- 创建一个账户,登录进入
- 对于不成功的插件可通过系统管理-》管理插件中进行安装
- 系统管理-》全局工具配置,配置jdk,maven
2. 持续集成
浏览器访问http://服务器ip地址:指定的端口并登陆
- 创建任务
3.8.容器管理
1. 容器管理工具Rancher
1.简介
- 是开源的全栈化容器部署及管理工具