求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
自动化构建的那些事儿:金融网站虚拟案例
 
火龙果软件    发布于 2013-9-25
 

介绍

本系列的第一部分讨论了将你的构建和部署流程自动化的部分好处。促使你这样做的理由有很多:让你的开发者更关注于核心业务而不是流程管理、减少人为因素导致的错误、减少部署花费的时间以及其它很多原因。无论你的动机如何,自动化你的构建流程永远是正确的回答。

本篇文章中,我们将以一个虚拟的金融机构的企业网站作为示例,将其构建过程一步步完全自动化。

案例描述

我们的公司叫做第三国民银行(3rd National Bank),是一家本地商业机构。我们的在线银行应用包括前端web应用层(ASP.NET),可接入移动应用的RESTful服务层(WebAPI),一系列使用了传统的领域驱动设计方式来分离业务逻辑、领域对象及数据访问的内部服务层(WCF),以及一台SQL Server数据库。

软件团队使用Mercurial作为源代码控制系统,并使用特性分支的策略定期交付新特性。该策略为每个新特性或bug创建一个新分支,分支代码在测试完成后就会合并入主分支等待发布。

在现阶段,所有的构建和部署过程都是由软件团队手动完成的,导致开发者每周都得花费几个小时,停下手上的编码工作去维护他们的资源库和服务器。我们在尝试改变现状,尽可能多的将过程自动化。

构建脚本

构建脚本是自动化构建过程的第一步。脚本的形式可以是多种多样的:可以是shell或者批处理文件、基于XML的文件,或者由现有或定制的编程语言所写;可以手写或自动生成;也可以完全从IDE环境中隐藏。你的流程甚至可以组合使用多种技术。在这篇示例中,我们使用NAnt作为构建脚本引擎。

在我们的环境中,前端web应用、暴露给外部的服务以及内部服务各是一个独立的Visual Studio解决方案,另外SQL数据库也是一个独立的database解决方案。我们将创建一个主构建脚本文件3rdNational.Master.build,看起来差不多是这样:

<project name="3rd National Bank" default="build">
<target name="build">
<call target="createStagingEnvironment" />
<nant buildfile="BankDB/BankDB.build" target="build" />
<nant buildfile="ServiceLayer/ServiceLayer.build" target="build" />
<nant buildfile="OnlineBanking/WebUI.build" target="build" />
<nant buildfile="ExternalServices/ExternalServices.build" />
</target>
</project>

这段脚本没有做什么具体的事,它仅仅是调用了那四个解决方案的构建脚本。每个解决方案都有一个构建文件,其中包含了编译及准备这一部分应用程序的所有代码。

现在让我们来看一看其中一个解决方案的构建脚本。每个解决方案都基于相同的基本步骤:准备、编译及暂存。ServiceLayer.build就是一个基本的编译脚本,它的语法也非常容易理解:

<project name="ServiceLayer">
<property name="msbuildExe" value="c:\windows\
microsoft.net\framework\v4.0.30319\msbuild.exe" />
<target name="build">
<call target="prepare" />
<call target="compile" />
<call target="stage" />
</target>
<target name="prepare">
<!-- Implementation omitted -->
</target>
<target name="compile">
<exec program="${msbuildExe}">
<arg value="ServiceLayer.sln" />
<arg value="/p:Configuration=Release" />
<arg value="/t:rebuild" />
</exec>
</target>
<target name="stage">
<copy todir="../deploy/BankWcf">
<include name="WcfServices/**/*.svc" />
<include name="WcfServices/**/*.asax" />
<include name="WcfServices/**/*.config" />
<include name="WcfServices/**/*.dll" />
</copy>
</target>
</project>

准备步骤可以包括生成AssemblyInfo文件、重编译代理或者任意数量的其它任务。这个例子里的编译步骤仅仅是简单调用了MSBuild,这是Visual Studio用来编译解决方案的构建引擎。当构建的每一步骤成功后,最后一步会把生成的文件复制到某个暂存区域,留待之后使用。

对于其它三个解决方案我们也采取同样的做法,只是基于不同的项目类型作些微调。

编写构建脚本其实和写代码一样,可以通过不同的做法达到同样的效果。你可以直接使用命令行编译器替代MSBuild,也可以分别构建每个项目文件而不是整个解决方案,还可以使用MSDeploy来暂存或部署你的应用程序,取代过滤及复制文件的方式。说到底,这取决于你适应于哪种方式。只要你的脚本能生成一致的结果,怎样编写都可以。

持续集成

我们已经有了构建脚本,现在需要某些东西来调用它们了。我们可以在命令行下运行构建脚本,但既然我们打算将一切自动化,我们就需要一台机器在适当时运行脚本,这就是持续集成发挥作用的地方了。

我们使用JetBrains的TeamCity作为CI工具。它的售价模型非常合理,并且为项目创建提供了非常优秀的的用户体验。在我们的新构件服务器上安装它非常简单,一切已准备就绪了。

使用TeamCity的第一步是创建一个项目,包含项目名称和一系列的构建配置。让我们创建一个叫做“3rd National Bank”的项目。

我们打算创建一个模板,这样一来,我们打算加入CI里的代码分支都可以引用和主分支下的相同配置。我们首先设置版本控制信息,选择Mercurial作为源代码资源库,设置默认分支,提供认证凭证,并提供获取文件的地址。接下来是构建步骤,选择NAnt选项以及主构建文件。如果我们包含了单元测试项目,我们只需新建一个构建步骤以运行NUnit、MSTest或任何一个我们使用的测试框架。最后,我们设置一个基于版本控制的构建触发器(trigger),意味着主资源库的任何一次签入都会触发一次构建。

TeamCity中还可以做其它很多有意义的事,比如根据构建结果定义失败条件、设置对其它构建的依赖以及定制参数。你可以继续探索各种用法,不过我们现在已经有了一个满足我们所需的基本构建了。

让我们使用这个模板再创建一个新的构建配置“Main Line”,它将处于版本控制树的顶端,包含准备发布到生产环境的稳定代码。特性分支会派生自它,因此我们可以使用这个模板按需创建更多的构建配置,每个配置负责一个特性,所要做的仅仅是为每个配置的源代码设置做一些微调而已。现在,不仅是主线,而且每个特性都可以由代码签入自动触发,并在几分钟内完成构建。

当某个特性完成后,将合并入主线准备发布,对应于这个分支的构建配置就可以移除了。

部署

现在,CI系统已经为我们构建好代码,运行了测试,并且暂存了待发布的内容,我们可以讨论部署的事了。和其它部分一样,部署你的应用程序也有多种策略供选择。以下是将应用程序部署到IIS时可以采用的一些基本策略。

仅备份当前的应用程序,替换为新版本代码,而完全不必考虑修改配置信息。

将你的代码拷贝到web服务器上的一个对应新版本的路径下,这可以预先完成。当一切就绪时,再将IIS指向新的路径。你也可以选择多做一步,即在替换代码之前,先在IIS里创建一个“staging”web应用程序,指向你的新版本代码并做一些基本的验证测试。

不要隐藏版本号,将它们包含在你的URL里:比如http://example.com/v3.4/和http://example.com/v3.5/ , 并通过简单的改动配置文件或IIS设置信息,将根目录应用http://example.com/ 指向你的新应用程序。3.4将依然可用,而只有访问根目录应用的用户会应用新版本。这给了你一个不影响现有用户会话的机会。过了大概一小时后,当你发现3.4不再有用户会话时,你就可以安全地从IIS中移除3.4版本了。

你的团队可以决定对你来说最佳的方案,这取决于你的组织对系统正常运行时间及不可用时间所制订的政策,以及数据库的设计方针。拿我们作为例子来说,我们预期每周可以有一小时的不可用时间,因此我们会采取简单的文件拷贝策略,以便能够给我们充足的时间,在系统恢复前备份、部署代码和数据库及运行测试。

你的CI系统已经暂存了待发布内容,因此你的工作仅仅是将这些文件放到生产服务器上,并部署你的数据库改动。如果你的本机具有访问构建服务器和web服务器文件系统的权限,那么只需运行如下的批处理文件就可以简单地完成文件拷贝工作:

rem BACKUP
robocopy /E \\web1\www\BankWeb \\web1\Backups\BankWeb\%DATETIME%
robocopy /E \\web1\www\BankRest \\web1\Backups\BankRest\%DATETIME%
robocopy /E \\svc1\www\BankWcf \\svc1\Backups\BankWcf\%DATETIME%

rem DEPLOY
robocopy /E \\build1\BankWeb\deploy \\web1\www\BankWeb
robocopy /E \\build1\BankRest\deploy \\web1\www\BankRest
robocopy /E \\build1\BankWcf\deploy \\svc1\www\BankWcf

...etc...

如果你不具有完整的文件访问权限,那你需要更有创意的方法来部署文件。当然,你可以通过远程桌面访问服务器,或者跳板服务器以执行批处理文件或手动拷贝文件。但请记住我们的宗旨是将流程自动化,因此步骤越少越好。理想情况是,你有一台受信的中间系统,在它认证你的身份后就能够部署文件到web服务器了。DubDubDeploy就是这样一种选择,它从某个受信的服务器通过HTTP方式拷贝代码,使得你可以在不具有web服务器的文件系统访问权限时进行部署。

部署数据库也有多种方式,仍然取决于你的组织。在这个示例中,我们使用了一个database项目,因此只需运行一句命令就可以将项目内容与生产数据库中的内容自动对比,运行脚本实现内容改变,并运行你所编写的填数据的定制SQL语句。如果你乐于让系统自己完成这些任务,那只需执行以下命令就可实现:

msbuild.exe /target:Deploy p:TargetDatabase=3rdNational;
TargetConnectionString=”Server=db1;
Integrated Security=True”;
Configuration=release BankDb.sqlproj

当然,你有多种方法来执行它,可以作为一个目标对象加入你的NAnt脚本,或者加入TeamCity,或者手动执行,也可以放入一个部署批处理文件中。

结论

相比之前那种需要手动实现构建、运行测试、暂存、备份及部署代码流程的方式,我们已取得了很大的进步。现在,我们有编译代码的脚本,持续且稳定地运行这些脚本和测试的系统,以及简单且可重复的部署任务。

如果你没有时间,也不必一次到位。你可以一次只做一点点,而仍旧可以从每个步骤中得到好处。比方说,你可以在一小时之内为你的整个应用创建一个基本的构建脚本,然后可以再花一小时进行测试和调试,以确保构建结果和原先的方式一致。那么即使没有使用CI或其它自动化工具,你也降低了构建和暂存应用的难度。等到下次手动进行部署时,你甚至不用打开你的IDE。也许你有时间在下周或下个月搭建一个简单的CI项目,然后在下下个月继续改进。没准当你回过神来的时候,你已经有了一套完整的自动化流程了。

在这个示例中我使用了.NET,NAnt和TeamCity,不过基本的原理也可以应用到其它平台。无论何种操作系统、编程语言、服务端技术、源代码管理策略和团队结构,自动化都是可以实现,并且值得投入精力的。

 
相关文章

CMM之后对CMMI的思考
对软件研发项目管理的深入探讨
软件过程改进
软件过程改进的实现
 
相关文档

软件过程改进框架
软件过程改进的CMM-TSP-PSP模型
过程塑造(小型软件团队过程改进)
软件过程改进:经验和教训
 
相关课程

以"我"为中心的过程改进(iProcess )
iProcess过程改进实践
CMMI体系与实践
基于CMMI标准的软件质量保证
 
分享到
 
 

相关文章
由外而内看敏捷软件开发
架敏捷开发中史诗故事与用户
看板任务管理
面向全球化的有效敏捷交付
小型团队快速开发方法
DevOps,不是一个传说!
更多...   

相关培训课程
统一过程及应用
敏捷过程实践
基于XP/RUP的迭代开发
软件开发过程指南
SCRUM过程实践
敏捷测试-简单而可行

成功案例
某博彩企业 产品经理与产品管理
北京 研发团队与工作管理
广东金赋信息 敏捷开发过程与项目管理
某支付平台 软件配置管理与发布管理
富士 软件外包项目管理与进度管理
塞孚耐 基于Scrum的敏捷开发
更多...