这篇系列博文主要向大家介绍如何使用Spring Cloud和Docker构建微服务平台。
Spring Cloud 是一个 pivotal 提供的用于进行分布式系统构建时提供一些常用的解决方案的工具集。如果你对使用 Spring Framework 构建应用程序很熟悉的话,Spring Cloud 提供了一些常用基础组件的构建服务。
在Spring Cloud 提供的解决方案中,你将会发现如下的问题:
关于Spring Cloud 最重要的部分就是启动Spring Boot的概念模型上。
对于那些刚使用Spring Boot的人而言,他所要做的仅仅是起一个名副其实的项目名,你就会获得一个使用Spring Framework构建的微系统项目,直接转换成使用最小配置,万事俱备的完美的系统应用了。
每一个服务都含有一个特定意义的微服务架构。当你在Spring Cloud上构建微服务架构时,这里有几个基本概念需要首先澄清下。首先,你要先创建Configuration Service和Discovery Service 两个基础服务。如下图所示:
上面的图片说明了四个微服务被创建以及服务之间的依赖关系。
configuration service 处于最顶端,黄色标识,而且被其他微服务所依赖。
discovery service 处于最低端,蓝色标识,同时也被其他服务所依赖。
绿色标识的两个微服务只是一个本地实例应用的一部分,下面我将会使用他们创建博客,分别是:电影和观影建议。
configuration service 在微服务架构中是一个非常重要的组件。基于在 twelve-factor app 上构建的应用,配置你的微服务应用在环境中而不是在本地项目中。
configuration service 是一个必不可少的基础组件的原因是因为它可以对所有通过点对点和检索的基础服务进行服务管理。他的优势在于多用途。
假设我们有多个部署环境。比如我们有一个临时环境和一个生产环境,针对每个环境的配置将会是不同的。每一个 configuration service 将会由一个独立的Git仓库来存放环境配置。没有其他环境能够访问到这个配置仓库,它只是提供该环境中运行的配置服务罢了。
当configuration service 启动后,它将会指向那些根据配置文件配置的路径并启动对应服务。每一个微服务通过读取自己配置文件中的具体环境来运行。在这一过程中,配置是通过版本管理来进行的内部和集中化管理,更改配置不需要重启服务。
通过Spring Cloud提供的服务终端,你可以更改环境配置同时向discovery service 发送一个刷新信号,所有的用户都会收到新的配置通知。
Discovery Service 是另一个重要的微服务架构的组件.Discovery Service管理运行在容器中的众多服务实例,而这些实例工作在集群环境下.在这些应用中,我们使用客户端的方式称之为从服务到服务.举个例子,我使用 Spring Cloud Feign ,这是一个基于RESTFUL风格的微服务提供的客户端,它是从 Netflix OSS project 项目中派生出来的.
```
@FeignClient("movie")
public interface MovieClient {
@RequestMapping(method = RequestMethod.GET, value = "/movies")
PagedResources findAll();
@RequestMapping(method = RequestMethod.GET, value = "/movies/{id}")
Movie findById(@RequestParam("id") String id);
@RequestMapping(method = RequestMethod.POST, value = "/movies",
produces = MediaType.APPLICATION_JSON_VALUE)
void createMovie(@RequestBody Movie movie);
}
```
在上面的例子中,我创建了一个 Feign
客户端 映射了一个 REST API
方法来暴露我的电影服务.使用 @FeignClient
注解,我声明了我想要为 movie
微服务而创建的客户端API.接下来我声明了一个我想要实现的服务映射.通过在方法上声明一个URL规则来描述一个 REST API
的路由规则.
令人兴奋的是,这一切在Spring Cloud都很容易,我所要做的仅仅是知道service ID 来创建我的Feign 客户端.服务的URL地址在运行时环境是自动配置的,因为每一个在集群中的微服务将会在启动时通过绑定 serviceid
的方式来进行注册。
我微服务架构中的其他服务,也是通过上面提到的方式运行。我只需要知道进行通讯服务的 serviceid
,所有的操作都是通过Spring自动绑定的.
API Gateway 服务是Spring Cloud的另一个重要组件.它主要用来创建服务集群并管理自己域名下的应用实例.下图的绿色六边形是我们提供的数据驱动服务,主要用来管理自己域名下的实体类和数据库.通过添加 API Gateway 服务,我们可以为通过下面绿颜色的服务为每一个API路由创建一个代理暴露接口.
让我们假设推荐服务和电影服务都暴露他们自己的REST API在自己管理的域实体上.API gataway通过discovery service和从其他服务注入的基于代理路由的 API方法.通过这种方式,包括推荐服务和电影服务将拥有一个完整定义的路由,通过暴露的REST API获得本地的微服务.API Gateway 将会重定义路由请求到服务实例,这些请求是通过HTTP请求的方式拥有
我已经在github上创建了一个实例项目 ,这个项目是一个端到端的原生云平台,使用Spring Cloud 构建实际的微服务架构.
基本概念:
使用Docker对每一个服务进行构建和部署.使用Docker compose在一个开发机上进行端到端的集成测试.
实例程序中的一个核心概念是如何将混合持久化转化为实际.项目中的微服务使用自己的数据库同时集成通过REST或者消息总线方式从其他的服务提供的数据接入.举个例子,你可以拥有从以下数据库中提供的微服务:
这个例子演示了如何使用微服务创建一个新的应用,而不是单体应用优先策略.由于在项目中的每一个微服务只有一个单一的父项目.开发者为此得到的收益是可以在本机上运行和开发每一个微服务.添加一个新的微服务非常简单,当发现微服务时将会自动发现运行时的集群环境上.
项目中包含两个发现服务,一个在 Netflix Eureka ,另一个使用了
Consul from Hashicorp .多种发现服务提供了多种选择,一个是使用(Consul)来做DNS服务集群,另一个是(Consul)基于代理的API 网关.
每一个微服务都关联Eureka,在整个集群中检索API路由.使用这个策略,每一个在集群上运行的微服务只需要通过一个共同的API网关进行负载均衡和暴露接口.每一个服务也会自动发现并将路由请求转发到自己的路由服务中.这个代理技术有助于开发用户界面,作为平台完整的API通过自己的主机映射为代理服务.
下面的实例将会通过Maven来构建,使用Docker为每一个微服务构建容器镜像.我们可以很优雅的使用Docker compose在我们自己的主机上搭建全部的微服务集群.
在这之前,请先移步至项目的GitHub 仓库.
https://github.com/kbastani/spring-cloud-microservice-example
clone或者fork这个项目并且把源码下载到您自己的电脑上。下载完毕后,你需要使用Maven和Docker 来编译和构建本地的容器镜像.
首先,如果你还没有Docker请先下载它.可以跟随这个 指南 来获取docker,安装并运行在你的开发机上.
当然你也需要安装 Docker Compose ,这个 指南 将会帮到你.
环境要求:
能够运行实例程序,需要在你的开发机上安装下面的软件.
通过命令行方式,构建当前项目,在项目的根目录运行下面的命令.
$ mvn clean install
项目将会根据pom.xml中的每一个项目声明中下载相应的依赖jar包.每一个服务将会被构建,同时Maven的Docker插件将会自动从本地Docker registry
中构建每一个容器镜像.Docker将会在构建成功后,根据命令行运行 mvn clean install
来清除相应的资源.
在项目成功构建后,你将会看到如下的输出:
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] spring-cloud-microservice-example-parent .......... SUCCESS [ 0.268 s]
[INFO] users-microservice ................................ SUCCESS [ 11.929 s]
[INFO] discovery-microservice ............................ SUCCESS [ 5.640 s]
[INFO] api-gateway-microservice .......................... SUCCESS [ 5.156 s]
[INFO] recommendation-microservice ....................... SUCCESS [ 7.732 s]
[INFO] config-microservice ............................... SUCCESS [ 4.711 s]
[INFO] hystrix-dashboard ................................. SUCCESS [ 4.251 s]
[INFO] consul-microservice ............................... SUCCESS [ 6.763 s]
[INFO] movie-microservice ................................ SUCCESS [ 8.359 s]
[INFO] movies-ui ......................................... SUCCESS [ 15.833 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
现在每一个镜像都成功构建完毕,我们使用Docker compose来加速启动我们的集群.我已经将 Docker compose的yaml文件包含进了项目中,大家可以从github上获取.
现在,我们通过下面的命令行启动微服务集群:
$ docker-compose up
如果一切配置都是正确的,每一个容器镜像将会通过在Docker上的虚拟容器和自动发现的网络服务来运行.当他们开始顺序启动时,你将会看到一系列的日志输出.这可能需要一段时间来完成,取决于运行你实例程序的机器性能.
一旦容器启动成功,你将会通过Eureka主机看到通过discovery service注册上来的应用服务.
通过命令行终端复制粘贴下面的命令到Docker中定义的 $DOCKER_HOST
环境变量中.
$ open $(echo /"$(echo $DOCKER_HOST)/"|
/sed 's/tcp://///http://///g'|
/sed 's/[0-9]/{4,/}/8761/g'|
/sed 's//"//g')
如果Eureka正确的启动,浏览器将会启动并打开Eureka 服务的仪表盘,如下图所示:
我们将会看到每一个正在运行的服务实例和状态.通过下面的命令,获取数据驱动服务,例如 movie
服务.
$ open $(echo /"$(echo $DOCKER_HOST)/movie/"|
/sed 's/tcp://///http://///g'|
/sed 's/[0-9]/{4,/}/10000/g'|
/sed 's//"//g')
这个命令将会访问根据导航网关终端提供的代理方式访问 movie
服务的REST API终端.这些REST APIs使用 HATEOAS 来配置,它是一个通过内嵌链接的方式支持自动发现服务的接口.
{
"_links" : {
"self" : {
"href" : "http://192.168.59.103:10000/movie"
},
"resume" : {
"href" : "http://192.168.59.103:10000/movie/resume"
},
"pause" : {
"href" : "http://192.168.59.103:10000/movie/pause"
},
"restart" : {
"href" : "http://192.168.59.103:10000/movie/restart"
},
"metrics" : {
"href" : "http://192.168.59.103:10000/movie/metrics"
},
"env" : [ {
"href" : "http://192.168.59.103:10000/movie/env"
}, {
"href" : "http://192.168.59.103:10000/movie/env"
} ],
"archaius" : {
"href" : "http://192.168.59.103:10000/movie/archaius"
},
"beans" : {
"href" : "http://192.168.59.103:10000/movie/beans"
},
"configprops" : {
"href" : "http://192.168.59.103:10000/movie/configprops"
},
"trace" : {
"href" : "http://192.168.59.103:10000/movie/trace"
},
"info" : {
"href" : "http://192.168.59.103:10000/movie/info"
},
"health" : {
"href" : "http://192.168.59.103:10000/movie/health"
},
"hystrix.stream" : {
"href" : "http://192.168.59.103:10000/movie/hystrix.stream"
},
"routes" : {
"href" : "http://192.168.59.103:10000/movie/routes"
},
"dump" : {
"href" : "http://192.168.59.103:10000/movie/dump"
},
"refresh" : {
"href" : "http://192.168.59.103:10000/movie/refresh"
},
"mappings" : {
"href" : "http://192.168.59.103:10000/movie/mappings"
},
"autoconfig" : {
"href" : "http://192.168.59.103:10000/movie/autoconfig"
}
}
}
这是使用Spring Cloud和Docker构建微服务架构的系列博文的第一部分.在已经介绍完的博客中,我们接触到了如下的概念:
在这之后的博文中,我们将会演示如何使用后台服务来构建前端应用程序.同时也会介绍一个混合性持久化的实例,使用MySQL和Neo4j.
首先我会特别感谢 Josh Long 何spring团队的其他成员给我提供了第一手的令人激动的Spring framework项目.没有Josh Long的支持,我无法用言语表达Spring生态圈给我的研究所带来的令人惊奇的事情.
我还要感谢那些开源工具,例如Spring Cloud,没有这些领军人物的思想,我也无法继续研究.包括 Adrian Cockcroft (Netflix的运营支撑系统), Martin Fowler (所有事), Sam Newman ( O'Reilly's 构建的微服务 ), Ian Robinson (消费者驱动约定), Chris Richardson (VMware的Cloud Foundry)和其他那些使用开源技术改变现在社会的人.