liu 发布的文章

Docker化之前,阿里主要交易业务已经容器化。采用T4做容器化,T4是2011年开发的一套系统,基于LXC开发,在开发T4的过程中,跟业界很大的不同在于,T4更像VM的容器。当用户登进T4后,看起来与标准的KVM等几乎完全一样,对用户来讲是非常透明化的。所以,容器化不是我们推进Docker的原因。

  a)触发我们Docker化的主要原因一:Docker最重要的一点是镜像化,可以做到拿着镜像就可以从一台完全空的机器的应用环境搭建起来,可以把单机环境完全从零搭好。Docker化之前,阿里巴巴的应用部署方式主要由Java、C来编写的,不同的业务BU可能采用完全不同的部署方式,没有统一标准。内部尝试通过基线来建立部署标准,定义的基线包括应用依赖的基础环境(OS、JDK版本等)、应用依赖的脚本,基础环境的配置(启动脚本、Nginx配置等)、应用目录结构、应用包、应用依赖的DNS、VIP、ACI等,但不成功。部署标准做不了,直接导致自动化很难做到。

  b)触发我们Docker化的主要原因二:DevOps是一个更好的方向,阿里巴巴做了很多运维和研发融合的调整。Docker是帮助DevOps思想真正落地的一种手段,所有的思想最终都体现在工具或框架上,变成一个强制性的手段,Docker会通过Dockerfile的描述,来声明应用的整个运行环境是怎样的,也就意味着在编写Dockerfile过程中,就已经清楚在不同环境中的依赖状况到底是怎样的,而且,这个环境是通过一个团队来维护的。

  Docker化目标

  2016年7月,阿里巴巴制定了两个Docker化目标:

  交易核心应用100%Docker化;

  DB其中一个交易单元全部Docker化。

Docker化之路

  推进Dcoker之前,我们有一个准备的过程。在准备阶段,我们需要Docker更像VM和更贴合阿里运维体系的Docker,我们将改造过的Docker称为AliDocker;除了AliDocker以外,我们需要支持AliDocker的工具体系,比如编译、镜像库、镜像分发机制,在完成这些准备工作后,我们认为可以一帆风顺地开始大规模的AliDocker上线。但事实并非如此。

  第一轮Docker化

  我们碰到了很多问题:

  工具不完善,阿里很多应用之前都是在T4容器中,怎样将T4容器转换成AliDocker是首要面临的问题;

  镜像Build后上传,以前阿里一个应用转成多个,很多时候需要在自己的机器上做Build,然后自己上传,导致做应用时很痛苦;

  应用从T4切换成走Docker的链路,链路没有完全准备好,从资源创建到发布,很多需要手工去做,大规模去做效率非常低。

  第二轮Docker化

  在推进的过程中,我们又遭遇了新的问题。Docker的发布模式是典型的通过镜像,拉到镜像后将原来的容器销毁,重新创建一个容器,把镜像放进去,拉起来。Docker单一化的发布方式支持不了多种发布模式,更改velocity模板发布效率低;有本地内存cache的发布,重启本地内存cache就会消失。怎样在基于镜像模式情况下又能支持多种发布模式呢?

  我们在Docker的镜像模式基础上做出一个crofix的模式,这个模式不是绕开镜像,而是从镜像中拉起我们需要的文件,去做覆盖等动作,这样就可以完成整个发布。Docker化镜像模式是必须坚持的,否则失去了Docker化的意义。

  第三轮Docker化

  继续推进到很多应用切换到Docker的时候,我们又遇到了更大的问题:

  首先,很多研发人员都有明显的感受,切换到Docker后变慢。第一,编译打包镜像慢,编译打包完应用的压缩包后,还需要把整个环境打包成镜像,这是在原有基础上增加的过程,如果编译时每次都是新机器,以前依赖的所有环境都要重新拉,一个应用Docker的完整镜像通常会很大,因为它包括依赖的所有环境。对此,我们在编译层做了很多优化,尽可能让你每次都在之前编译的基础上进行编译。第二,镜像压缩问题,Go在1.6以前的版本压缩是单线程,意味着压缩整个镜像时效率会非常低,所以我们选择暂时把镜像压缩关闭掉。

  其次是发布问题,Docker的镜像化模式决定了分发一定是镜像分发,使用Docker时不能完全把它当作透明化东西去用,对所有研发人员来说,要非常清楚依赖的环境、Dockerfile中镜像的分层改怎么做,将频繁变化部分与不频繁变化部分做好分层,镜像分层是改变Docker慢的重要方案;阿里制定了镜像分发多机房优化,比如打包后将所有镜像同步到所有机房;阿里也做了发布优化(P2P、镜像预分发、流式发布),还通过Docker Volume将目录绑定到Dockerfile中,可以保证镜像文件每次拉起时不会被删掉。

  在整个Docker化的过程中,我们在“慢”这个问题上遇到了最大的挑战,不管是编译慢还是发布慢,都做了很多突击的改造项目,最后才让整个编译过程、发布过程在可控的响应速度内。

  第四轮Docker化

  在推进过程中,我们还遇到规模问题:

  由于规模比较大,开源软件很容易碰到支撑规模不够,稳定性差的问题。目前我们使用Swarm来管理,Swarm的规模能力大概可以支撑1000个节点、50000个容器,而我们需要单Swarm实例健康节点数在3W+,对此,我们对Swarm进行了优化。

  规模我们做到从支撑1000到3W+,压力减小了很多。而Swarm的稳定性对我们来讲,最大的问题在HA上,一个Swarm实例如果挂掉,重新拉起需要时间,所以我们在用Swarm时进行了改造。在前面加了一层Proxy,不同业务、不同场景都可以通过Proxy转换到自己不同的Swarm实例上。另外,所有的Swarm节点我们都会用一个备方案在旁边,而且都是不同机房去备。

  通过改造增强HA机制后,可以做到每次切换、简单发布。

Bugfix和功能增强

  除了上面四轮次比较明显的问题,在整个Docker化过程中,还做了很多的Bugfix和功能增强,具体有以下几方面:

  Daemon升级或crash后,所有容器被自动销毁的问题;

  Cpuset、cpuacct和CPU子系统mount到一起时CGroup操作错误的bug;

  支持基于目录的磁盘配额功能(依赖内核patch);

  支持制定IP启动容器,支持通过DHCP获取IP;

  支持启动容器前后执行特定脚本;

  支持镜像下载接入各种链式分发和内部mirror的机制;

  增加Docker Build时的各种参数优化效率和适应内部运维环境;

  优化Engine和Registry的交互。

  经历了这么多坎坷,我们终于完成了全部目标,实现双11时交易所有核心应用都AliDocker化,DB其中一个交易单元全部AliDocker化,生产环境共几十万的AliDocker。

未来

  容器化的好处是可以把很多对物理机型的强制要求虚拟化,可能也需要Docker在内核层面的改造,对于未来,我们已经做好了准备,希望:

  所有软件AliDocker化;

  和Docker公司紧密合作回馈社区;

  AliDocker生态体系逐渐输出到阿里云。


背景

2014年乐视云开始尝试Docker的推广和使用,我们的团队开始开发第一代容器云平台Harbor (分享网址:http://dockone.io/article/1091 )。(在这里提醒一下,这与VMware公司中国团队为企业用户设计的Docker Registry erver开源项目Harbor 重名)。

第一代容器云平台可以认为是一个开放的托管平台。开发者可以将自己从公司申请的虚拟机或者物理机添加到Harbor系统中进行托管管理,平台基本包含:镜像自动构建(CI),应用快速扩容、缩容、灰度升级,资源权限管理,多集群主机管理等功能。

由于那时容器才刚刚兴起,刚开始在公司内部推动也有一定的阻力,刚开始给业务线推广的时候,需要首先介绍Docker,介绍容器和虚拟机的区别,然后再介绍平台本身和使用方法,推广成本以及业务线学习成本也比较高。接入Harbor上的业务的大多是业务线自己提供虚拟机,而物理机占少数。不过鉴于Harbor的易用程度,吸引了很多新业务接入。到现在为止Harbor已经完全实现开发自助化。业务自己添加主机,自主管理应用和容器,对应用进行升级、回滚,弹性伸缩,镜像构建,现在已经稳定运行2年多。

第一代容器云平台不足之处

  1. 网络方面也是用的最基本的Nat,端口映射模式,存在性能问题。业务必须要知道容器对外映射出来的端口,对业务不透明,不便于报警和运维,也不便于对接负载均衡。

  2. 容器的分发调度全部自己开发,任务量大,当时没有能够做到容器自动迁移。

  3. 不支持应用的全球部署。

  4. Harbor管理的计算资源需要业务线自己申请,计算资源可以是物理机也可以是虚拟机,导致业务线需要关心底层的计算资源,计算资源无法对业务线完全透明。

  5. 为了降低用户对Dockerfile的学习成本,我们对Dockerfile进行了封装,只让用户写Shell脚本,因封装的不合理,导致制作出的镜像太大,尤其Maven项目,需要编译,每次在Docker Build时候,都会重新下载依赖包,导致编译过程长,镜像大,并且容器内服务启动方式不灵活。

  6. 监控报警机制不完善,没有做到容器和应用级别的监控和报警。

  7. 镜像仓库Registry并没有做得到像Docker Hub那样用户权限划分。

随着Kubernetes在越来越多公司开始使用,乐视内部更多的团队和业务线开始接受或者主动了解Docker,同时为了解决第一代平台的存在问题和基于乐视现有服务部署情况,到2015年底,我们团队计划替换掉之前自己写的调度方案,着手尝试使用Kubernetes作为容器的调度引擎,在对比多套网络方案(Calico,Flannel等等)后,结合乐视现有状况,采用Bridge模式,容器大二层网络方案。负载均衡使用Nginx,计算资源全部使用物理机,计算资源完全对业务透明。经过半年多的调研和开发,在2016年10月第二代PaaS平台LeEngine在美国上线,半个月后,北京地区上线。LeEngine现在保持着一月一版本的开发迭代速度,到现在为止已经开发了3个版本。

LeEngine 采用全新的架构,主要面向于无状态或者RPC应用。现在已经承接了乐视云计算,乐视体育章鱼TV,风云直播,乐视网乐看搜索,云相册等近100多个重要业务,使用的客户普遍反映一旦掌握了LeEngine的使用流程,从开发到上线部署,弹性伸缩,升级的效率可成倍增长,极大简化了运维成本。LeEngine拥有极强的用户粘性,吸引了很多业务线主动申请试用LeEngine,现阶段已经不需要再增加额外的精力在公司内部推广。

简介

Kubernetes:Google开源的的容器编排工具,在整个2016年,越来越多的公司开始在线上使用Kubernetes,同时Kubernetes具备我们迫切需要的容器自动迁移和高可用功能。关于Kubernetes 的架构在这里我就不多介绍了,虽然架构偏重,但是我们最终决定使用它,并且尽量只使用它的Pod,Replicationtroller和Service功能。

这里首先解释一下几个概念:

用户

:乐视各个产品线下的产品、开发、测试、运维等人员。

Region

:偏向于地理概念,例如北京和洛杉矶是两个Region。 同一个Region内要求内网可达,网络可靠,低延迟。同一个Region共用一套镜像Registry,镜像构建系统,负载均衡系统和监控报警系统,不同Region 共享全局唯一的SDNS和GitLab代码仓库。

Cell

:我们现在使用的Kubernetes 1.2.0版本,理论上能控制1000个计算节点,为谨慎使用,规定一个Kubernetes集群最大计算节点会控制在600个左右。 Cell 概念的引入是为了扩充单个Region下计算节点的规模,偏向于机房的概念,一个Cell 即一个Kubernetes集群,每个Region下可以搭建多个Cell。所有Cell共享本Region下的镜像Registry,镜像构建系统,负载均衡系统和监控系统。为同一个Cell下的容器配置一个或者多个网段,每个网段划分单独的VLAN。同一Cell下的计算节点不会跨机房部署。

LeEngine Registry

:基于Docker Registry 2.0做的部分修改,后端支持乐视云的Ceph存储。并仿照Docker Hub增加权限和认证机制,只有拥有相应权限的用户才能对特定的镜像进行Push和Pull操作。也可以设置镜像公开,公开的镜像任何用户都可以Pull。

计算节点

: 物理机,Kubernetes的Node概念。

应用

: 定义提供相同业务逻辑的一组容器为一个应用,可以认为应用是一个微服务。这类应用要求是无状态Web服务或者RPC类的服务。应用可以部署在多个Cell中。上文提到过,一个Cell可以认为是一个机房。LeEngine在一个Region下会至少部署2个Cell,部署应用时候,我们要求应用至少部署在2个Cell中,这样即使一个机房出现网络故障时,另一个机房的应用容器还能继续对外提供服务。一个应用下可以部署多个版本的容器,因此可以支持应用的灰度升级。访问web类应用时候,我们强制要求这类应用(如果是线上应用)前面必须使用负载均衡,由我们的服务发现系统告诉负载均衡当前应用下有哪些容器IP。从Kubernetes层面讲,我们规定一个应用对应Kubernetes下的一个Namespace,因此在应用的数据库表中会存在一个Namespace的字段,并需要全局唯一,而应用的多个版本对应了在这个Namespace下创建的多个Replicationtroller。

Region、Cell 和kubernetes的关系:

关系.png

架构平台设计

容器直接运行在物理机上,计算节点全部由我们提供,业务线不需要关心,LeEngine可以作为一个企业解决方案对外全套输出,平台架构如下:

架构.png

业务层: 乐视使用容器的各个业务线,是LeEngine的最终用户。

PaaS 层: LeEngine提供的各种服务,主要是完成对应用的弹性伸缩,灰度升级,自动接入负载均衡,监控,报警,快速部署,代码构建等服务。

宿主机资源层:主要指Docker 物理机集群,并包含IP池的管理。

逻辑.png

用户访问部署在LeEngine上的应用时,首先通过SDNS智能解析到对应的Nginx负载均衡集群,然后由Nginx将请求打到对应的容器中。数据库,缓存等有状态的服务并没有在LeEngine体系之内,因为采用大二层网络,容器可以直接连接公司其他团队提供的数据库或者缓存等服务。

下图是为了更好的说明支持多地域,多kubernetes集群的部署。

Region.png

单一Region下单Cell部署图:

单cell.png

我们将计算节点的管理网络和容器网络划分开并给容器网络划分单独的VLAN。

成员、权限管理

LeEngine下面定义了四大资源,应用、镜像、镜像分组和代码构建。为了团队协同操作,这4大资源都增加了成员和权限管理。成员和权限仿照了GitLab进行了设计,成员角色分为:Owner、Master、Developer、Reporter、Guest。 不同的角色针对不同的资源系统都定义了不同的权限。比如应用,只有Owner和Master有权限对应用部署新版本,弹性伸缩等等。 假如一个用户A创建了一个应用A1,那么A就默认是应用A1的Owner,拥有对应用A1所有操作权限,包括部署新版本,弹性伸缩,修改应用,删除应用等所有操作。而用户B此时对应用A1不可见,若想可见,必须由A对这个应用A1执行添加成员的操作,把B添加到A1中,并赋为除Owner以外的任何一个角色,若此时B被赋为Master角色,那B拥有了对应用A1部署新版本,弹性伸缩等权限,反之则没有。

根据上面的权限设计,通过LeEngine的Console界面,不同的用户登录后看到的仅仅是跟自己相关的资源,如下图,在应用中,能看到我创建的以及我参与的应用:

参与应用.png

在镜像页面,能够看到我创建的以及我参与的镜像,如下图:

参与镜像.png

帮助文档会提供给用户不同资源的权限说明:

帮助.png

帮助2.png

用户端和管理端

LeEngine具有面向用户端的Console界面和面向运维管理员的boss界面,在用户端用户可以看到自己创建和参与的4种不同的资源。管理端则主要是对整个LeEngine平台资源进行管理,包括用户可使用最大资源的限制,负载均衡特殊配置,Cell集群下的资源使用情况,操作频率统计等等。

下图是LeEngine测试环境boss系统关于操作频率统计:

操作频率.png

操作频率包括每天所用应用的部署次数,代码的构建次数,镜像的Push次数,弹性伸缩次数,在一定程度上能展示出业务线对LeEngine平台本身的使用频率。

LeEngine-core

LeEngine-core是LeEngine最终对外提供服务的API接口层(beego实现),所有4大资源的操作,包括权限控制,都是通过这一层控制的。LeEngine只提供最原子的API接口,特殊业务线要想有特殊的需求,完全可以在现有API基础上进行二次开发。

容器网络

容器采用大二层网络,因此可以保证外部服务可以直接连通容器,容器也可以直接连通外部服务,比如数据库,缓存等等。采用此种方案可以保证容器横向可连接,纵向可访问。外部想连接容器可以通过容器IP地址直接连接,也可以通过负载均衡方式进行访问。而容器也可以直接访问LeEngine体系外的虚拟,物理机资源,以及MySQL等组件服务。

纵向访问.png

我们自己写了CNI插件和CNICTL管理工具,支持添加多个IP段,用来防止IP资源不够的情况。IP段的信息存在了当前Kubernetes集群里的etcd中。我们会为每个Cell即每个Kubernetes集群下都添加至少一个IP段,一般1024个IP地址22子网掩码,单独vlan防止广播风暴,这需要提前跟网络部门规划好IP段。如果这个IP段已经使用完,我们会使用CNICTL工具,重新增加一个新的IP段。

容器网络.png

为了进一步保证业务容器在网络方面的稳定性,我们所有的计算节点都是4个网卡,2千兆,2万兆,双双做bond,千兆bond1用来做管理网卡,万兆bond1用来跑业务容器,每个计算节点在交付时候会创建一个OVS网桥,并将bond1挂载上去,上联交换机做堆叠,计算节点尽量打散在多个不同机柜中。

计算节点物理机上的Kubulet在创建Pod的PAUSE容器后,会调用我们自己CNI插件,CNI会创建一个veth pair, 一端扔到这个容器的Namespace中,并命名eth0,一端挂载到OVS网桥上,之后从etcd中大的IP段中找出一个连续16个IP地址的小段给这个计算节点,然后再从这个子段中找一个空闲的IP给这个容器,配置好容器IP,以及路由信息,同时会根据配置来确定是否发送免费ARP信息,之后遵守CNI规范把相应的信息返回给kubelet。当这个计算节点再次创建新的Pod时,会优先从这个子段中选择空间的IP,若没有空闲的IP地址,会重新计算一个子段给这个计算节点用。

现在CNI不能保证Pod删掉重新创建时候IP保持不变,因此应用在每次升级操作后,容器IP地址会变,这就需要我们的服务发现与负载均衡做对接。

不过现在的这套方案也会存在一些问题:比如物理主机突然down掉,或者Docker进程死掉,导致本主机上所有容器挂掉,等kubelet重新启动后,原来死掉的容器所占用的IP并不会释放。我们现在的解决方案是通过我们开发CNICTL命令来进行定期检测。CNICTL提供一个check命令,会检索etcd中所有分配的IP和对应的POD信息,之后调用apiserver获得所有Pod信息,取差值则为没释放的IP地址。收到报警后,人工调用CNICTL的释放IP功能,手动释放IP。

服务发现

我们充分利用了Kubernetes的Service概念,前面已经提过,一个应用对应一个Namespace,一个版本对应一个RC,在用户通过API请求创建应用时候,LeEngine核心API层:LeEngin-core会默认在对应的Kubernetes集群中创建相关联的Namespace,同时默认在这个Namespace下创建一个Service,并创建一个唯一的标签属性,用户在部署新版本(RC)时候,LeEngine会给这个RC添加这个Service的唯一标签。这样就可以通过Service来发现后端的Endpoint。我们用Go写了一个服务发现服务,通过watch api-server的API接口,自动归类发现哪个应用下有IP变动,之后调用我们负载均衡的API接口,动态更改Nginx的后端upstream serverip。

在我们没使用Kubernetes的健康探测功能之前,会有一定的几率出现容器创建完成,服务没有完全启动,这时候容器IP已经加载到负载均衡的情况,如果这时候如果刚好有请求过来,会出现请求失败的现象。之后我们在最新一版中,加入了健康探测功能,用户在给应用部署新版本时,允许用户指定自己服务的监控探测HTTP接口,当容器内服务探测成功后,才会加入到负载均衡中去。而删除容器则不会出现这种情况,执行RC缩容命令后,需要删除的容器首先会立马从负载均衡中删除,之后才会执行容器的删除操作。

负载均衡

我们并没有使用Kubernetes的Proxy作为负载均衡,而是使用Nginx集群作为负载均衡。Nginx我们原则上会部署在同一个Region下的多个机房中,防止因为机房网络故障导致全部的Nginx不可用,支持Nginx横向可扩展,当负载均衡压力过大时候,可以快速横向增加Nginx物理机。为防止单一Nginx集群下代理的Domain数目过多,以及区分不同的业务逻辑,比如公网和内网负载均衡,我们支持创建多个Nginx负载集群。

下图为用户浏览请求路径。

请求路径.png

关于如何能够通知Nginx集群自动更新Upstream下的Server IP问题, 我们在Nginx集群外面用beego框架设计了一层API层:slb-core, 专门对外提供API接口,具体结构如下:

slb-core.png

etcd里面存放每个domain的配置信息。具体key结构如下:

/slb/{groupname or groupid}/domains/{domain_name}/

每一台Nginx主机上都会安装一个Agent,每个Agent监控他所属的groupid 的key,比如/slb/2/,这样可监控本Nginx 集群下所有Domain的配置变化,Agent 将变化过的Domain 配置更新到Nginx下的目录下,并判断配置变化是否是更改的upstream下的Server IP还是其他配置,如果发现是其他配置更改,比如location或者增加header,则会reload nginx, 如果发现单纯更改upstream 下Server IP,则直接调用Nginx动态更改upstream ip的接口。

上层的slb-core 则会提供domain动态更改后台upstream ip的接口, 供服务发现调用。

如果多个互相关联,互相调用的业务域名都同时被一个Nginx集群所代理,若其中一个domain需要更改配置,导致需要reload nginx,很可能会出现reload 时间过长的问题。

基于这套架构,后端Nginx主机可以快速扩展,迅速增加到对应集群中。由于增加了nginx test机制,当用户更改domain的配置有语法问题, 也不会影响负载均衡,还会保持上一个正确的配置。现在这套架构已经是乐视负载集群的通用架构,承载了乐视上千个域名的负载均衡。

用户在创建一个应用时候,如果需要负载均衡则需要填写负载均衡域名,Nginx集群等信息, 如下图:

创建应用.png

创建成功后,通过查看应用的负载均衡导航栏可以知道这个应用负载均衡的CNAME和VIP信息,等业务测试成功后,DNS系统上配置使域名生效。

如下图:

负载均衡.png

下图可以让用户查看负载均衡Nginx配置信息:

负载均衡配置.png

现阶段Nginx负载均衡集群并没有按照一个应用来进行划分,大多数情况是一个Nginx负载均衡集群代理了多组domain。因此对于用户端,为了防止业务线用户恶意或者无意的随便更改,而导致整个Nginx集群出现问题,现阶段用户端无权更改Nginx配置,如果需要更改特殊配置,需要联系管理员,由管理员进行配置。后续我们会考虑给一个应用分配一组Nginx容器进行负载均衡代理,这样用户就会拥有Nginx配置更改的最高权限。

LeEngine registry

LeEngine Registry是我们内部提供的镜像仓库,根据Docker Registry 2.0 版本:docker distribution做了修改,支持乐视Ceph后端存储,同时使用auth-server 以及LeEngine 的权限机制,定义用户和权限划分。允许镜像私有和公开。 公开的镜像任何用户可以执行Pull 操作。私有的镜像可以添加团队成员,不同角色的成员具有不同的Push,Pull, 删除权限。基于以上的设计LeEngine Registry 可以完全独立于LeEngine对外提供镜像仓库服务, 业务线如果不想使用LeEngine的代码构建功能,可以完全使用自己的构建方法,构建出镜像来,之后Push 到LeEngine registry中。

如下图是关于镜像tag的相关操作:

镜像tag.png

成员:

成员.png

动态:

动态.png

LeEngine下4大资源:应用、镜像、镜像组织、代码构建,在每个资源页里都是有动态一栏,用来记录操作记录,方便以后的问题追踪。

代码构建

为了快速将代码构建成Image,并Push到镜像仓库中,LeEngine后面会设置一组专门构建用的Docker物理机集群,用来执行构建任务,每个构建物理机都会安装一个Agent。

LeEngine的代码构建框架如下:

构建框架.png

每个构建物理机上的agent 启动后,都会将自己的信息定期自动注册到etcd中,表示新增一台构建机,当Agent意外停止或者主机挂掉,etcd中的注册信息会失效,表示已经下线一台构建机。另外Agent会监控自己的任务key,用来接收LeEngine-core下发的构建任务。

当有一个构建请求时会调用LeEngine-core的API,LeEngine-core会从etcd中选出一个合适的构建机(一般按照hash方式,尽量保证一个代码构建在同一台物理机上构建,加快构建速度), 然后将构建任务放到这个构建机的任务key中,对应的Agent监控到key变化后,会执行代码Clone,编译,Build和Push操作。

Etcd在LeEngine中扮演这非常重要的角色,是各个模块通信的消息总线。

鉴于Maven项目,需要编译,在第一代Harbor系统中,编译步骤放在了Docker Build 过程中,由于Maven编译需要大量的mvn依赖,每次编译都需要重新下载依赖,导致编译时间长,编译的镜像多大,因此我们在Build之前,会起一个Container,在Container中对代码进行编译,并将mvn依赖的目录映射到主机上,这样同一个代码构建,在每次构建时候,都会共享同一个mvn依赖,不需要重新下载,加快编译速度,同时还能保证不同的代码构建使用不同的mvn依赖目录,保证编译环境绝对纯净,最后只将编译好的二进制打到镜像中,在一定程度上保证代码不外泄。

代码构建仅限于放在Git上的代码,现阶段并不支持SVN,因此有的业务如果代码在SVN上,可以使用其他工具自己将代码制作成镜像,然后Push到LeEngine Registry上。由于LeEngine Registry上对镜像和镜像仓库做了权限认证,保证了镜像的安全。

代码构建支持手动构建和自动构建,在GitLab上设置相应的Web hook,这样用户只要提交代码,就会自动触发LeEngine的代码构建功能。

下图为创建代码构建的Web页:

添加构建.png

使用LeEngine的代码构建,我们要求用户的代码里需要自己写Dockerfile,Dockerfile 里FROM 的根镜像可以使用LeEngine Registry 里公开的镜像,也可以使用Docker Hub里公开的镜像。

如果业务代码需要编译,则可以指定编译环境,编译脚本也是需要放到代码中。

下图为手动构建页面:

手动构建.png

tag名如果不写,LeEngine会根据当前分支下的commit号作为镜像tag名。如果选用mvncache,则本次构建就会使用上次构建所下载的mvn依赖,加快构建速度。

下图为构建结果:

构建结果.png

构建过程:

构建日志.png

构建日志中,每一关键环节都记录了耗时时间,以及具体的执行过程。

应用管理

应用支持垮机房部署,多版本灰度升级,弹性伸缩等功能。我们规定一个应用对应一个镜像。

应用服务.png

部署版本(一个版本即一个RC)时候,需要指定镜像tag,容器数目,CPU,内存,环境变量,健康检查等等参数,现在的健康检查我们暂时只支持http接口方式:

创建新版本.png

由于大部分的升级,都是更改镜像tag,因此每次部署新版本时候,LeEngine会在新弹出框内,将上一版本的容器数目,CPU,内存,环境变量,健康检查等等参数自动填充到弹出框中,用户只需选择新的镜像tag就可以了。因此最后灰度上线,只需要创建新版本等新版本的容器完全启动,服务自动加入负载均衡后,再将旧版本删除即可。

下图为应用事件查看:

应用事件.png

应用事件主要收集的是应用在Kubernetes集群中的事件信息。

监控、告警系统

监控报警我们分PaaS平台和业务应用两大类。

PaaS平台主要聚焦在基础设施和LeEngine的各个服务组件的监控报警(比如主机CPU,内存,IO,磁盘空间,LeEngine各个服务进程等等),这一类使用公司统一的监控报警机制。

业务应用类,也就是跑在LeEngine上的各个业务线的监控和报警,需要由LeEngine进行对其进行监控和报警,触发报警后,会通知给各个应用的负责人。我们采用了heapster 来收集容器的监控信息和Kubernetes的各种事件。每个Cell集群中都部署一个heapster,监控数据存放到influxdb中。设定了一个应用全局对应一个Kubernetes的Namespace,因此我们能很好的聚合出应用和单个容器的监控数据。

如下图 针对应用的网络流量监控:

网络监控.png

容器 IP,运行时间和状态:

容器监控列表.png

下图是针对应用下单个容器的监控:

单个容器监控.png

现在heapster 没法收集容器的磁盘IO数据,后期我们会增加对于磁盘IO的监控收集,同时我们会丰富其他的监控数据(比如请求量等等)。关于报警,我们后期准备使用kapacitor 进行用户自助化报警,让用户自定义设定针对于应用cpu,内存,网络,IO,容器重启,删除等的报警阀值。触发报警后,会调用公司统一的告警平台(电话,邮件,短信三种方式)对相关人员进行报警。默认报警人员为当前应用的Owner和Master角色的成员。此功能已经基本调研完成,计划3月底上线。

日志收集

根据公司具体状况,容器的日志收集暂时还没有纳入LeEngine范围内,全部由业务线自己收集,然后统一收入到公司的日志系统中或者由业务线自己搭建日志存储和检索系统。我们后期会考虑日志统一收集。

总结

一键式解决方案

LeEngine提供了代码构建,镜像仓库,应用管理,基本上实现了开发者一键式解决方案:

一站式解决方案.png

各个业务线开发人员只需要提交代码,剩下的就会根据打包和构建规则自动生成特定的镜像版本,测试和运维人员只需要拿着对应的镜像版本进行测试和线上升级即可,极大简化开发运维工作。

减少运维成本

我们建议程序在容器内前台启动,利用Kubernetes的功能,程序死掉后,由kubelet自动拉起,实时保证线上容器实例数。若需要调试,业务或者运维可以直接通过SSH连接到容器内排查问题。由于Kubernetes强大的容器自动迁移功能,即使后端物理主机出现宕机或者网络问题,也不会产生严重的问题,除非后端物理计算资源不够,这在很大程度上减少了运维人员大半夜被叫起处理问题的次数。

计算资源对业务完全透明

底层计算资源完全由我们提供,业务线不用担心资源的问题。

产品化

LeEngine在设计之初,保证尽量少的依赖其他外部资源和服务,整个LeEngine可以作为一个解决方案整体对外输出。

存在的问题

任何一款产品不管怎么设计,都有它的不足之处,LeEngine在上线之后,我们也收到了不少反馈和问题。

  1. 按照之前的运维习惯,运维人员在排查问题时候,经常会根据IP来进行区分,而LeEngine下的应用每次升级后,容器IP都会变化,这对传统的运维造成一定的冲击。我们现在的解决思路是,如果运维人员一定要通过IP去排查,我们会让运维人员登录LeEngine的Console,查看当前应用下的容器IP列表,之后再去逐个排查。同时有的业务会对IP进行访问限制,针对这种情况,我们只能让这些业务对一个IP段进行限制。

  2. Kubernetes 1.2版本,对容器的swap并没有控制,若业务应用有bug,出现大量的内存泄露,往往会把容器所在物理机的swap吃满,而影响了物理机上其他的容器。 我们现在的解决方案暂时只能通过报警方式,尽快让用户修复问题。

  3. 由于Dockerfile 和编译脚本都要求放在用户Git代码中。会存在用户Git使用不规范,不同分支代码互相merge,导致Dockerfile和编译脚本出现变化,导致构建出的镜像与预期的不一样,从而上线失败。这种问题,我们只能要求业务线规范Git使用规范,LeEngine代码构建本身已经无法控制到这种细粒度。

  4. 现阶段我们还没法做到自动弹性扩容(给应用设定一个最小容器数目和最大容器数目的阀值,根据CPU、内存、IO、请求量或者其他值,自动觉得容器是否需要扩容,缩容)。

展望

Docker和Kubernetes也在飞速发展中,相信Kubernetes未来会有更加强劲的功能,我们后续也会考虑把有状态的服务跑到Kubernetes中去,欢迎大家一块探索。

Q&A

Q:你们的IP管理应该做了很大的开发工作吧?能详细介绍一下?

A:确实做了很多开发工作,其中很大的一个开发量是关于空闲IP获取这块。

Q:还有你们的灰度发布是用的Kubernetes本身滚动更新功能?还是自己实现的?

A:灰度发布没用Kubernetes 的滚动更新更能,而是用了不同的RC的相互切换。

Q:多个Region的镜像管理,如何实现镜像同步与更新?

A: 我们不需要实现镜像的同步。分享中已经提到过,各个Region有自己的镜像仓库。

Q:你好 请问你们大二层网络是用开源方案实现的还是自己根据OVS开发实现的?

A:是我们自己实现的,我们CNI中调用了OVS,主要是使用了OVS的网桥功能。

Q:应用跨机房部署,我理解也就是可以跨Kubernetes集群部署,Kubernetes里的调度是如何做的?

A:应用的概念,是在Kubernetes集群之上的,应用可以部署在多个Kubernetes 集群中。

Q:请问贵公司内部服务之间的互相调用是怎么控制的?容器到容器还是容器-Nginx-容器(等同外部)?

A:1. 容器->容器 2. 外部服务->Nginx->容器 3. 容器->Nginx->容器 4. 容器->外部服务。 这种情况都有,主要看业务场景。

Q:构建服务集群用到什么CI工具,还是自己开发的?etcd在其中有什么作用?

A:自己开发的,etcd 相当于消息队列,控制层收到构建请求后,etcd中存放了现阶段集群下都有哪些构建机,当来到构建请求后,控制层会寻找一个构建机器,并向构建机器所在的etcd key中发送命令, 对应的构建机器在监控自己的key发生变化后,会执行相应的构建任务。

以上内容根据2017年2月14日晚微信群分享内容整理。分享人

作者:张杰,乐视云计算有限公司PaaS平台LeEngine负责人。毕业于东北大学,专注于云计算领域PaaS平台的技术研究。14年入职乐视,目前从事基于Docker和Kubernetes的企业级PaaS平台的架构设计,研发以及平台落地工作。


京东从2016年底启动从OpenStack切换到Kubernetes的工作,截止目前(2017年2月)已迁移完成20%,预计Q2可以完成全部切换工作。Kubernetes方案与OpenStack方案相比,架构更为简洁。在这个过程中,有这些经验可供业界借鉴。

背景介绍

2016年底,京东新一代容器引擎平台JDOS2.0上线,京东从OpenStack切换到Kubernetes。到目前为止,JDOS2.0集群2w+Pod稳定运行,业务按IDC分布分批迁移到新平台,目前已迁移20%,计划Q2全部切换到Kubernetes上,业务研发人员逐渐适应从基于自动部署上线切换到以镜像为中心的上线方式。JDOS2.0统一提供京东业务,大数据实时离线,机器学习(GPU)计算集群。从OpenStack切换到Kubernetes,这中间又有哪些经验值得借鉴呢?

本文将为读者介绍京东商城研发基础平台部如何从0到JDOS1.0再到JDOS2.0的发展历程和经验总结,主要包括:

  • 如何找准痛点作为基础平台系统业务切入点;

  • 如何一边实践一边保持技术视野;

  • 如何运维大规模容器平台;

  • 如何把容器技术与软件定义数据中心结合。

集群建设历史

物理机时代(2004-2014)

在2014年之前,公司的应用直接部署在物理机上。在物理机时代,应用上线从申请资源到最终分配物理机时间平均为一周。应用混合部署在一起,没有隔离的应用混部难免互相影响。为减少负面影响,在混部的比例平均每台物理机低于9个不同应用的Tomcat实例,因此造成了物理机资源浪费严重,而且调度极不灵活。物理机失效导致的应用实例迁移时间以小时计,自动化的弹性伸缩也难于实现。为提升应用部署效率,公司开发了诸如编译打包、自动部署、日志收集、资源监控等多个配套工具系统。

容器化时代(2014-2016)

2014年第三季度,公司首席架构师刘海锋带领基础平台团队对于集群建设进行重新设计规划,Docker容器是主要的选型方案。当时Docker虽然已经逐渐兴起,但是功能略显单薄,而且缺乏生产环境,特别是大规模生产环境的实践。团队对于Docker进行了反复测试,特别是进行了大规模长时间的压力和稳定性测试。根据测试结果,对于Docker进行了定制开发,修复了Device Mapper导致crash、Linux内核等问题,并增加了外挂盘限速、容量管理、镜像构建层级合并等功能。

对于容器的集群管理,团队选择了OpenStack+nova-docker的架构,用管理虚拟机的方式管理容器,并定义为京东第一代容器引擎平台JDOS1.0(JD DataCenter OS)。JDOS1.0的主要工作是实现了基础设施容器化,应用上线统一使用容器代替原来的物理机。

在应用的运维方面,兼用了之前的配套工具系统。研发上线申请计算资源由之前的一周缩短到分钟级,不管是1台容器还是1千台容器,在经过计算资源池化后可实现秒级供应。同时,应用容器之间的资源使用也得到了有效的隔离,平均部署应用密度提升3倍,物理机使用率提升3倍,带来极大的经济收益。

我们采用多IDC部署方式,使用统一的全局API开放对接到上线系统,支撑业务跨IDC部署。单个OpenStack集群最大是1万台物理计算节点,最小是4K台计算节点,第一代容器引擎平台成功地支撑了2015和2016年的618和双十一的促销活动。至2016年11月,已经有15W+的容器在稳定运行。

在完成的第一代容器引擎落地实践中,团队推动了业务从物理机上迁移到容器中来。在JDOS1.0中,我们使用的IaaS的方式,即使用管理虚拟机的方式来管理容器,因此应用的部署仍然严重依赖于物理机时代的编译打包、自动部署等工具系统。但是JDOS1.0的实践是非常有意义的,其意义在于完成了业务应用的容器化,将容器的网络、存储都逐渐磨合成熟,而这些都为我们后面基于1.0的经验,开发一个全新的应用容器引擎打下了坚实的基础。

新一代应用容器引擎(JDOS 2.0)

1.0的痛点

JDOS1.0解决了应用容器化的问题,但是依然存在很多不足。

首先是编译打包、自动部署等工具脱胎于物理机时代,与容器的开箱即用理念格格不入,容器启动之后仍然需要配套工具系统为其分发配置、部署应用等等,应用启动的速度受到了制约。

其次,线上线下环境仍然存在不一致的情况,应用运行的操作环境,依赖的软件栈在线下自测时仍然需要进行单独搭建。线上线下环境不一致也造成了一些线上问题难于在线下复现,更无法达到镜像的“一次构建,随处运行”的理想状态。

再次,容器的体量太重,应用需要依赖工具系统进行部署,导致业务的迁移仍然需要工具系统人工运维去实现,难以在通用的平台层实现灵活的扩容缩容与高可用。

另外,容器的调度方式较为单一,只能简单根据物理机剩余资源是否满足要求来进行筛选调度,在提升应用的性能和平台的使用率方面存在天花板,无法做更进一步提升。

平台架构

鉴于以上不足,在当JDOS1.0从一千、两千的容器规模,逐渐增长到六万、十万的规模时,我们就已经启动了新一代容器引擎平台(JDOS 2.0)研发。JDOS 2.0的目标不仅仅是一个基础设施的管理平台,更是一个直面应用的容器引擎。JDOS 2.0在原1.0的基础上,围绕Kubernetes,整合了JDOS 1.0的存储、网络,打通了从源码到镜像,再到上线部署的CI/CD全流程,提供从日志、监控、排障、终端、编排等一站式的功能。JDOS 2.0的平台架构如下图所示。

jd_arch

jd_feature

在JDOS 2.0中,我们定义了系统与应用两个级别。一个系统包含若干个应用,一个应用包含若干个提供相同服务的容器实例。一般来说,一个大的部门可以申请一个或者多个系统,系统级别直接对应于Kubernetes中的namespace,同一个系统下的所有容器实例会在同一个Kubernetes的namespace中。应用不仅仅提供了容器实例数量的管理,还包括版本管理、域名解析、负载均衡、配置文件等服务。

不仅仅是公司各个业务的应用,大部分的JDOS 2.0组件(Gitlab/Jenkins/Harbor/Logstash/Elastic Search/Prometheus)也实现了容器化,在Kubernetes平台上进行部署。

开发者一站式解决方案

JDOS 2.0实现了以镜像为核心的持续集成和持续部署。

jd_deploy

  1. 开发者提交代码到源码管理库

  2. 触发Jenkins Master生成构建任务

  3. Jenkins Master使用Kubernetes生成Jenkins Slave Pod

  4. Jenkins Slave拉取源码进行编译打包

  5. 将打包好的文件和Dockerfile发送到构建节点

  6. 在构建节点中构建生成镜像

  7. 将镜像推送到镜像中心Harbor

  8. 根据需要在不同环境生产/更新应用容器

在JDOS 1.0,容器的镜像主要包含了操作系统和应用的运行时软件栈。APP的部署仍然依赖于以往运维的自动部署等工具。在2.0中,我们将应用的部署在镜像的构建过程中完成,镜像包含了APP在内的完整软件栈,真正实现了开箱即用。

jd_app

网络与外部服务负载均衡

JDOS 2.0继承了JDOS 1.0的方案,采用OpenStack-Neutron的VLAN模式,该方案实现了容器之间的高效通信,非常适合公司内部的集群环境。每个Pod占用Neutron中的一个port,拥有独立的IP。基于CNI标准,我们开发了新的项目Cane,用于将Kubelet和Neutron集成起来。

jd_tor

同时,Cane负责Kubernetes中service中的LoadBalancer的创建。当有LoadBalancer类型的service创建/删除/修改时,Cane将对应的调用Neutron中创建/删除/修改LBaaS的服务接口,从而实现外部服务负载均衡的管理。另外,Cane项目中的Hades京东开源在GitHub上组件为容器提供了内部的DNS解析服务。

灵活调度

JDOS 2.0接入了包括大数据、Web应用、深度学习等多种类型的应用,并为每种应用根据类型采用了不同的资源限制方式,并打上了Kubernetes的不同标签。基于多样的标签,我们实现了更为多样和灵活的调度方式,并在部分IDC实验性地混合部署了在线任务和离线任务。相较于1.0,整体资源利用率提升了约30%。

jd_schedule

推广与展望

有了1.0的大规模稳定运营作为基础,业务对于使用容器已经给予了相当的信任和支持,但是平台化的容器和基础设施化的容器对于应用的要求也不尽相同。比如,平台化的应用容器IP并不是固定的,因为当一个容器失效,平台会自动启动另一个容器来替代,新的容器IP可能与原IP不同。这就要求服务发现不能再以容器IP作为主要标识,而是需要采用域名,负载均衡或者服务自注册等方式。

因此,在JDOS2.0推广过程中,我们也推动了业务方主要关注应用服务,减少对单个容器等细节的操作,以此自研了全新智能域名解析服务和基于DPDK高性能负载均衡服务,与Kubernetes有效地配合支持。

近两年,随着大数据、人工智能等研发规模的扩大,消耗的计算资源也随之增大。因此,我们将大数据、深度学习等离线计算服务也迁移进入JDOS2.0。目前是主要采用单独划分区域的方式,各自的服务仍然使用相对独立的计算资源,但是已经纳入JDOS2.0平台进行统一管理,并通过机器学习方法,提升计算资源使用效率。

灵活的标签给予了集群调度无限的可能。未来我们将丰富调度算法,并配以节能的相关技术,提高集群整体的ROI,从而为打造一个低能耗、高性能的绿色数据中心打下基础。

回望与总结

Kubernetes方案与OpenStack方案相比,架构更为简洁。OpenStack整体运营成本较高,因为牵涉多个项目,每个项目各自有多个不同的组件,组件之间通过RPC(一般使用MQ)进行通讯。为提高可用性和性能,还需要考虑各个组件的扩展和备份等。这些都加剧了整体方案的复杂性,问题的排查和定位难度也相应提升,对于运维人员的要求也相应提高。

与之相比,Kubernetes的组件较少,功能清晰。其核心理念(对于资源和任务的理解)、灵活的设计(标签)和声明式的API是对Google多年来Borg系统的最好总结,而其提供的丰富的功能,使得我们可以投入更多精力在平台的整个生态上,比如网络性能的提升、容器的精准调度上,而不是平台本身。尤其是,副本控制的功能受到了业务线上应用运维工程师的追捧,应用的扩容缩容和高可用实现了秒级完成。JDOS 2.0目前已经接入了约20%的应用,部署有2个集群,目前日常运行的容器有20000个,仍在逐步推广中。

真诚感谢Kubernetes社区和相关开源项目的贡献者,目前京东已经加入CNCF组织,并在社区排名达到TOP30。

作者简介

鲍永成,京东基础平台部技术总监,带领基础平台部集群技术团队从2014年上线京东容器引擎平台JDOS1.0到现在的JDOS2.0,作为坚实的统一计算运行平台承载京东全部业务稳定运行。目前主要工作方向是JDOS2.0研发和京东第一代软件定义数据中心建设。


作为一名程序员,设计程序架构、优化算法已经是一件很头疼的事了,然而,还有更让人烦躁的,那就是环境配置,想必各位同学们都深有体会。每个人的电脑都不一样,不管是软件还是硬件,或者是要依赖的环境,因此同样的安装流程在别人那里是好使的,在你这就处处 bug,在电脑 A 上能顺利安装,在电脑 B 上就遇到问题了。于是有人就想出了一个办法,大家何不把自己配置好的环境打包成镜像呢?当需要配置同样的环境时,就把别人的镜像拿过来,进入镜像之后,就进入了别人搭建好的环境,而我们只需要提供硬件支持即可,而这个镜像就是 docker 容器。什么是镜像呢?简单来说,镜像就类似操作系统光盘介质,docker 容器相当于通过光盘安装后的系统。通过光盘(镜像),我们能在不同机器上部署系统(容器),系统内的操作只会保留限制在当前的系统(容器)中。需要了解的是,像 docker 这样的容器有很多种,而 docker 只是其中之一,但它是最受欢迎的,也因此占据了大半的市场份额。其他容器还有 CoreOS rkt、Mesos、lxc 等。

OpenStack 的诞生

我们都知道,全球云市场被三大巨头垄断,分别是亚马逊(Amazon)、微软(MicroSoft)和 阿里巴巴(Alibaba),而亚马逊正是云计算的开山鼻祖。

早在 2003 年,Amazon 向客户推出了一项全新的业务——包括存储空间、计算能力等资源服务的 Web Service,这就是大名鼎鼎的 AWS(Amazon Web Service)。说白了,就是给大家提供了远程电脑,上面配置了各种满足你需求的服务,你可以远程使用它,这就是云计算最早的形式。到了 2006 年,亚马逊又推出了一种配置更简单、方便的弹性计算云(Elastic Compute Cloud),又称 EC2 。而在同年的 8月9日,Google首席执行官埃里克·施密特在搜索引擎大会上首次提出“云计算”(Cloud Computing)的概念。从此,云计算进入了高速发展阶段。时间转到了 2010 年,一家名叫 Rackspace 的公司,同样在做云主机和云储存服务,和 Amazon PK 了多年,但是在竞争中一直处于下风。最终,他们把云服务代码给开源了。随后,NASA 也步后尘,开放了其在云领域多年的研究成果,并与 Rackspace 联手共同成立了一个开源项目。这个项目,就是 OpenStack,也是云计算发展的里程碑。

OpenStack 是什么

现在的云上资源(计算、存储、网络等)都是以集群的形式存在,这些集群里的物理机(Host)可以放在一个机房里,也可以分布式放在各个地方,而一个 host 上又可以虚拟出多个虚拟机(VM)。而 OpenStack 从一开始,就是为了云计算服务的,它就是一套软件,一套 IaaS 软件,用来管理集群里所有 Host(物理机)上的所有 VM(虚拟机)。什么是 IaaS?Infrastructure as a Service,基础设施即服务。这里的关键字是“基础设施”,也就是物理机。各大公司在 OpenStack 上进行了二次开发,形成了自己的 Iaas 软件,比如华为的 FusionSphere平台 和中兴的 TECS 平台。OpenStack 的安装部署非常快速,兼容性和适用性极强,而且便宜,一直很受市场欢迎。

Docker 的出现

按理说,Host 虚拟化出来了许多 VM,云上资源粒度划分已经很细了,也已经能做到资源的充分利用。然而,虚拟机的性能开销很严重。主要由于两点原因:一是虚拟层的引入;其二是因为 VM 的操作系统和 Host 的操作系统不一致,导致与操作系统有关的性能优化手段不能应用到所有的 VM 上。如果说虚拟机技术开启了云计算时代,那么 Docker 容器作为下一代虚拟化技术,将云计算推向了高潮。

  • 虚拟机和 Docker 的区别

首先,你要明确一点:Docker 容器不是虚拟机,但你可以把它近似看成一种轻量级的虚拟机。

一个 VM 里可以创建多个 Docker 容器。

Docker 比虚拟机更节省内存,启动更快,数量级上”虚拟机需要数分钟启动,而 Docker 只需要50毫秒”,这是因为 Docker 是利用宿主(VM)的系统内核。

K8S - 为 Docker 而生

当只需要一个容器时,你可以手工部署,没有问题。然而在集群里要部署海量的 Docker,还要管理它们时,手工显然不现实了,于是 Kubernetes 这种更高维度的容器编排工具应运而生。Kubernetes 简称 K8S, 它抽象了所有物理机资源,将所有云主机抽象成一个资源池,而这个池子里装的就是一个个容器。容器就是孩子,而 K8S 就是这些孩子们的亲妈,为啥这么说呢?比如,应用程序发现 CPU 不够用时,K8S 就将其调度到另一台 CPU 足够用的机器上,内存不满足要求时,K8S就会帮忙寻找一台有足够内存的机器,并在上面创建对应的容器。更重要的是,一旦应用程序由于某些原因挂掉了, K8S 还会帮它自动迁移重启, 照顾得简直无微不至。而开发者只关心自己的代码,容灾备份、服务资源扩充则由 K8S 保证。

说到这里,你可能认为”K8S“的调度单位是一个容器(container)。事实上,K8S 调度的基本单位为 pod, 一个 pod 表示一个或多个容器。引用一本书里所说“之所以没有使用容器作为调度单位,是因为单一的容器没有构成服务的概念;例如 Web 应用做了前后端分离,需要一个 NodeJS 与 Tomcat 才能组成一个完整的服务,这样就需要部署两个容器来实现一个完整的服务,虽然也可以把他们都放到一个容器里,但这显然违反了一个容器即一个进程的核心思想 --《Service Mesh实战 - 用 istio软负载实现服务网格》”


背景:模拟用户真实场景,在windows 2012R2上部署MSSQL ,并用HammerDB跑压力

1.创建新的数据库

在windows开始菜单,打开SQL Server Management Studio,创建一个新的数据库--->用HammerDB跑压力




2.运行Hammer DB

3.使用HammerDB在windows下跑MSSQL

3.1双击SQL Server,选择MSSQL Server,点击ok


3.2选择“TPC-C”-->"Schema Build"-->"Options"


3.3双击“Options”,会弹出“Microsoft SQL Server TPC-C Build  Options”对话框

把“Number of warehouses”至少设置为800;“Virtual User to Build Schema”设置为3。点击ok,回到主窗口


3.4双击“Schema Build”下“Build”,开始构建schema。通常需要几个小时才能完成(具体时间长短因前面设置的warehouse、virtual users大小而异)。


schema构建完成后,“status”下扳手图标会变成绿色“√”。

3.5点击交通灯形状的按钮(从左到右第十个)

3.6点击展开“Driver Script”,双击options按钮--->弹出另一个窗口,点击“ok”回到主窗口,点击‘load’载入脚本



3.7在‘virtual user’下双击‘options’,其中‘virtual users’数量不应超过50,最好和server cpu核数相等;‘Iteration’为设置迭代次数(让压力跑多少次)


3.9 ‘creat’创建用户,‘run’开始进行压力测试



————————————————

版权声明:本文为CSDN博主「西域火龙油」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/u012439646/article/details/78348159