Cloud foundry基础

  • VMware突然发布了业内第一个开源的PaaS——CloudFoundry。 第一部份主要介绍CloudFoundry的架构设计,从它所包含的模块介绍起,到各部份的消息流向,各模块如何协调合作;

      第二部份会在第一部份的基础上,以怎样在你的数据中心里面用CloudFoundry部署一个私有PaaS为目标,把第一部分介绍到的架构知识使用起来。

      第一部份讲的很多内容,会引用Pat在10月12日的VMwareCloud Forum上面关于CloudFoundry架构的演讲。Pat是CloudFoundry Core的负责人,他的那次演讲很值得一听。若你当时在场,且理解他所说的内容,本部份可以选择直接跳过。除了会把说的内容讲具体点外,我不太可能可讲得比他好。

      一、架构及模块

      从总体地看,CloudFoundry的架构如图1所示:


      图1

      这个架构图以及下文所用到的各模块架构图均来自Pat的PPT。从上图能够看到CloudFoundry主要有以下几大组件组成:

      1、 Router

      Router组件在CloudFoundry中是对所有进来的Request进行路由。进入Router的request主要有两类:首先是来自VMCClient或者STS的,由CloudFoundry使用者发出的,管理型指令。

      例如:列出你所有apps的vmcapps,提交一个apps等等。这类request会被路由到AppLife Management组件,又叫CloudController组件去;第二类是外界对你所部署的apps访问的request。这部份requests会被路由到Appexecution,又或者叫做DEAs的组件去。所有进入CloudFoundry系统的requests都会经过Router组件,看到这里可能会有朋友会担心Router成为单点,从而成为整个云的瓶颈。

      但CloudFoundry作为云系统,其设计的核心就是去单点依赖,组件平行扩充,并且可替代的以保证扩展性,这是CloudFoundry,甚至所有云计算系统的设计原则,后文会讨论CloudFoundry怎样做到这点,目前只要知道,系统可部署多个Routers共同处理进来的requests,但Router上层的LoadBalance不在CloudFoundry的实现范围,CloudFoundry只保证所有的request是无状态的,这样就使上层均衡附载选择面非常非常大了,例如可通过DNS做,也可部署硬件的LoadBalancer,或简单点,弄台ngnix作负载均衡器,都是可行的。

      Router组件,目前版本是对nginx的一个简单封装。熟悉ngnix的朋友应该知道,它可一个套接字文件(.sock文件)作为输入输出。所有安装CloudFoundry的Router组件服务器都会安装一个nginx,其ngnix.conf文件有以下配置,如图2所示:


      图2

      从整体的来看,Router组件的结构如图3所示:


      图3

      2、DEA(Droplet Execution Agency)

      首先要解析下什么叫做Droplet。Droplet在CloudFoundry的概念里面是指一个把你提交的源代码,以及CloudFoundry配套好的运行环境,再加上一些管理脚本,例如Start/Stop这些小脚本全部压缩好在一起的tar包。还有一个概念,叫做Stagingapp,就是指制作上面描述这个包,然后把它存储好的过程。CloudFoundry会自动保存这个Droplet,直到你start一个app时,一台部署了DEA模块的服务器会来拿一个Droplet的copy去运行。因此如果你扩展你的app到10个instances,那这个Droplet就被会复制十份,让10个DEA服务器拿去运行。

      如图4所示,是DEA模块的架构图:


      图4

      Cloud Controller模块(下面会介绍)会发送start/stop等基本的apps管理请求给DEA,dea.rb接收这些请求,然后从NFS里面找到合适的Droplet。前面说到Droplet其实是一个带有运行脚本的,带运行环境的tar包,DEA只需要把它拿过来解压,并即行里面的start脚本,就可以让这个app跑起来。到此,app算是可访问,并start起来了,那即是说就是有这台服务器的某一个端口已经在待命,只要有request从这个端口进来,这个app就可接收并返回正确的信息。

      接着dea.rb要做些善后的工作:

      1、把这个信息告诉Router模块。我们前面说到,所有进入CloudFoundry的requests都是由Router模块处理并转发的,包括用户对app的访问request,一个app起来之后,需要告诉router,让它根据loadbalance等原则,把合适的request转进来,使这个app的instance能够干起活;

      2、一些统计性的工作,例如要把这个用户又新部署了一个app告诉CloudController,以作quota控制等;3、把运行信息告诉HealthManager模块,实时报告该app的instance运行情况。此外DEA还要负责部份对Droplet的查询工作,譬如,若用户通过CloudController想查询一个app的log信息,那DEA需要从该Droplet里面取到log返回等。

      3、CloudController:CloudController是CloudFoundry的管理模块。主要工作包括:

      a. 管理service,包括service与app的绑定等;

      b. Cloud环境的管理;

      c. 修改Cloud的用户信息;

      d. 对apps的增删改读;

      e. 启动、停止应用程序;

      f. Staging apps(把apps打包成一个droplet);

      g. 修改应用程序运行环境,包括instance、mem等;

      h. 查看Cloud Foundry,以及每一个app的log信息。

      这似乎有点复杂,简单的说,可很简单:就是与VMCyu STS交互的服务器端。VMC与STS与CloudFoundry通信采用的是restful接口,另一方面CloudController是一个典型的Rubyon Rails项目,从VMC或STS接到JSON格式的协议,然后写入CloudController Database,并且发消息到各模快去控制管理整个云。同其他ROR项目一样,CloudController的所有API可从conf/routes.rb里看到。开放的Restful接口好处在于第三方应用开发与集成,像阿里云这样企业在用CloudFoundry部署私有云时,可通过这些接口来自动化控制管理整个Cloud环境。这部份内容将在第二部份论述。

      如图5所示,是Cloud Controller的架构图:


      图5

      图中Health Manager与DEA是外部模块,CCDatabase就是CloudController Database,这个是整个CloudFoundry不能做HP的地方。CloudController Database的并发性不会很多,应用级别的数据库访问是由底下的Service模块处理的,这个数据库存的是Cloud的配置信息。读操作主要来自DEA启动,作为初始化DEA的依据;以及healthmanager模块会从这里读取预期的状态信息,这部份数据会与从DEA得到的实际状态信息进行比对。

      NFS是多个CloudController的共享存储,CloudController其中一个重要工作就是StagingApps。Droplets的存储是在集群环境的唯一的。而CloudController是集群运行,换言之,就是每一个控制Request可能由不同的CloudController处理,假设一个简单的用户场景:我们需要部署一个app到CloudFoundry中。我们在敲完那条简单的push命令后,VMC开始工作,在做完一轮的用户鉴权、查看所部署的apps数量是否超过预定数额,问了一堆相关app的问题后,需要发4个指令,分别是:

      (1)发一个POST到”apps”,创建一个app;

      (2)发一个PUT到”apps/:name/application”,上传app;

      (3)发一个GET到”apps/:name/”,取得app状态,看看是否已经启动;

      (4)如果没有启动,发一个PUT到”apps/:name/”,使其启动。

      若第2与第4步由不同的Cloud Controller来处理,而又无法保证他们能找到同一个Droplet,那第4步将会由于找不到对应的Droplet而启动失败。怎样保证这一连串指令过来所指向的Droplet都是同一个呢?使用NFS,使CloudController共享存储是最简单的方法。但这个方法在安全性等方面并不完美。在10月12日的VMwareCloud Forum上,Pat告诉我们下一版本的CloudFoundry这里将会有大调整,但在那部份代码公开前,我不方便在这评价太多。

      (5)HealthManager: 做的事情不复杂,简单的说是从各个DEA里面拿到运行信息,然后进行统计分析,报告等等。统计数据会和CloudController的设定指标进行比对,并且提供Alert等。目前HealthManager模块还不是十分完善,但CloudManage栈里面,自动化health管理、分析是一个很重要的领域,而这方面可扩展的地方也很多,结合OrchestrationEngine可使云自管理、自预警;而与BI方面技术结合,可统计运营情况,合理分配资源等。这方面CloudFoundry还在发展中。

      (6)Services:Cloud Foundry的Service模块从源代码控制上看就知道是一个独立的、可Plugin的模块,以方便第三方把自己的服务整合入CloudFoundry生态系统。在Github上看到service是与CloudFoundry Core项目vcap独立的一个repository,为vcap-service。Service模块其中设计原则是方便第三方服务提供商提供服务。在这方面CloudFoundry做得很成功,从Github上看,已有以下服务提供:

      a)MongoDB;

      b) mysql;

      c) neo4j;

      d) PostgreSql;

      e) RabbitMQ;

      f) Redis;

      g)vBlob。

      基类都是放在base文件夹中。

      第三方若需要自己开发CloudFoundry的服务,需要继承改写它里面的两个基础类:Node与Gateway;而里面一些操作,如:Provision,可在base的provisioner.rb基础上加入自己的逻辑,同样的还有Service_Error与Service_Message等。关于怎样写自己的Service,ELC的博客会推出相应文章详细论述,并不在本文的讨论范围里面,从架构了解上来说,只要知道服务间的关系,知道个服务同base间透过继承关系来横向扩充,而CloudFoundry和apps调用Service是通过base来完成这一简单的架构方法即可。

      (7)NATS(Message bus): 从CloudFoundry的总架构图看,位于各模块中心位置的是一个叫nats的组件。NATS是由CloudFoundry的架构师Derek开发的一个轻量级的,支持发布、订阅机制的消息系统。Github开源地址是:https://github.com/derekcollison/nats。其核心基于EventMachine开发,代码量不多,可下载下来慢慢研究。

      CloudFoundry是一个多模块的分布式系统,支持模块自发现,错误自检,且模块间低耦合。其核心原理就是基于消息发布订阅机制。每个台服务器上的每个模块会根据自己的消息类别,向MessageBus发布多个消息主题;而同时也向自己需要交互的模块,按照需要的信息内容的消息主题订阅消息。譬如:一个DEA被加入CloudFoundry集群中,它需要向大家吼一下,以表明它已准备好服务了,它会发布一个主题是”dea.start”的消息:


      图6

      @ hello_message_json中包括DEA的UUID,ip, port, 版本信息等内容。

      再例如,CloudController需要启动一个Droplet的instance:

      a)首先一个DEA在启动的时候,会首先会对自己UUID的消息主题进行订阅。


      图7

      其他模块需要通过’’dea.#{uuid}.start”这个主题发送消息来使它启动,一旦这个DEA接收到消息,就会触发process_dea_start(msg)这个方法来处理启动所需要的工作。

      b)Cloud Controller或者其他模块发送消息,让UUID为xxx的DEA启动。


      图8

      c)DEA模块接收到消息后,就会触发process_dea_start(msg)方法。msg是由其他模块发送过来的消息内容,包括:droplet_id,instance_index, service, runtime等内容,process_dea_start会取得这些启动DEA必须的信息,然后进行一系列操作,例如从NFS中取得Droplet,解压,修改必要环境配置,运行启动脚本等等。等一切都准备好后,然后需要给Router发个消息,告诉它这个Droplet已经随时准备好报效国家,以后有相应的request记得让它来处理。


      图9

      d)Router模块在启动时就已经订阅”router.register”消息主题。


      图10

      收到前面DEA发出的信息后,会触发register_droplet方法,去绑定Droplet。到此启动一个Droplet的instance工作完成。

      我们可看到整个CloudFoundry的核心就是一套消息系统,若想了解CloudFoundry的来龙去脉,去跟踪它里面复杂的消息机制是非常好的方法。另一方面,CloudFoundry是一套基于消息的分布式系统,面向消息的架构是它节点横向扩展,组件自发现等云特性的基础。

      Cloud Foundry的架构简单介绍至此,其实作为第一款开源的PaaS,CloudFoundry架构有很多可学习借鉴的地方,很多细节上的处理是很精妙的,这些内容若有可能会在后续文章继续探讨,本文题虽为深入CloudFoundry,实际上也只是浅尝即止,把总体架构介绍一下,目标在于使我们有足够的背景知识去用CloudFoundry搭建企业内部的私有PaaS。总结一下,笔者从CloudFoundry的结构中学到的东西:

      1、基于消息的多组件架构是实现集群的简单、且有效方法。消息可以使集群节点间解耦,使自注册,自发现这些在大规模数据中心中很重要的功能得到实现;

      2、适当的抽象层,模板模式的使用,方便第三方可以方便在CloudFoundry开发扩展功能。CloudFoundry在DEA及Service层都做了抽象层处理,相对应地使开发者可以容易地为CloudFoundry开发Runtime和Service。例如,在CloudFoundry刚推出的时候,只支持Node.js,Java, Ruby,但第三方提供商、开源社区快速跟进,为CloudFoundry添加了PHP,Python的支持。这得益于CloudFoundry精巧的DEA架构设计,如何开发新的Runtime支持,会在后续博文中有所论述.

      二、源码导读

      笔者一直觉得深入理解一个技术的最好方法就是读它的源码,而CloudFoundry是完全开源的PaaS平台,而因为刚发展起来,代码量不多,主要作者们的代码功力也相当不错,读起来很舒服,很适合研读。而不得不再次表扬一下它完全基于消息机制的架构设计,对组件扩展性,第三方接入等方面做得很好,读者可以从中学到不少思想性的东西。笔者很推荐大家去读一下它的源代码。你可以在Github上找到CloudFoundry的全部代码:https://github.com/cloudfoundry,你会看到几个不同的Repositories,它们分别是:

      1、vcap: Cloud Foundry的Core,又或者称作Kernel;

      2、vcap-service: Cloud Foundry的Service组件。Cloud Foundry的service是作为插件提供的,这出于它方便第三方开发service而设计的;

      3、vmc: VMware Cloud CLI. 是一个Ruby应用,与Cloud Foundry的CLI交互。主要通过分析用户输入的CLI,向CloudFoundry发送Restful请求;

      4、vcap-java: 如果你的app是用java开发,且需要与Cloud Foundry交互,例如取得当前serviceserver的ip地址等,你可能需要这个jar,里面对我们Java开发常用框架有所支持,它底层也是对CloudFoundry的Restful请求的包装;

      5、vcap-java-client: Cloud Foundry的Restful API的Java封装,与上面的项目不一样,它只是个简单的读取CloudFoundry信息,并放如JavaBean中;

      6、vcap-test: Cloud Foundry的test cases;

      7、vcap-test-assets: Cloud Foundry一些apps示例。




Cloud Foundry 组件概述

Cloud Foundry 组件包括了一个自服务的应用执行引擎、一个用于应用部署和生命周期管理的自动化引擎、一个脚本命令行接口(CLI)、以及与开发工具的集成以简化部署过程。Cloud Foundry 有一个开放的架构,其中包括一个用于添加框架的 buildpack 机制、应用服务接口和云提供商接口(CPI)。

这里写图片描述

路由

Router

Router 将传入的流量路由到适当的组件,要么是一个Cloud Controller 组件,要么是在Diego Cell 上运行的托管应用。

Router 定期查询 Diego Bulletin Board System(BBS),以确定每个应用当前运行的 cell 和容器。使用这些信息,Router 根据每个cell 虚拟机(VM)的IP地址和 cell 容器的主机端端口号重新计算新的路由表。

认证

OAuth2 Server (UAA) 和 Login Server

OAuth2 Server (UAA) 和 Login Server 一起工作以提供身份管理。

应用生命周期

Cloud Controller 和 Diego Brain

Cloud Controller (CC) 指导应用的部署。为了将一个应用发布到 Cloud Foundry 上,需要target Cloud Controller。然后,Cloud Controller 通过CC-Bridge 组件将 Diego Brain 引导到协调各个Diego cell 来stage和运行应用。

Cloud Controller 还维护orgs、spaces、user roles、services 等的记录。

nsync、BBS 和 Cell Reps

为了使应用可用,云部署必须不断地监控它们的状态,并将它们与预期的状态进行协调,并根据需要启动和停止进程。

这里写图片描述

nsync、BBS和Cell Rep组件一起工作在一个链上,以保持应用的运行。一端是用户,另一端是在广泛分布的vm上运行的应用实例,它们可能会崩溃或不可用。

  • 当用户scale应用时,nsync会从Cloud Controller 收到一条消息,它会将实例的数量写入Diego BBS数据库的DesiredLRP中。
  • BBS使用它的convergence进程来监控DesiredLRP和ActualLRP的值。它将启动或杀死应用实例,以确保ActualLRP数量与DesiredLRP数量匹配。
  • Cell Rep监视容器并提供ActualLRP值。

应用存储和执行

Blobstore

blobstore是大型二进制文件的存储库,Github无法轻松管理,因为Github是为代码设计的。Blobstore二进制文件包括:

  • 应用代码包
  • Buildpacks
  • Droplets

可以将blobstore配置为一个内部服务器或一个外部S3或与S3兼容的端点。

Diego Cell

应用实例、应用任务和staging任务都在Diego Cell VM 上作为Garden容器运行。Diego cell rep 组件管理这些容器的生命周期,并在它们中运行进程,将它们的状态报告给Diego BBS,并将它们的日志和指标发送给Loggregator。

服务

Service Brokers

应用通常依赖于诸如数据库或第三方SaaS提供商之类的服务。当开发人员提供服务并将服务绑定到应用时,该服务的service broker 负责提供服务实例。

通信

Consul 和 BBS

Cloud Foundry组件虚机内部通过HTTP和HTTPS协议相互通信,共享存储在两个位置的临时消息和数据:

  • Consul server 存储较长期的控制数据,例如组件IP地址和分布式锁,这些锁可以防止组件复制操作。
  • Diego 的Bulletin Board System (BBS)存储了更频繁的更新和一次性数据,如cell和应用状态、未分配的工作和心跳消息。BBS在MySQL中存储数据,使用MySQL驱动程序。

route-emitter组件使用NATS协议将最新的路由表广播到router。

指标和日志

Loggregator

Loggregator (log aggregator)系统将应用日志记录给开发人员。

Metrics Collector

Metrics Collector 从组件收集指标和统计信息。操作人员可以使用这些信息来监控Cloud Foundry 的部署。

Cloud Foundry使用GitHub上的git系统来版本控制源代码、buildpack、文档和其他资源。平台上的开发人员也可以使用GitHub用于自己的应用、自定义配置和其他资源。为了存储大型二进制文件,例如droplets,CF维护一个内部或外部的blobstore。为了存储和共享临时信息,例如内部组件状态,CF使用MySQL、Consul和etcd。

Cloud Foundry是业界领先的PaaS云平台,可以为应用提供高可用的运行平台,现在很多运行商都在使用Cloud Foundry为用户提供应用服务,如IBM、AWS等。自Cloud Foundry面世以来便一直使用BOSH来创建和更新生产服务。BOSH是一条开源工具链,用于对大规模分布式服务进行发行版工程处理、部署和生命周期管理。它包含一个云提供商接口(CPI),如VMWare,通过调用CPI完成整个Cloud Foundry的创建、部署和升级。


Kubernetes经过几年的发展越来越成熟,遍布全球的数百位开发者纷纷投身到Kubernetes的快速迭代中。越来越多的企业开始采用Kubernetes支撑生产业务,实现了高可用的容器化微服务。


但原来用户如果想继续在Kubernetes上使用Cloud Foundry,那该怎么做呢?现在业界没有一个标准的做法。较为正规的方式是开发一套完整的Kubernetes的CPI,然后利用BOSH将Cloud Foundry部署在Kubernetes上。但BOSH设计初衷是面向IaaS的部署工具,它首先需要一个Linux的虚拟机模板 Stemcell,Cloud Foundry的不同组件通过BOSH安装在基于这个Stemcell构建的虚拟机上。这种部署方式在Kubernetes上有一个很大的问题,就是当部署的Cloud Foundry组件,如Cloud Contorller或者Router的Pod因为一些原因坏了或者重启了,那么重启回来的Pod只是一个空的Stemcell,没有任何的组件信息,只能通过BOSH re-create为组件创建新的虚拟机:


640?wx_fmt=png&wxfrom=5&wx_lazy=1


使用BOSH在Kubernetes上部署Cloud Foundry还有一些其他问题和弊端:


  1. BOSH现在主要适用于IaaS

  2. 需要开发新的Kubernetes CPI

  3. 部署时间过长

  4. 需要手工执行许多配置,如网络和资源等


现在业界有很多厂商都在研究如何更好更快地将Cloud Foundry部署在Kubernetes上,如SUSE的SCF和Cisco的Container CF等。虽然现在还没有发布用于生产环境的版本,但思路相比BOSH更贴近Kubernetes的使用方式,也更融合Kubernetes。主要的方式就是通过制作相对应的Cloud Foundry组件的Docker Image,部署的时候直接部署对应的Docker Image,然后在运行容器之前,通过配置信息和环境变量,设置容器参数使整个Cloud Foundry组件之间可以相互通信。即使哪个Cloud Foundry组件坏了或者被重启了,组件使用已创建的Docker Image可以快速启动,只是在启动时需要重新配置一下参数。它相对之前BOSH的部署方式,好处显而易见:


0?wx_fmt=png


那么我们就以SUSE的SCF为例,看看它到底是如何做到的?


0?wx_fmt=png


  1. 首先我们需要将BOSH的工程通过SUSE的转换工具fissile将其编译并制作成Docker Image。

  2. 之后我们需要通过Helm将预设的参数转换成Helm或者Kubernetes的配置资源文件。

  3. 最后通过Helm将整个CF部署到Kubernetes上。


下图是和传统的BOSH CPI的部署方式的比较,绿色部分为新的Fissile + Helm 方式改变的步骤。但这些绿色步骤只需要管理员执行一次来创建Docker Image,之后就可以重复使用了。最终用户只需要执行橙色步骤,修改自己配置文件,下载相应的Docker Image,部署整个Cloud Foundry。整个部署Cloud Foundry的时间大概在15-20分钟,这和之前BOSH部署4-6个小时相比,快了很多:


0?wx_fmt=png


接下来我们就来看看如何利用SCF在Kubernetes上快速部署一个Cloud Foundry,如下图:


0?wx_fmt=png


  1. 首先我们需要一个性能较好的机器并且可以连接外网并安装Vagrant。

  2. 克隆整个SCF的Git项目 https://github.com/SUSE/scf

  3. 执行相应的Vagrant命令启动构建环境。

  4. 进入Vagrant创建的虚拟机,执行 make vagrant-prep 命令创建工程、编译并制作Docker Image,这个过程大概需要2-3个小时,但只需要执行一次。

  5. 上一步正确完成后,执行make kube,根据预设配置,创建Helm或Kubernetes配置资源文件。

  6. 最后执行make run将整个Cloud Foundry部署到Vagrant自带的Kubernetes上。

  7. 你也可以通过它自带的pod-status来观察整个Cloud Foundry的状态。大概15-20分钟之后,所有的Pod都启动了,Cloud Foundry就可以使用了。


所有相关信息都可以在SCF的Git中找到:https://github.com/SUSE/scf。


下图为部署成功后SCF显示的环境信息:


0?wx_fmt=png


下图为部署在Kubernetes上所有Cloud Foundry组件的Pod的运行状况:


0?wx_fmt=png


当然,SCF现在做的只能将Cloud Foundry运行在Vagrant创建的Kubernetes上。你也可以把创建的Cloud Foundry组件的Docker Image上传到外部的Docker Hub上,然后使用Kubernetes的配置资源文件将你的Cloud Foundry部署到你自己的Kubernetes上。

猜你喜欢

转载自blog.csdn.net/zyc88888/article/details/80411370
今日推荐