1持续交付现状与趋势分析专家简介:陈能技,新炬网络首席测试专家,10多年来专注于软件测试与质量管理相关方法、技术、工具的研究与应用,著有《软件测试技术大全》、《性能测试诊断分析与优化》等多本畅销书。随着企业对版本上线质量和速度的要求越来越高,迭代开发、敏捷开发模式的接受度越来越高,以互联网企业为首的企业开始广泛实践持续集成,并且结合运维前段工作,往持续交付的方向发展。这点不管是从业界讨论焦点,还是从国内外出版的书籍来看,都有比较明显的趋势。持续集成更强调研发过程的质量控制,持续交付的范围更广,可以认为是:持续集成+自动发布。可以预见,互联网企业探索实践的这些方法论和相关技术,在传统IT领域会被逐渐地引入和采纳。但是传统企业与互联网企业存在比较大的差异,会导致持续交付的应用方式的差异。互联网企业:节奏快、版本发布频率高,上线出故障影响面广,但是一般影响度不高,通过完善的实时监控,发现故障及时发布新版本进行修复。传统企业:第一类,节奏慢、版本发布频率不高,上线出故障影响面不广、影响度不高,这类企业对持续集成的需求不会太强烈,应用持续集成的目的更多地是希望开发过程规范化、透明化。第二类,节奏相对慢、版本发布频率不算高,上线出故障影响面广,影响度高,这类企业对持续集成和自动发布都会有需求,应用持续交付的目的是希望把好版本发布的质量关,同时需要在研发过程中控制质量风险,所以需要持续集成。第三类,节奏快、版本发布频率高,上线出故障影响面广、影响度高,这类2企业一般已经在应用迭代开发、敏捷开发的模式,对持续集成、敏捷测试、自动化测试、自动发布都有强烈的需求。基于Docker实现灵活的企业应用持续集成与自动部署随着业界持续发布技术的逐渐成熟,DevOps在传统企业的应用也逐步完善,下面是某物流行业客户基于Docker实现持续集成和自动部署的案例。在设计持续交付流程的过程中,客户有一个非常合理的需求:是否可以在测试环境中尽量模拟真实软件架构(例如:模拟静态服务器的水平扩展),以便尽早发现潜在问题?基于这个需求,可以尝试将多台机器划分不同的职责并将相应服务按照职责进行部署。然而遇到的第一个挑战是:硬件资源严重不足。最终申请到了两台四核CPU加8G内存的物理机,同时还获得了一个Oracle数据库实例。因此,任务就变为把所有服务外加持续集成服务器(Jenkins)全部部署在这两台机器上,并且,还要模拟出这些服务真的像是分别运行在不同职责的机器上并进行交互。如果采用传统的部署方式,要在两台机器上完成这么多服务的部署是非常困难的,需要小心的调整和修改各个服务以及中间件的配置,而且还面临着一旦出错就有可能耗费大量时间排错甚至需要重装系统的风险。第二个挑战是:企业内部对UAT(与产品环境配置一致,只是数据不同)和产品环境管控严格,轻易无法访问,也就无法自动化。这就意味着,整个持续发布流程不仅要支持自动化部署,同时也要允许下载独立发布包进行手工部署。最终客户选择了Docker解决上述两个挑战,主要原因如下:1、Docker是容器,容器和容器之间相互隔离互不影响,利用这个特性就可以非常容易在一台机器上模拟出多台机器的效果。2、Docker对操作系统的侵入性很低,因其使用LXC虚拟化技术(Linux内核从2.6.24开始支持),所以在大部分Linux发行版下不需要安装额外的软件就可运行。那么,安装一台机器也就变为安装Linux操作系统并安装Docker,接着它就可以服役了。3、Docker容器可重复用,且Docker本身提供了多种途径分享容器,例如:通过export/import或者save/load命令以文件的形式分享,也可以通过将容器3提交至私有Registry进行分享。Docker与持续集成持续集成(以下简称CI)可以说是当前软件开发的标准配置,重复使用率极高。而将CI与Docker结合后,会为CI的灵活性带来显著的提升。1、创建Jenkins容器相比于直接把Jenkins安装到主机上,选择把Jenkins做为Docker容器单独使用,这样就省去了每次安装Jenkins本身及其依赖的过程,真正做到了拿来就可以使用。2、使用Docker容器作为Jenkins容器的Slave在使用Jenkins容器时,有一个原则:不要在容器内部存放任何和项目相关的数据。因为运行中的容器不一定是稳定的,而Docker本身也可能有Bug,如果把项目数据存放在容器中,一旦出了问题,就有丢掉所有数据的风险。因此Jenkins容器仅负责提供Jenkins服务而不负责构建,而是把构建工作代理给其他Docker容器做。相比直接将Jenkins安装到主机上的方式,Jenkins容器的解决方案带来了4明显的好处:1、重用更加简单,只需一行命令就可获得CI的服务;2、升级和维护也变的容易,只需要重新构建Jenkins容器即可;3、灵活配置Slave的能力,并可根据企业内部需要预先定制具有不同能力的Slave,比如:可以创建出具有构建RubyOnRails能力的Slave,可以创建出具有构建NodeJS能力的Slave。当Jenkisn需要具备某种能力的Slave时,只需要dockerrun将该容器启动,并配置为Slave,Jenkins就立刻拥有了构建该应用的能力。如果一个组织内部项目繁多且技术栈复杂,那么采用Jenkins结合Docker的方案会简化很多配置工作,同时也带来了相率的提升。Docker与自动化部署自动化部署通常不仅仅代表以自动化的方式把某个应用放置在它应该在的位置,这只是基本功能,除此之外它还有更为重要的意义:1、以快速且低成本的部署方式验证应用是否在目标环境中可运行(通常有TEST/UAT/PROD等环境);2、以不同的自动化部署策略满足业务需求(例如:蓝绿部署);3、降低了运维的成本并促使开发和运维人员以端到端的方式思考软件开发(DevOps)。在本案例中,由于无法将UAT乃至产品环境的部署全部自动化,而客户希望验证软件架构的需求,采用的策略是:尽量使测试环境靠近产品环境。1、标准化Docker镜像很多企业内部都存在标准规范,定义了开发中所使用的语言、工具的版本信息等等,这样做可以统一开发环境并降低运维团队负担。在应用Docker的环境中,可创建一系列容器并把它们按照不同的职能进行分组:5把Docker镜像分为三层:基础镜像层、服务镜像层以及应用镜像层,下层镜像的构建依赖上层镜像,越靠上层的镜像越稳定越不容易变。(1)、基础镜像层负责配置最基本的、所有镜像都需要的软件及服务,例如openssh-server(2)、服务镜像层负责构建符合企业标准化规范的镜像,这一层很像SaaS(3)应用镜像层和应用程序直接相关,CI的产出物分层后,由于上层镜像已经提供了应用所需要的全部软件和服务,因此可以显著加快应用层镜像构建的速度。曾经有人担心如果在CI中构建镜像会不会太慢?经过这样的分层就可以解决这个问题。2、更好的组织自动化发布脚本为了更好地组织自动化发布脚本,版本化控制是必须的。在项目中单独创建了一个目录:deploy,在这个目录下存放所有与发布相关的文件,包括:用于自动化发布的脚本(shell),用于构建镜像的Dockerfile,与环境相关的配置文件等等,其目录结构是:├──README.md6├──artifacts#war/jar,数据库迁移脚本等├──bin#shell脚本,用于自动化构建镜像和部署├──images#所有镜像的Dockerfile├──regions#环境相关的配置信息,我们只包含本地环境及测试环境└──roles#角色化部署脚本,会本bin中脚本调用这样,当需要向某一台机器上安装java和jboss镜像时,只需要这样一条命令:bin/install.shimages-p10.1.2.15javajboss3、构建本地虚拟化环境通常在聊到自动化部署脚本时,大家都乐于说这些脚本如何简化工作增加效率,但是,其编写过程通常都是痛苦和耗时,需要把脚本放在相应的环境中反复执行来验证是否工作正常。建议最好首先构建一个本地虚拟化环境,有了它,就可以在自己的机器上反复测试而不受网络和环境的影响。Vagrant是很好的本地虚拟化工具,和Docker结合可以很容易的在本地搭建起与测试环境几乎相同的环境。由于部署脚本通常采用SSH当方式连接,所以,完全可以把这两台虚拟机看做是网络中两台机器,调用部署脚本验证是否正确。4、构建企业内部的DockerRegistry上面提到了诸多分层镜像,如何管理这些镜像?如何更好的分享?答案就是使用DockerRegistry。DockerRegistry是一个镜像仓库,它允许你向Registry中提交(push)镜像同时又可以从中下载(pull)。