SpringCloud微服务技术栈(上)-微服务治理、Docker
微服务技术栈导学
【微服务作用】:由于单体项目耦合度高,后期业务量大时不易维护,因此需要将整个项目按照功能进行拆分(每个功能模块称为服务)
【微服务技术栈】:
服务集群:单体项目拆分成多个服务后的结果
注册中心:记录每个服务的IP和端口以及它能干什么事情,当服务集群中的某个服务要找到另外一个服务时候,直接从注册中心去拉取或者注册服务信息即可
配置中心:统一管理服务的配置
服务网关:识别访问者的权限以及帮助访问者定位到具体服务
分布式缓存和分布式搜索:解决高并发的查询数据库
消息队列:减少服务调用的链路长度即减少服务之间调用的时间,降低高并发问题
系统监控链路追踪、分布式日志服务:记录和管控整个技术栈出现的问题
【自动化部署(持续集成)】:Jenkins、docker……
【学习路线】:
微服务治理
认识微服务
服务架构演变
【单体架构】:
【分布式架构】:
【微服务】:微服务是一种经过良好架构设计的分布式架构方案
微服务架构特征:
- 单一职责:微服务拆分粒度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
- 面向服务:微服务对外暴露业务接口
- 自治:团队独立、技术独立、数据独立、部署独立
- 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题
微服务技术对比
微服务这种方案需要技术框架来落地,全球的互联网公司都在积极尝试自己的微服务落地技术。在国内最知名的就是SpringCloud和阿里巴巴的Dubbo
【技术对比】:
【企业需求】:
SpringCloud
SpringCloud是目前国内使用最广泛的微服务框架。官网地址:https://spring.io/projects/spring-cloud。
SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验:
服务拆分
Demo的实现要求:通过订单模块调用用户模块,达到在查询订单信息的同时将用户信息也查询出来
案例Demo
【环境准备】:
目录结构:
数据库:
cloud_user数据库中的tb_user表:
cloud_order数据库中的tb_order表:
代码展示:
order-service(订单模块):
-
application.yml文件(可见配置的数据库是cloud_order)
-
OrderController文件(可见是根据orderId查询订单信息)
er) -
order实体类对象
user-service(用户模块):
-
application.yml文件(可见配置的数据库是cloud_user)
-
UserController文件(可见是根据id查询用户信息)
-
user实体类对象
运行结果:
- order-service:
可见,此时查询订单信息时并没有包含用户信息 - user-service
服务远程调用
【分析】:订单模块是否可以像浏览器一样发送url获取到用户模块中的用户信息,然后封装显示出来
【实现流程】:
步骤一:利用Spring提供的工具RestTemplate可以发送请求,在order-service的启动类OrderApplication中注册RestTemplate
步骤二:在订单模块中的service目录下的OrderService中发送查询(根据订单实体类中的userId查询,即将userId作为参数传递过去)请求获取到用户信息
Eureka
提供者与消费者
服务提供者:一次业务中,被其他微服务调用的服务。(提供接口给其他微服务)
服务消费者:一次业务中,调用其他微服务的服务。(调用其他微服务提供的接口)
eureka原理分析
【服务调用出现的问题】:
【Eureka的作用】:
说明:
搭建eureka服务
【案例实操】:
-
目录结构:
-
搭建注册中心:搭建EurekaServer
步骤一:创建项目,在项目eureka-server项目中引入spring-cloud-starter-netflix-eureka-server
的依赖
步骤二:编写启动类,添加@EnableEurekaServer
注解
步骤三:添加applicatio.yml文件,编写下面配置:
-
服务注册:将user-service、order-service都注册到eureka
步骤一:在user-service项目引入spring-cloud-starter-netflix-eureka-client
的依赖
步骤二:在application.yml文件,编写下面配置:
order-service与上面的user-service的注册方式一样
一个服务可以注册多个实例:
结果: -
服务发现:在order-service中完成服务拉取,然后通过负载均衡挑选一个服务,实现远程调用
步骤一:修改OrderService的代码,修改访问的url路径,用服务名代替ip、端口:
步骤二:在order-service项目的启动类OrderApplication中的RestTemplate添加负载均衡注解@LoadBalanced
"订单查询服务"会根据eureka的负载均衡算法(Ribbon)找到不同端口的“用户查询服务”实例
Ribbon
负载均衡原理
【负载均衡流程】:
细化:由图片可知,整个负载均衡策略是IRule的子接口做的(里面包含了不同的实现类即包括不同的负载均衡策略,默认的是ZoneAvoidanceRule策略)
负载均衡策略
【负载均衡策略框架图】:
不同策略的说明:
【调整负载均衡的方法】:
方法一:代码方式,在order-service中的OrderApplication类中,定义一个新的IRule(作用在全局上的):
方法二:配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则:
饥饿加载
Ribbon默认的是采用懒加载,即第一次访问时才会去创建LoadBalanceClient(用于拦截服务消费者的请求url),请求时间会很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过在order-service项目下面配置开启饥饿加载:
可以为多个服务开启饥饿加载
Nacos
认识和安装Nacos
【认识】:Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。
【安装】:
-
步骤一:下载安装包
在Nacos的GitHub页面,提供有下载链接,可以下载编译好的Nacos服务端或者源代码:
GitHub主页:https://github.com/alibaba/nacos
GitHUb的Release下载页:https://github.com/alibaba/nacos/releases
如图: -
步骤二:解压
将这个包解压到任意非中文目录下,如图:
目录说明:
bin:启动脚本
conf:配置文件 -
步骤三:端口配置
Nacos的默认端口是8848,如果你电脑上的其他进程占用了8848端口,请先尝试关闭该进程。
**如果无法关闭占用8848端口的进程,**也可以进入nacos的conf目录下,修改配置文件中的端口:
修改其中的内容:
-
步骤四:启动
进入bin目录,结构如下:
然后执行命令即可:
——windows命令
-
步骤五:访问
快速入门
【以下基础均在Eureka实例的基础上改的,没改的配置均采用原有Eureka的步骤执行(比如负载均衡@LoadBalanced
没改……)】
步骤一:在cloud-demo父工程中添加spring-cloud-alibaba的管理依赖,里面定义了Nacos的所有版本,以后Nacos的版本我们就不用操心了
步骤二:注释掉order-service和user-service中原有的eureka的依赖并添加nacos的客户端依赖
步骤四:修改user-service&order-service中的application.yml文件,注释eureka地址,添加nacos地址:
步骤五:启动并测试
服务多级存储模型
【分级存储模型】:由于某个服务有多个实例(比如上面的user-service就有多个实例,每个实例的作用是一样的,每个实例可能在不同的服务器上,这样可以解决高并发的一些问题,也能防止因为一个服务器崩坏导致整个服务不能使用,这些实例可以组成一个个集群分布在不同的地域)
【集群的作用】:
服务调用尽可能选择本地集群的服务,跨集群调用延迟较高,本地集群不可访问时,再去访问其他集群;总而言之集群的作用就是为了防止服务跨区域调用
【添加集群的步骤】:
实例:
步骤一:修改user-service的application.yml文件
步骤二:启动两个User类
步骤三:修改user-service的application.yml文件,将cluster-name属性改成SH
步骤四:重启最后一个User类
步骤五:在Nacos控制台观看结果
NacosRule负载均衡
【问题】:我们将order-service也放在杭州HZ集群下,,但是当order服务调用user服务实例时候并没有优先调用最近集群中的实例
【解决方法】:
步骤一:修改order-service中的application.yml文件,设置集群为HZ
步骤二:在order-service中设置负载均衡的IRule为NacosRule,这个规则优先会寻找与自己同集群的服务实例,而在本地集群中是随机访问策略,要是本地集群服务停止工作,则再访问外地集群:
步骤三:注意将user-service的权重都设置为1
服务实例的权重设置
实际部署中会出现这样的场景:服务器设备性能有差异,部分实例所在机器性能较好,另一些较差,我们希望性能好的机器承担更多的用户请求(Nacos提供了权重配置来控制访问频率,权重越大则访问频率越高)
【配置步骤:】
【实例的权重控制】:
环境隔离
Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离用的,不同命名空间下的服务是没有关系的,是被分离开的相当于放在不同的文件夹下
【命名空间的创建于修改】:
-
步骤一:
-
步骤二:
-
步骤三:获取ID
【将服务添加到自定义的命名空间中去】
Nacos和Eureka的对比
Nacos和Eureka的不同点在下面已经标记:
说明
服务注册时候,都默认该实例为临时实例,但是我们可以通过设置将实例改为非临时实例,下面再order-service中的application.yml修改为例:
Nacos实现配置管理
【问题】:当我们需要修改某个配置文件时(热更新),但是发现该配置文件与很多服务都有联系,所以我们需要对每一个服务都要进行修改,这样会太麻烦,因此Nacos为我们提供了配置管理,统一管理需要进行热更新的配置,要修改的时候只需要再配置管理服务修改,所有的服务就会自动获取修改的配置。
【步骤】:
微服务配置拉取
说明:项目需要先获取nacos中配置管理的配置信息,然后再获取本地配置文件application.yml的配置信息将两种融合才算获取到完整的配置信息;
但是要先获取到nacos的地址才能找到nacos的配置文件,但是nacos的地址放在了application.yml文件中,因此需要另一个比application.yml配置文件更高的bootstrap.yml文件存放nacos的地址
【步骤】:
步骤一:在ueser-service引入Nacos的配置管理客户依赖:
步骤二:再userservice中的resource目录下添加一个bootstrap.yml文件(里面的属性名与nacos的配置文件名userservice-dev.yaml一一对应,比如和userservice服务配置融合,开发环境是dev),这个文件时引导文件,优先级高于application.yml
步骤三:消除application.yml中与bootstrap.yml重复的依赖
【检测】:
在user-service中的Controller中编写测试程序:
Nacos的配置信息:
结果:
配置热更新
【配置热更新】:当修改nacos中的配置信息,相应服务的配置信息能够实时更新,不要去重启项目服务
【实现方法】:
方法一:在@Value注入的变量所在类上添加注解@RefreshScope
,这样nacos一改配置属性,Controller就立马能获取无需重启
方式二:使用@ConfigurationProperties注解,创建一个属性类获取到nacos的配置属性
在Controller类中注入属性类并获取的配置属性
多环境配置共享
【应用场景】:比如某个配置属性在开发、测试、生产等多个环境中均有应用,要是哪天该配置属性需要更改,则需要到多个环境上依次更改,很麻烦,因此提出了多环境配置共性
【步骤】:
在nacos上新建一个userservice.yaml文件作为多环境共享属性文件,并添加配置属性信息
测试:在dev环境下看是否能够督导userservice.yaml文件的属性
因为bootstrap.yml文件没有变,所以我们依旧在dev环境下
在上面的属性类PatternProperties文件中获取到userservice.yaml配置文件中的属性enSharedValue
在UserController中获取到属性并返回到浏览器界面上
结果:我们发现dev环境下的userservice-dev.yaml配置属性与多环境下的userservice-yaml配置属性均能读出来,可以证明不同环境(可以自己添加多个环境测试一下)下都能读取userservice.yaml中的共享配置信息,以达到多环境共享配置的作用
【细节】:要是本地配置文件application.yml、指定环境下的配置文件(如dev环境下的配置文件userservice-dev.yaml)和多环境配置文件(userservice.yaml)中配置了共同的属性(如patern:name:),那么谁的优先级会更高呢?(如图)
nacos集群搭建
nacos配置成集群也是为了防止单点nacos出现问题后导致服务不能使用
【nacos集群框架图】:
【nacos集群部署步骤】:
步骤一:搭建数据库集群,初始化数据库表结构,数据库具体表的创建见黑马nacos集群搭建视频文档
步骤二:进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf
步骤三:在cluster.conf中添加三个nacos的ip
步骤四:在nacos.conf同级目录下找到application.properties文件修改里面配置的数据库信息
步骤五:
分别更改每个nacos的端口号:
nacos1:server.port=8845
nacos2:server.port=8846
nacos3:server.port=8847
步骤六:分别在每一个nacos的bin目录下打开cmd窗口执行startup.cmd命令打开
步骤七:打开nginx文件夹,修改conf/ngnix.conf文件,配置如下(随便在哪添加,可以设置负载均衡)
Feign
基于Feign远程调用
RestTemplate方式调用存在的问题
Feign是一个声明式的http客户端,官网地址为:https://github.com/OpenFeign/feign其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题
【使用Feign的步骤如下】:
步骤一:在服务消费者order-service中引入依赖
步骤二:在order-service的启动类添加注解@EnableFeignClient
开启Feign的功能
步骤三:编写Feign客户端:
步骤四:将原来service目录下的OrderService中原有的RestTemplate代码形式改为:
自定义配置
Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:
一般我们需要配置的就是日志级别。
【配置Feign日志的两种方式】:
方式一:配置文件方式
- 全局生效:
- 局部生效:
方式二:java代码方式
- 步骤一:新增一个配置类,并且在该类下声明一个Bean
- 步骤二:如果将它设置为全局配置,则把
defaultConfiguration = FeignClientConfiguration.class
放在启动类的@Enable FeignClients这个注解中:
如果将它设置为局部配置,则把configuration = FeignConfiguration.class
放到clients目录下的XXXClient类中的@FeignClient注解中
性能优化
【Feign的底层客户端实现】:Feign只是把我们的声明变成http请求,而真实的http请求还是得交给下面几个实现:
- URLConnection:Feign默认的,不支持连接池
- Apache HttpClient:支持连接池(可以减少三次握手的时间达到优化的效果)
- OKHttp:支持连接池
【优化一】:下面我们用Apache HttpClient来替代默认的URLConnection
步骤一:在order-service中引入依赖
步骤二:在order-service中的本地配置文件application.yml中配置连接池
【优化二】:日志级别尽量用none或者basic,减少日志带来的时间消耗
最佳实践分析
方式一(继承):给消费者的FeignClient和提供者的controller定义统一的父接口作为标准【但是会导致服务紧耦合;父接口参数列表中的映射不会被继承;所以不建议】
方式二(抽取):将FeignClient(如下面的UserCient)抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用
实现Feigin最佳实践
【实现最佳实践方式二的步骤如下】:
步骤一:首先创建一个module,命名为feign-api,然后引入feign的starter依赖
步骤二:将order-service中编写的UserClient、User、DefaultFeignConfiguration都剪切(复制加删除) 到feign-api项目中
步骤三:在order-service中引入feign-api的依赖
步骤四:修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api的包
- 导入feign-api中的User:
import cn.itcast.feign.pojo.User
- 导入feign-api中的UserClient:
import cn.itcast.feign.clients.UserClient
- 导入feign-api中的DefaultFeignConfiguration:
import cn.itcast.feign.config.DefaultFeignConfiguration
步骤五:由于我们把order-service中的UserClient、User、DefaultFeignConfiguration放入到cn.itcast.feign包下的Fegin-api中了,导致定义的FeignClient(UserCient类)不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。有两种解决方式:
- 方式一:指定FeignClient所在的包,在order-service的启动类中的
@EnableFeignClient
注解中添加basePackages = "cn.itcast.feign.clients"
- 方式二:指定FeignClient所在的包,在order-service的启动类中的
@EnableFeignClient
注解中添加clients = {UserClient.class}
步骤五:重启测试
Gateway网关
网关作用介绍
【网关的作用】:
【网关的技术实现】:
- gateway
- zuul
Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则时基于Spring5中提供的的WebFlux,属于响应式编程的实现,具有更好的性能。
快速入门
步骤一:创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:
步骤二:编写启动类
步骤三:在getway项目的本地配置类中配置路由以及nacos地址,配置说明如下图一,具体操作见下图二
步骤四:测试
【网关的整个实现流程】:
路由断言工厂
【网关路由可以配置的内容包括】:
- 路由id:路由唯一标识
- uri:路由目的地,支持lb(负载均衡声明地址)和http(具体的IP地址)
- predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地
- fliters:路由过滤器,处理请求或者响应
【路由断言工厂】:
- 我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
- 例如
Path=/user/**
是按照路径匹配,这个规则是由org.springframwork.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的 - 像这样的断言工厂在SpringCloudGateway还有十几个
路由过滤器配置
【路由过滤器GatewayFilter】:
过滤器该做出怎么样的处理呢?这得看过滤器工厂,Spring提供了31种不同的路由过滤器工厂,例如:
【示例】:
给所有进入userservice的请求添加一个请求头:Truth = Itcast is freeking awesome!
实现方式:在gateway种修改application.yml文件,给userservice的路由添加过滤器:
测试:在user-service中的controller种修改代码在控制台打印请求头
另外:如果要对所有的路由都生效,则可以将过滤器工厂写到default下,格式如下
全局过滤器
【全局过滤器GlobalFilter】:
全局过滤器的作用也是处理一切进入网关的请求和微服务响应的,与GatewayFilter的作用一样。==区别在于GatewayFiter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。定义方式是实现GlobalFilter接口。
【需求】:定义全局过滤器,拦截请求,判断请求的参数是否满足下面的条件:
- 参数中是否有authorization
- authorization参数值是否为admin
如果同时满足则放行,否则拦截
【步骤】:
步骤一:在gateway目录下创建一个AuthorizeFilter类并继承GolobalFilter接口
步骤二:编写具体的实现代码
【测试结果】:
过滤器链执行顺序
【过滤器执行顺序】:
- 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
- GlobalFilter通过实现Ordered接口,或者添加
@Order
注解来指定order值,由我们自己指定。 - 路由过滤器和defaultFilter的order由Spring指定,默认按照声明顺序从1递增(即同一类型的过过滤器的order值默认按照声明顺序从1递增,但是order值相同的不同类型的过滤器的优先级大小呢?)
- 当过滤器的order值一样的时候,会按照defaultFilter>路由过滤器>GlabalFilter的顺序执行
网关的cors跨域配置
【跨域问题处理】:
Docker
Docker
Docker的定义
【开发面临的一些问题】:由于大型项目使用的组件工具会很多,并且这些组件应用以后都会部署到Linux服务器上,而这些应用都会依赖Linux操作系统的一些依赖(Dependencies)与函数库(Libraries,Linux的操作命令来操作内核),这么复杂的环境很有可能因为版本问题导致不兼容;并且其开发、测试、生产环境都会有差异
【Docker如何解决依赖的兼容问题呢】:
- 将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
- 将每一个应用放到一个隔离容器去运行,避免互相干扰
【Docker如何解决组件应用跨系统运行(比如Unbuntu和CentOS系统,它们只是系统应用不同,提供的函数库会不一样,但都基于Linux内核)】
【总结】:
Docker和虚拟机的差别
【差别】:Docker如何使组件应用在多环境上运行上面已经介绍过了,而虚拟机是在操作系统中模拟硬件设备,然后运行了另一个操作系统,比如在Windows系统里面运行了一个Ubuntu系统,这样就可以运行任意的Ubuntu应用了。
Docker架构
镜像与容器:
- 镜像(Image):Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像【相当于一个已经配置好的最原始的应用程序(用来被别人复制的,所以镜像是只读的,应用程序就是一个文件夹嘛),而其他的进程想要用它的时候只需要把他复制一份即可(也可以修改,但不能修改原始的那一份即镜像那一份)】
- 容器:镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器做隔离,对外不见
DockerHub
- 如何将镜像共享给其他同事使用呢?借助DockerHub就可以了,DockerHub是一个Docker镜像的托管平台(与GitHub很像,只不过GitHub是做代码的托管平台)。这样的平台统称为Docker Registry,国内也有类似与DockerHub的公开服务,比如网易云镜像服务、阿里云镜像库等。
- 如何从远端拉取镜像和运行 容器呢?这就得了解Docker架构了
Docker的安装
镜像命令
镜像的一些常见命令,有很多但是可以在Linux虚拟机上【控制终端工具FinalShell】通过docker --help命令查询这些基础命令的使用
【命令的使用案例一】:从DockerHub中拉取一个nginx镜像并查看
步骤一:首先去镜像仓库(DockerHub)搜索nginx镜像,直接去DockerHub官网搜就可以了
步骤二:进入nginx,复制操作命令进入终端控制台从DockerHub拉取nginx
**【命令的使用案例二】:利用docker save将nginx镜像导出磁盘,然后再通过load加载回来 **
容器命令介绍
容器命令案例1
【案例】:创建运行一个Nginx容器
【步骤分析】:
【测试结果】:
【日志查询】:
容器命令案例2
【案例】:进入Nginx容器,修改HTML文件内容,添加“传智教育欢迎您”
【结果】:
【注意】:还有其他命令都可以通过docker XX --help(比如删除的细致操作docker rm --help)看它跟细致的操作,在这不一一演示了。
容器命令练习
其他镜像的操作命令都可以在DockerHub的对应镜像的相关指南上找到,可以自己多多实践
数据卷命令
【容器与数据耦合的问题】:
【解决】:数据卷
数据卷(volume)是一个虚拟目录,指向宿主机文件(服务器文件)中的某个目录。
【数据卷的一些常用命令以及演示】:
数据卷挂载案例1
【数据卷挂载的命令】:
【案例需求】:上个案例中,我们进入nginx容器内部,已经知道nginx的html目录所在位置/user/share/nginx/html,我们需要把这个目录挂载到html这个数据卷上,方便操作其中的内容
【步骤】:
步骤一:创建容器并挂载数据卷到容器内的HTML目录
步骤二:进入html数据卷所在的位置,并修改HTML内容
【结果】:
【注意】:当我们创建并运行容器时挂载了一个并不存在的数据卷,Docker会自动帮你创建。
数据卷挂载案例2
【宿主机目录直接挂载到容器的命令】:
【案例】:创建并运行一个MySQL容器,将宿主机目录直接挂载到容器
【思路分析】:
【具体实现】:
步骤一:拖入本地mysql.tar,并加载镜像(docker load)和创建两个文件
步骤二:上传配置文件hmy.cnf到/tmp/mysql/conf下
步骤三:到DockerHub的MySQL查询相关指南(具体的命令)
【数据卷挂载对比】:
自定义镜像-镜像结构
【自定义镜像的目的】:在我们之前,我们使用某个应用程序时候可以拉取或者加载官网镜像并创建容器;但是我们自己的Java项目如何在服务器(宿主机器)创建镜像和容器供别人使用呢(部署在服务器上),使用Dockerfile即可
【定义】:镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。
【镜像结构图】:
自定义镜像-Dockerfile
【Dockerfile的定义】:Dockerfile就是一个文本文件,其中包含一个个指令,用指令来说明要执行什么操作来构建镜像。每一个指令都会形成一层Layer。(==相当于将所有创建指令打包成一个文件,我们只需要执行这个文件即可=)
更详细的语法说明,请参考官网文档:https://docs.docker.com/engine/reference/builder
【案例说明】:基于Ubuntu镜像构建一个新镜像,运行一个Java项目
【步骤说明】:
【实现流程】:
自己些Dockerfile的内容
结果:
【问题】:我们发现创建很多服务的镜像时候,编写Dockerfile有太多重复的了,因此我们可以使用基于java:8-alpine镜像创建自定义的镜像
DockerCompose-初始Compose
Docker Compose可以基于Compose文件帮助我们快速的部署分布式应用(管理服务集群的镜像与容器,把服务集群统一上传到服务器的宿主机器中并把集群中的所有服务创建好镜像并运行容器),不需要繁琐的将服务一个个创建镜像和运行容器!(包括 官方镜像的创建和容器的运行 和 自定义镜像的创建与容器的运行,见下图)
Compose文件是一个文本文件,通过指令定义集群中的每一个容器如何运行。
DockerCompose的详细语法参考官网:https://docs.docker.com/compose/compose-file/
【下载并安装】:
方式一:直接从远端拉取,太慢了
方式二:直接将已有的文档拖进Linux目录下即可,并执行一些配置命令
DockerCompose-部署微服务集群
- 步骤一:准备好cloud-demo文件夹,将所有服务以及相应的文件放进去(具体什么文件下面会解释),另外记得将docker-compose文件也放进去(相当于把对服务集群“创建镜像以及运行容器”的操作命令封装到这个文件里,然后到宿主机器里一起执行):
文件目录:
docker-compose文件说明:
gateway、order-service和userservice文件说明:发现只有Dockerfile文件,我们之前自定义镜像容器创建时是不是还需要服务的打包文件,因此我们需要将服务打包并复制到里面
mysql文件说明:里面包括conf(配置文件,里面有之前需要加载的自定义的配置文件)和data(数据文件,里面有之前所有的数据表文件),因为mysql已经拉取了镜像,不需要复制自己的架包文件到目录下了
- 步骤二:由于之前所有服务都部署在本地主机上,所以服务的调用ip以及端口用的都是本地的(localhost/本地自端口号),现在我们通过docker-compose部署到服务器宿主机器上了,服务之间的访问IP可以使用服务的名字(在docker-compose文件写过),访问的端口可以使用docker-compose文件中映射过的端口,具体我们需要到项目中改:
- 步骤三:前面说过所有的服务文件夹还需要自己的打包文件,我们使用maven打包工具,将项目中的每个微服务都打包为app.jar(为什么要打包成这个名称,怎么打包成这个名称,打包好的文件在哪),并将其打包文件拖如相应的文件夹
- 将cloud-demo上传至虚拟机(拖拽),利用docker-compose up -d来部署
Docker镜像仓库
私有镜像仓库搭建:
方式一:官方搭建无图形化界面的
方式二:搭建有图形化界面的私仓
【方式二实现步骤】:
推送服务镜像到私有镜像仓库,从私有镜像仓库拉取服务镜像