在CAAS系统出现前企业应用架构基本被IAAS/SAAS/PAAS等模式垄断,直到docker的出现为咱们打开了另外一个扇大门,废话不说了,咱们直奔主题mysql
咱们先了解下一个简单的CAAS系统是如何为用户提供服务的web
企业用户上传它的应用代码或其余代码托管方式,咱们生成用户应用的镜像,或者用户直接上传镜像,或者用户直接使用咱们提供的基础服务镜像redis
用户部署他的镜像应用,启动它的镜像容器算法
用户访问他的应用服务sql
OK,需求肯定了,该搬砖了docker
既然是一个简单的CAAS系统,咱们就不让用户上传代码或者使用第三方代码托管了,直接让他们制做镜像后提交给咱们,为此咱们须要搭建一个docker私服来让用户上传镜像,假设用户上传的镜像遵循这种格式:
docker私服地址/{appId}:{version},这对用户有必定要求,毕竟一些用户可能连docker是啥都不知道就更别奢望让他们编写dockerfile制做镜像交付给咱们了。固然若是咱们提供一些基础服务镜像(好比mysql服务,redis服务等)给用户那最好了。数据库
有了用户制做的镜像,该是启动它的时候了后端
docker pull docker私服地址/{appId}:{version} docker run -d docker私服地址/{appId}:{version}
启动方式很简单,但这并非咱们想要的,毕竟咱们是要让用户可以访问到他部署的服务的,假如用户的服务是一个web服务,那你得暴露出用户的web服务端口,这须要咱们肯定容器的通讯方案:api
跟宿主机共用一个网络空间缓存
发布一个容器端口,让docker随机选择一个未使用的高位端口
发布一个容器端口,并映射到宿主机上指定端口为外部路由服务
采用docker的'links'来容许容器间通讯。 若是一个新容器连接到一个已有容器,新容器将会经过环境变量得到已有容器的连接信息,一个关联的容器将会得到它的对应链接信息,在它处理了那些变量后容许它自动链接。这样就使得同一个宿主机上的容器不须要知道对应服务的端口和地址,就能够直接进行通讯
咱们简单的CAAS系统暂时还用不到容器间通讯,若是跟宿主机共用一个网络空间即--net="host"模式启动的话,那么若是有多个用户上传了镜像,他们的WEB服务端口都是8080,显然宿主机上只能启动一个8080端口,只能有一个用户的容器启动成功,其余的由于端口已经被占用致使启动失败,在这里咱们选择第三种模式,选择指定的端口映射来发布容器,这也方便咱们后面管理宿主机上的端口资源。OK,启动方式改为下面:
docker run -d -p 25701:8080 docker私服地址/{appId}:{version}
为了避免让某个用户的应用占用过多资源致使影响到整个宿主机上其余的应用,咱们稍微对用户的资源进行下限制,好比限制用户应用容器的使用内存和CPU权重
docker run -d -p 25701:8080 -m 512M -c 1024 docker私服地址/{appId}:{version}
为了能作到水平扩展,容器服务最好是无状态的的,这样能更好的实现负载均衡和水平扩容。
应用启动成功,咱们能够经过在宿主机上访问25701便可访问容器的8080端口服务
在写代码的时候咱们经过Docker Remote API client libraries来启动卸载容器,具体代码实现就很少说了。
容器启动成功后,用户该如何访问到他的容器服务呢,总不能提供宿主机IP给用户直接访问吧,这就须要咱们构建一个服务发现组件了
当每个服务启动上线以后,他们经过发现工具来注册自身信息
服务的消费者可以在预设的终端查询该服务的相关信息,而后它就能够基于查到的信息与其须要的组件进行交互
为了简便,咱们使用zookeeper来做为咱们的服务发现工具
首先在容器启动成功后咱们将服务注册到zookeeper中,存储的path路径以下:/caas/service/address/{appId}/{version},存储的服务子节点为{containerId}->{宿主机IP}:{服务端口}
例如用户appId01和appId02分别部署了各自的应用版本容器containerId01和containerId02,对应的服务端口分别为25701和25702,那么zk里存储的注册表信息为下:
/caas/service/address/appId01/app01Version/containerId01 -> {宿主机IP}:25701 /caas/service/address/appId02/app02Version/containerId02 -> {宿主机IP}:25702
若是一个用户部署了多个容器实例,对应的zk注册表信息相似下面:
/caas/service/address/{appId}/{version}/containerId01 -> {宿主机IP}:25701 /caas/service/address/{appId}/{version}/containerId02 -> {宿主机IP}:25702 /caas/service/address/{appId}/{version}/containerId03 -> {宿主机IP}:25703 /caas/service/address/{appId}/{version}/containerId04 -> {宿主机IP}:25704
以上咱们完成了服务的注册,注册完服务后为了实现应用的高可用,咱们应该还须要对容器进行故障检测,故障检测的方案一般有下面2种:
组件主动请求服务发现心跳方式:组件能够设置一个超时时间,并能按期去请求服务发现来重置超时时间,超时时间达到阀值更新注册表
服务发现主动请求组件心跳方式:服务发现按期的健康检查组件以及当组件出现故障时更新注册表
一般内部本身的服务可使用第一种方式让组件主动请求服务发现,用户本身写的服务通常不可能费劲的去实现心跳来访问服务发现组件,因此一般会要求用户实现一个服务发现组件能访问的心跳接口,让服务发现组件去主动请求用户的应用,一旦访问失败在重试必定次数后会认为该应用已经出现故障没法继续提供服务,这时能够根据策略来选择直接中止删除该用户容器或者从新启动。
好比服务发现的健康检查组件能够每隔必定时间来访问用户的心跳接口,相似{宿主机IP}:25701/_ping
基于安全方面考虑,一般状况下咱们须要对服务发现作相应的访问控制,以便对注册表中的存储信息实现安全访问,可能有如下几种方案可供参考:
服务发现工具能够采用SSL/TLS加密连接
对写入数据进行加密,使用者使用的信息必须用相应的密钥解码从服务发现中获取
服务发现实现访问控制,将不一样的键值切分到不一样的分组中,根据访问的须要来制定不一样的秘钥从而访问相应的分组
这里咱们就不说具体的安全方面的实现了,谁让咱们是简易版CAAS系统呢。
其实服务发现的注册表存储访问地址只是其中的一个方面,你能够用它来存其余的信息,好比存应用的配置,你能够经过配置动态的调整应用,也能够存容器的相关指标,负载均衡就是一个很好的例子,它能够经过查询服务发现获得各个后端节点承受的流量数,而后根据这个信息来调整配置。具体的负载均衡算法能够根据需求来选择,咱们就使用最简单的round bobin算法,即轮询方式访问。这方面的实现涉及到CAAS系统的另外一个组件:路由网关,具体后面介绍。
上面咱们一直都是使用了zookeeper来做为服务发现工具的,除了zk,咱们还可使用其余的服务发现工具:etcd、consul、crypt、confd,你们有兴趣能够了解下,最重要的是能保证注册表信息的数据一致性。
经过上面几步你的CAAS系统基本小有所成了,但这还不够。咱们在生产环境里随着用户应用容器的数量增长须要增长宿主机来支撑避免资源不足,或者将某些用户的实例单独部署在指定的宿主机上,这就须要咱们实现一个调度器组件。
CAAS系统是一个分布式系统,在多个宿主机的环境里,咱们须要知道用户的应用该部署在哪台宿主机上,若是单机的话那就不须要选择了,直接指定就行了。具体该如何调度须要考虑如下几点:
须要一个默认的调度策略,好比选择可用内存最多的宿主机部署服务或选择cpu最空闲的宿主机部署服务
调度器须要提供覆盖机制,好比2个容器必须部署在同一个宿主机上做为一个单元来运行,好比同一个服务的2个实例容器必须部署在不一样机器上来达到高可用
调度器须要知足限制条件,好比给特定的宿主机打标签,好比一些服务须要部署在集群中的每一台宿主机上
随着业务的扩展,咱们可能须要提供分组容器管理,将一个集合的容器(一般是有相互依赖关系紧密关联的组件)做为一个单独应用来处理,好比一个web服务容器再加上后端的数据库服务容器组合成一个project来发布。这里就很少作讨论了,咱们的简易版系统还没考虑到这步。
供应是指将一个新主机上线并完成基本配置使得它们可以工做的一个过程,一般在集群管理里用来自动扩展宿主机,管理工具来定义需求额外主机的过程以及自动触发的条件,例如,若是你的应用的负载很高,你可能但愿让你的系统增长额外的机器并水平扩展容器以缓解负载,这里咱们一样不作实现,简易版就直接手动增长宿主机就行了嘛。
咱们在这里举个实现调度器的相对简陋的方案:
主要使用关系型数据库如mysql来存储宿主机信息,调度器查询宿主机的相关指标信息根据调度算法选择相应的宿主机来部署,利用乐观锁来保证并发操做时的数据一致性,利用事务来保证部署和卸载等操做的原子性。这里面可能坑比较多,你们也可使用如今比较流行的调度器,经常使用的调度器有:fleet、marathon、Swarm、mesos、Kubernetes、compose,你们有兴趣能够了解下。
上面咱们在服务发现的负载均衡方面介绍到了网关,咱们把它做为CAAS系统中重要的一个组件,他主要是负责用户请求的转发,举个例子用户部署了容器想要访问它的容器服务,这个请求到达网关后网关根据策略选择相应的后端容器服务而后转发请求。根据用户的设定,动态路由请求到对应容器实例,这至关于一个代理服务器。具体如何选择容器实例服务转发就须要实现负载均衡器,咱们能够经过查询服务发现组件来获取相应容器信息来完成。既然是代理服务,咱们在中间能够对用户的请求作其余处理,好比作黑名单过滤,作流量统计,作CNames路由等等
假设咱们的CAAS网关访问域名是mycaas.gateway.cn,用户在咱们后台部署了一个WEB应用容器实例,调度器将他部署在了10.10.10.101宿主机上,容器服务端口映射为25701,用户请求mycaas.gateway.cn到达网关后,网关根据请求信息识别用户查询该用户全部的应用容器信息,获得全部的容器服务地址,根据负载均衡规则代理转发到目标容器服务上。这个查询服务发现的过程当中最好实现本地缓存,好比使用zookeeper的缓存减小和避免每次请求都访问服务发现组件,同时代理转发中尽可能使用链接池减小开销。
至此咱们简单的CAAS系统就架构设计好了,在整个系统中有服务发现/调度器/网关等多个组件协调配合。
做者信息
做者来自力谱宿云LeapCloud旗下MaxLeap团队_云服务研发成员:David Young
首发地址:https://blog.maxleap.cn/archi...
相关文章
欢迎关注微信订阅号:MaxLeap_yidongyanfa