【转】ZTEsoft基于Jenkins和Docker的CI实践

基于Jenkins的CI过程web

一 切要从2013年4月开始提及,当我4月份从委内瑞拉回来以后当即投身到国内一个运营商的大型后端建设项目的尾声中(项目历时3年多,当时已经接近尾 声),这个项目涉及100多台主机,包含数十个集群,除了传统的WEB应用外,还用到了流程引擎、ESB、规则引擎、搜索引擎以及缓存和日志,是当时比较 复杂的体系结构(固然不能跟如今的云平台相比,但在项目开始的年代这仍是一个很不错的架构),整个项目当时一两百号人占了局方整整一层楼十几个办公室。docker

我 到了项目组以后成为了一个小组的小头目,管个四五我的,小组美其名曰“平台组”,干的都是打杂的事情,包括编译、打包、部署,平常监控以及系统优化等工 做,提及来简单,作起来仍是很复杂的,当时全部的工做基本上是靠人工的,可想而知,100来台机器的环境一台一台的部署环境,还得靠人工监控,手工检查, 四五个处处救火忙得不可开交,当时我虽然还不知道CI为啥物(压根儿就没这个概念),但也下定决心要改变忙乱的状态,累一点没关系,可是累得跟狗似的还干 很差那就白辛苦了。shell

在 2013年的4~8月份,咱们主要研究的是自动编译、打包和发布,采用的基本方式是各类脚本,包括windows下的批处理bat、Linux上的 shell甚至Python,虽基本上完成了自动从SVN取代码、自动编译、自动打包以及将应用发布到WebSphere上的这些工做(以下图):编程


但也明显存在一些问题:windows

  1. 自动执行靠的是Windows任务计划,执行过程、执行状况只能经过检查脚本执行时写的日志文件,不直观。后端

  2. 代码只做了编译,没有作代码走查,对代码质量的提高做用不大。缓存

  3. 发布过程利用IBM提供的wsadmin脚本,只能进行全量的发布,发布过程较长。tomcat

9月份以后,项目基本稳定后我也离开了项目现场,但自那以后对这块工做更加着迷,我从项目现场回来以后也组建了一个科室,仍是四五我的,当时我查阅了一些资料,尤为是看到了一本书《持续集成,软件质量改进和风险下降之道》,今后学到一个名词:CI(持续集成),一发而不可收拾,逢人就鼓吹CI。我组织科室人员一块儿研究了CruiseControl、Apache Continuum、QuickBuild、Hudson等业界CI经常使用工具,最后决定以Hudson为框架来逐步实现CI.。一早采用的是Hudson,后来为便于做二次开发切换到其社区版本Jenkins上。网络

Jenkins提供了一个管理界面,而且有丰富的第三方插件,支持定时任务,支持从SVN取代码,支持Ant编译和Maven编译(咱们产品编程框架逐渐从ANT转向maven模式),支持向tomcat、JBoss、Weblogic和WAS发布应用(Jenkins的WAS插件不支持集群模式,咱们仍然沿用了wsadmin脚本),支持用PMD、Checkstyle、findBugs进行代码走查并以图形化方式展示走查结果(包括趋势图和结果详情),支持调用Windows批处理bat、Linux的Shell等。架构

在采用Jenkins框架的基础上,咱们做了一些二次开发,实现了:

  1. 根据任务单增量从SVN取代码(有一些奇葩的项目现场要求挑任务单升级,所以咱们修改了jenkins的svn插件以支持这种需求)。

  2. 支持增量编译(采用两个Jenkins的JOB,一个作全量编译,做为首次编译并产生一个jar包给增量编译使用,此全量编译JOB只使用一次;另外一个JOB就引用全量JOB产生的jar包,只对变动(或新增)的代码编译产生class等文件,并将它们按部署目录放好以便于做增量发布,同时将这些class文件再打入到全量JOB下的jar包中以备下次增量编译使用)。

  3. 支持增量发布,经过调用lftp脚本实现快速的应用部署(在比较了cwRsync、unison、wget、lftp、ftpsync、csync、Syncrify、DeltaCopy、tar、bacula等工具后,最终lftp胜出,咱们采用: lftp -c 'open -e "mirror --allow-chown -x vssver.scc -R --parallel=10 --use-pget-n=10 --log=%LOG_FILE% %LOC_DIR% %REMOTE_DIR%" sftp://%USER%:%PASSWORD%@%IP%'这样的脚原本进行增量发布,将编译后的结果与部署环境上的进行自动比对更新)。

  4. 支持基于Ant和基于Maven的代码走查,编写Ant脚本和Maven脚本以支持PMD、Checkstyle、findBugs进行代码走查(因为jenkins中代码走查插件生成界面时会消耗大量系统资源,对机器性能影响很大,后面咱们改为了经过脚本方式生成并将走查结果打成压缩包发邮件给相关人员)。

  5. 支持基于Maven的代码的单元测试(采用TDD编码方式)。

  6. 支持自动化测试(调用ZTP,ZTP是我司自产的一个自动化测试工具,支持自动化脚本录制、回放等工做,其工做原理与robotframework比较相似,ZTP工具支持批处理脚本调用,故能够集成到jenkins中)。

当时,咱们还想在Jenkins上集成更多的功能,包括:

  1. 改进websphere-deploy插件,支持界面部署WebSphere应用包(这个计划后面搁浅了,主要是脚本方式已经能支持绝大部分WAS集群的部署了)。

  2. 应用环境迁移,经过将应用环境迁移过程自动化为Jenkins中的任务,实现应用环境迁移过程的自动化和可视化(目的就是想实现研发、测试及生产都是一套环境,测试经过后的环境能直接迁移到生产上去,当时只是作运维的一种本能的想法,但也由此引起了对Docker的关注)。

  3. 业务监控系统相结合,造成流程化的跨多个Jenkins任务的、总体的应用环境部署自动化和可视化,为未来生产环境部署的自动化和可视化做准备(曾经研究过一段时间jenkins的FLOW插件,当时FLOW插件的版本还比较低,功能还很弱,引入第三方的工做流工做量会比较大,而事实上这种流程化的编译部署过程实用性也比较低,这事就慢慢搁浅了)。

目前我所在的产品线全部的项目都已经采用Jenkins进行编译、打包、代码走查及自动部署到测试环境和准生产环境(运营商项目的生产环境发布后面会逐渐由我司自主开发的另外一利器“云应用管理平台”来支持,后面还会讲到)。

2基于Docker的应用发布

前面讲了,关于应用环境迁移的想法引起了我对Docker的兴趣,实际上这时已是2014年的6月份了,因而就跟一些同事自学鼓捣一下,当时Docker 1.0才刚刚发布,当时也就把官网的例子都作了一遍,参考官网做了Hadoop的镜像,本身又做了WebSphere的镜像,搭建了Registry,断断续续的做了一些东西,算不上很深刻,而Docker自己也在不断发展,感受隔几天就有一个新版本发布出来。

Docker大潮来势汹涌,到9月份的时候,我一开始说的那个巨大项目的运营商中有个技术专家提出了要用Docker来做应用发布平台,当时简直是不谋而合,因而有了一个项目,也就能够明正言顺的进行Docker研究了,不过既然已是一个正式的项目了,那光有几个爱好者是不够的,须要有正规军了,因而请出了公司技术委员会下属的一个研发团队,大约有六七人,也就是“云应用管理平台”的开发团队,一块儿进行相关的研究。给生产环境用的发布平台跟咱们前面讲的用Jenkins做的自动部署仍是有些不一样的,生产环境上版本的发布通常是有严格限制的,包括版本要求、时间要求(升级时间、故障率和故障解决时间)等,这一点是与如今的互联网企业升级自家的系统是彻底不一样的。

“云应用管理平台”围绕着Docker进行了大量的开发工做,制做了主机管理、容器管理、集群管理、版本计划管理、版本执行管理等等,其架构以下图:


1)Jenkins打包镜像

  • 自动获取SVN代码版本

  • 使用Dockerfile打包镜像,并自动上传到Docker Registry。

2)集群配置

  • 应用基本信息配置

  • 集群应用绑定

  • 环境变量配置

  • 固定端口号配置



3)制定发布计划

  • 选择镜像版本(Docker Registry API获取镜像列表)

  • 选择主机,并设置启动的容器实例数

 

4)执行发布计划

  • 使用Docker Java API链接docker daemon启动容器

  • 记录容器ID

 

5)容器管理

  • 主机检测(能检测主机上是否安装了docker,若是没有能够自动安装Docker)

  • 容器节点增长、缩减,用户选择的应用镜像版本和实际运行版本一致时执行伸缩

  • 容器状态监测

3基于Dubbo的跨主机的容器链接

一开始咱们在测试环境上将全部容器都放在一台主机上,测试过程很顺利,但在移到准生产环境上时,因为要模拟生产环境只能将容器部署到不一样的主机上,这时候就发现了一个奇怪的现象,应用之间调不通了,这里要说一下,咱们应用程序是由20多个服务组成的、经过Dubbo【阿里提供的一个服务框架】做为服务总线串连起来的,Dubbo提供了一个方便的服务发现机制,各个服务(称为服务提供者)只要向Dubbo注册中心注册过,注册中心就会将服务的地址发送给一样在注册中心注册的服务调用方(称为消费者),以后即便dubbo注册中心挂了也不影响服务的调用。


当服务提供者部署在容器中时,这时候发现其在Dubbo中心注册的是容器的IP地址,而对处于另外一个主机上的消费者来讲这个IP是不可访问的,咱们当时也参考了多种方式,想让消费者可以链接上服务提供者的IP,查阅资料总结起来大概有两种作法:

  1. 设置容器的IP与主机IP在同一网段内,使容器IP可直接访问【会占用大量的IP地址,且IP会限制在同一网段,在生产环境中每每不可能】。

  2. 经过复杂的iptables路由规则,经过多层桥接方式打通网络【此法是可行的,也是咱们从此要考虑的,但当时一堆开发人员对网络这块都不是太熟悉】。

考虑到当时公司技术委员会下属另外一个研发团队正在作dubbo的研究和改造,因而拉他们进来讨论,结果他们说这个很容易解决,因为主机之间是连通的,而容器在建立时也映射了主机和端口,只须要在服务注册时注册的是映射的主机IP和端口就能够连通了,该研发团队的效率很高,讨论的当天就给出了实现,考虑到局方要求严格管理容器和主机间的映射,咱们将主机IP和端口做为环境变量在容器启动时传入【扩展了dubbo protocol配置,增长了两个配置项 publish host、 publishport,对应主机的ip port,而且在注册服务时将主机的ip port写到注册中心】,果真解决了这个问题。

固然这是一种特殊状况下的跨主机容器链接方式,更为广泛的方式目前咱们正在讨论当中,基于ovs的链接方式是正在考虑的一个方案。

4困难与展望

目前咱们对Docker的使用还比较初步,虽然基本知足了项目的要求,但考虑到未来云平台要求自动扩展、服务发现,这些还有待咱们进一步研究。

5Q&A

Q:你好,问一个问题,咱们前段时间也把Dubbo框架运行在Docker里面,也是采用大家如今的把宿主机和端口做为环境变量传入的方式实现的,我比较想了解的是后继大家有什么更好的方式实现,我看你提到了基于OVS的方案?

A:有两种解决办法:

  • 一种是将显式传递环境变量作成隐式的自动获取宿主机和端口,从而减小配置工做;

  • 另外一种则是通用的Open vSwitch(OVS)方案,这是与Dubbo无关的。

Q:容器中的Dubbo注册问题,扩展Dubbo的protocol配置,增长publishhost和publishport解决了注册问题,能不能说的详细一点?

A:目前咱们硬编码了Dubbo的protocol,在里面加了两个字段,这种扩展方式有点野蛮,但Dubbo自己提供的扩展方式目前很难支持传递环境变量方式,咱们在考虑将环境变量隐式获取,这样就不用硬编码了。

Q:大家用的仍是端口映射吧,那么也会存在不少个端口的问题吧,像IP能够访问同样?

A:在这个项目中做端口映射是运营商的要求,他们要求能经过配置来设置每一个容器的端口映射,这与他们现有的运维方式有关,一开始咱们考虑的是docker的自动端口映射,固然这种需求未来确定是趋势,咱们的“云应用管理平台”中也有考虑。

Q:为什么考虑Dubbo而不是etcd作服务发现,Dubbo的优点是什么?

A:选中Dubbo是很偶然的,公司自己有ESB产品,但相对来讲比较重,通常用于多个产品间的调用,而Dubbo咱们通常用于产品内部多个模块之间的调用,是一种轻量级的服务总线,Dubbo这种方式不依赖于硬件和操做系统,etcd并非全部操做系统都能支持的吧,固然我也没有对etcd做深刻的研究。

Q:Jenkins的slave是选用了虚拟机仍是直接物理机?

A:咱们的Jenkins的master和slave都是用的虚拟机。

Q:代码提交上去,若是测试有问题,回滚是肿么处理,也是经过Jenkins?

A:这里要分状况来讲,一种是测试发现问题,提单子给开发修改,开发修改完代码提交到scm,而后触发Jenkins下一轮的编译和部署;另外一种状况是若是某次部署失败,则会用部署前的备份直接还原。

Q:请问用的Registry V1仍是V2 ,分布式存储用的什么,有没有加Nginx代理?

A:目前咱们用的是V1。生产环境可能是集群环境,须要加Nginx做分发。目前应用中分布式存储用的并很少,通常来讲用hdfs来存储一些日志便于后面分析,也有用FastDFS和MongoDB的。

Q:底层云平台用的是私有云?

A:底层平台一开始想用私有云,但运营商已经有了vCenter的环境,所以后来咱们改用Ansible来管理各种物理机和虚机,用Docker API来管理容器。

Q:Dubbo实现的服务发现是否具有failover功能,自动检测并迁移失败容器?

A:Dubbo目前不具有迁移容器的功能,其failover是经过负载均衡和心跳链接来控制的,自动检测和容器迁移咱们通常会考虑放在监控系统里面来作,若是放在Dubbo里面会加剧Dubbo,只因此用Dubbo也是考虑到它的轻便性。

Q:可否谈下对Jenkins+Mesos的见解,这个涉及到docker-in-docker的必要性?

A:Mesos咱们才刚刚接触,我了解的不太多,至于docker-in-docker我以为生产上很难用,由于性能方面损失比较严重,咱们作过性能测试,非--net=host方式的容器性能损失接近30%。

Q:能具体介绍下利用Dockerfile打包镜像吗,jar包也是在这一步编译出来的吗,这样发布出去的镜像会既包括代码又包含jar包吧?

A:咱们的镜像中是不包含代码的,镜像里面是产品包,编译是在打镜像以前作的。

Q:对不生产环境中不适合以容器运行的组件,Jenkins+Docker是否就没有优点了?

A:开发和测试环境仍是颇有优点的,固然有些有大量IO操做的服务其实不适合放在容器里面,这主要是性能方面的考虑。

Q:云平台是怎么管理容器的,有没有使用Docker生态系统相关的组件?

A:目前没有用到Swarm\Compose之类的组件,未来要看这块的发展了,也有可能会引入k8s或者Mesos来做管理,这些目前都在考虑当中 。

Q:在怎么判断部署Docker服务不可用,不可用后自动迁移仍是如何操做?

A:目前云应用平台只在发布时才对Docker容器进行状态检测,若是检测到失败,会根据指定的容器数目进行从新建立。后续咱们会把对容器状态的持续检测统一放到监控系统中。

Q:我是否是能够这么理解,大家的Jenkins是主要用来CI,而实际集群管理则是云应用平台作的?

A:是的,这个是严格分工的,当时做云应用管理平台时,是以测试交付物为起始点的,这里的测试交付物就是CI的产物,容器方式下就是镜像了。

Q:我能够理解Docker是部署在实体机,实体机上都有一个agent的东西负责与管理端通讯,主要负责Docker的管理(安装、部署、监控等)吗?

A:咱们的Docker目前都是部署在虚拟机上的,操做系统是Redhat 7.1,你所谓的agent其实应该就是Docker daemon吧。

徐新坤:这个我补充一下,做为Jenkins的slave,会向slave里面启动一个agent来执行相关脚本命令的。这个属于Jenkins的功能,能够去体验下。

Q:一个应用多个容器大家怎么负载均衡?

A:前面其实回答过,要加Nginx的。

Q:利用Dockerfile打包镜像并上传到Registry更像是CD环节的事情,那在单元测试、集成测试环境是否有利用到Docker呢,是否使用Jenkins中Docker相关的插件了?

A:当前项目的单元测试、集成测试都用到docker容器的。Jenkins中没有用Docker插件,试过感受都不太成熟,目前仍是Docker命令行最方便。

Q:开始的时候有讲若是没有Docker自动部署会自动部署,这个是如何部署的?

A:这个前面讲过,是经过lftp脚本比对编译环境与待部署的远程目录。

Q:也就是大家在虚拟机里面部署的Docker?

A:是的,当前的项目是在虚拟机里面部署Docker的,但我我的观点从长远看来,其实在物理机上部署Docker会更好,因此如今不少私有云好比OpenStack、CloudStack都能支持直接管理容器,不过目前虚拟机仍是不能缺乏的,容器的隔离性不如VM。

Q:若是用nat模式 容器如何指定IP啊?

A:不须要指定容器IP,只须要映射端口。

Q:有经过Dubbo作服务路由么?

A:Dubbo自己就有服务路由的功能。

相关文章
相关标签/搜索