美团云的Docker实践之路

ReynaldoGra 8年前
   <p>本文根据美团云工程师郑坤在2016.1.26北京容器大会上的分享内容整理</p>    <p>首先自我介绍一下,我是来自美团云的工程师:郑坤。</p>    <p>很高兴能和大家分享我们从去年(2015.6)到现在(2016.1)美团云在设计和开发上的一些思路和心得。</p>    <p>美团云是公有云提供商,我们从云提供商的角度来看,如何从云平台端为用户提供更好的Docker服务。不过今天分享的内容都是私有云场景下的,因为截止目前(2016.1)Docker还存在多租户安全隔离问题,这个问题还不是很容易解决。</p>    <h2>Why(我们为什么要用Docker?)</h2>    <p>2012年美团上线私有云,2013年共有云正式上线,刚开始所有业务和交易都放在私有云上(KVM和VM),后来迁移到了Docker上,怎么说服内部要做迁移的呢?这里用美团的外卖业务举个例子:外卖每天都有几个时间段内峰值是很高的,为了支撑业务我们有提供弹性的需求,VM来做弹性的话效果不是很理想,scale out周期太长无法满足,资源的回收也是个问题。Docker的轻量级/高效/敏捷灵活能很好的满足需求。</p>    <h2>How(MOS是怎样使用Docker的?)</h2>    <p>Docker发展了这几年,生态链已经日趋完善:编排、仓库、监控等都有很多startup在做,也已经做出了很多现成的东西。我们美团云内部有自己的控制器、registry、网络、除了镜像仓库和身份鉴别用的是openstack的glance和keystone外,剩下的所有组建都是自己写的,镜像仓库的后端也在开发计划中。</p>    <p>现在主要问题是怎样结合现有架构来使用Docker,在可接受的成本内如何发挥Docker自身的优势来实现快速开发、部署和上线,然后不适合Docker的地方就尽量针对VM来做优化:主要是low latency、批量调度、启动、创建等的流程的优化。详细分为几个部分:控制计算和调度架构用美团云现有的VM框架,镜像仓库和后端存储为glance和swift,目标是支持Docker;然后宿主机要支持Docker;使用统一的配置方式来配置网络;最后是隔离和鉴权,目前私有云对这方面要求不高。</p>    <p><img src="https://simg.open-open.com/show/23fdfbe976e8a3797dc92d58ec55130b.png"></p>    <p>如图示美团云Docker系统框架,这个框架其实也是美团云的框架,为Docker和VM共同复用。共用框架的好处是我们可以用一个云平台同时支持VM和Docker两种不通的计算服务,有效降低我们的开发、运维的成本。Docker和VM复用的前提条件是一致的数据结构定义,统一的API接口规范。我们将Docker的镜像、容器、网络都用已有的VM对应的数据结构定义。整个系统框架由4部分构成:</p>    <ul>     <li>客户端</li>     <li>控制器</li>     <li>宿主机服务</li>     <li>镜像仓库</li>    </ul>    <p>客户端工具是一个CLI,有两个接口:一个对Docker镜像的管理接口,一个是对容器/set的管理接口。通过一个客户端可以管理Docker镜像,也可以控制容器的创建、删除、启动停止等操作。</p>    <p>控制器:Docker和VM复用一个控制器,负责API处理、Docker容器的数据库管理,任务控制等计算服务</p>    <p>镜像仓库:负责Docker镜像的存储。分为两个部分,Glance是数据库和API,后端存储是分布式的key-value存储系统,由美团云自主开发。set,</p>    <p>宿主机服务:负责容器的控制执行、监控等功能。</p>    <p>所有组件都是通过RESTful API通信。</p>    <p>对于Docker的控制流,我们复用了原有的VM API,支持:create、start、stop、suspend、sync-status、delete、update、deploy等,然后rebuild_disk备份,重置密码,传文件都可以在容器当中执行。</p>    <p>云平台上的基础设施包括我们在宿主机上更好的储存网络、本地服务管理等等,Docker都可以复用。</p>    <p><img src="https://simg.open-open.com/show/9b0bf8daef476513be270af89a62bfb7.png"></p>    <p>如图,我们看一下美团云Docker的相关组件,mcclient是我们的客户端,自己开发的。keystone是openstack的,Region就是我们的控制节点;对象存储swift,和一个自研的后端存储,预计2016.3上线;host是自主开发, image glance 是openstack组件。从接入层来说,红色的部分是我们做扩展的部分,蓝色的部分是没有修改的。控制层有两个节点:一个是region是控制节点,还有glance image节点,glance image负责管理镜像,所有Docker的镜像操作都是由glance来控制的,由DB来提供维护的信息。容器我们把它当成是VM或者server,那它就由region来控制;主机端:Host server部分我们也做了扩展。</p>    <p><img src="https://simg.open-open.com/show/cf2b7c2c437314933a6a5b55d0b1f03a.png"></p>    <p>我们举一个简单的例子:一个镜像查询功能,我们怎么把查询一个镜像是否上传、是否存在,绿色的线就是客户端那边通过RESTful API查询glance,蓝色的是镜像,去查glance,glance这里会带身份认证的keystone,然后它会去先拿token查glance,glance拿着这个token到keystone去认证,认证通过就去检查数据库,然后返回信息。所以说容器也是一样,我们把容器当成VM了,所以指的是在region节点。</p>    <p><img src="https://simg.open-open.com/show/4634ddb3b7bc81781006ba9ae89e19b4.png"></p>    <p>我们来看稍微复杂一点的,如上图:一个容器的创建,可能这里面就有更多的细节。这个说一下,就是云平台大家知道访问的时候都需要鉴权的,第一步还是要获取keystone去拿token,然后带着token去发起post请求,这边创建一个server的时候,它首先去glance查询创建server的Docker load在不在,如果存在的话就把这个请求发到Host server,Host server去拿这个token的时候到glance拉Docker的镜像,我们把这个镜像通过Docker的pull 把它下到Docker的本地,这样的话就完成了准备工作。然后这个流程回来的时候,再到region,如果这一边就是auto start,那么region把这个调过来,把这边启动变成Docker start的一个API,这时在数据库上这个容器就起来了。当然整个过程全是layer pull的API的形式,所有的流程都是自动化的。虽然过程看起来比较复杂,但实际上所有地方都很快。</p>    <p>刚才谈到的是计算,现在来谈一下存储。</p>    <p>一个Docker镜像实际上是由若干个子镜像,或称layer组成的,每个layer里面再打开,就发现里面是有若干个文件还带一个reference文件。Docker镜像的存储,分层打包这一块的创新是Docker的创新,Docker公司将这个申请专利了。Docker将底层存储,镜像打包,部署、存储这一些列功能都做到了Docker daemon里,底层文件系统的细节,容器的namespace隔离细节,大家都不用关心。这里面有很多精妙的设计,docker commit之后,在container上面加了一层FS。Docker把FS这些复杂性的东西都屏蔽掉然后封装起来。只要Docker pull、 Docker run就能搞定。所以Docker image包含了业务运行的一个环境配置,如果要把image保存到仓库里,就可以把每一层layer看成是一个key-value的一个object对象,Glance实际上就是保存着key-value的一个object对象,每一层layer就当成一个对象,但是Glance每一个对象之间是没有一个逻辑关系的,也就是说没有一个逻辑来组织这些镜像。一个Glance的一个VM镜像就是一个VM镜像。所以它跟Docker不一样,因为Docker是由N个镜像组成的,我们做的事情就是把Docker做成像Glance这样简单化,我们把Glance加了一个Docker ID,即每个镜像都带一个ID,它可以指向它到父镜像,也就是每一层layer都单独保存并记录它们的继承关系,然后保存到Glance数据库中,这样我从Glance上去查Centos的时候,对应这个parent,我把这个layer一层层显示出来,和我们用Docker image是一样的。</p>    <p>接下来谈谈网络。</p>    <p>网络是另一大块标准化突破,大家都用Docker的一个原因是Docker的灵活性,给大家提供了灵活性。网络Docker支持四种网络配置模式,美团云选择了None,也就是说在宿主机上可以看到,云服务商你们买VM,网络和IP是云服务商提供的。所以我们分给容器更多的IP,我们内部网络,二层网络我们自己做,那这个IP从来没有通,我们就需要在容器的配置上把这个网络,这个IP配进去。先讲一下宿主机网络,美团云的宿主机网络是用OVS做本地管理的,OVS一端连着物理接口,从网卡出去直接到物理交换机。另一层通过port连接本地的VM。容器也是一样的,在启动的时候创建一个eth pair,然后把它放到容器的Namespace里面,另一端接入到OVS当中,然后我们的网络隔离是在OVS的flow table上做的,这是一个事先做好的,只要网络配好,容器会自动带有网络隔离的功能。我们对网络的限流、限速是在eth这个物理网卡跟tc这块来做,这样做之后,原来对VM的这些flow table全都在Docker上自动生效,不需要为限速等功能做额外的开发。</p>    <p>我们再来说说set。</p>    <p>先讲一下PaaS,我们之前调研过业界PaaS平台,包括主流的Kubernets,对我们来说,k8s太大了,过于复杂,需要专业的团队搭建集群,运维,开发。短期内难以满足我们快速迭代、快速定制功能满足需求,以及稳定性的要求。我们更倾向于利用现有的云平台,采纳k8s比较先进的设计思想,通过扩展云平台来支持我们的PaaS。经过调研,我们发现k8s有很多可以借鉴的地方,比如说Pod。Pod设计上一个很先进的地方在于它很适合微服务,一个Pod由多个容器组成,对应一个微服务,Pod内的容器是共享网络和volume的,因此一个微服务内的通信成本是非常低的。结合美团的业务来说,我们的每一个线上服务都是标准化的,即一个服务是由若干个进程组成的。典型的服务包含几个进程:infra进程、sg-agent进程和app进程。</p>    <p>infra 进程:负责网络、volume配置</p>    <p>sg-agent进程:负责日志收集工作和其他支撑服务</p>    <p>app进程:负责具体的业务。</p>    <p>在VM环境里,一个服务的几个相互依赖的进程最好放到一个VM内,而对于Docker,这几个进程最好放到一个容器内。但Docker的哲学是一个容器跑一个进程。自然就联想到Pod。我们把几个容器抽象成一个Pod,部署到一个宿主机上,容器之间共享网络,共享volume。Set,可以说是我们美团云版本的Pod,它是调度的基本单位,你不能将set内的几个容器调度到不同的宿主机上。它代表一个微服务实例,所以业务的扩容、缩容,都是以set为单位的。</p>    <p>最后介绍一下项目发展情况,私有云方面,我们在和另外一个基于Docker弹性伸缩的开发团队合作,他们调用我们的接口实现业务的弹性扩容缩容,目前在公司内部已有一些用户,2016年将大规模推广。公有云方面,2016年将接入美团云的PaaS服务。</p>    <p>我们2016年的规划,项目从2015年开始调研,立项,开始开发,上线私有云;2016年准备接入RDS,上线公有云调研,开发。</p>    <p> </p>    <p><a href="/misc/goto?guid=4959675517031820195">阅读原文</a></p>    <p> </p>