持续交付2. AgileChina 2011
赢得 2011 Jolt Excellence Award
“The book will redefine agile process and CI ;
and it will have as much influence as
Refactoring.”
中文版 预计 10 月中旬出版
http://drdobbs.com/joltawards/231500080?pgno=7
12. AgileChina 2011
www.etsy.com
WWW.ETSY.COM
注册用户总数 : 570
万
注册商家总数 : 40
万
每月浏览页面数 : 7.75
亿
13. AgileChina 2011
2010
在 1644 次部署中
有 4 次事故,
MTTD : (诊断 )
6.5 分钟
MTTR : (恢复)
6 分钟
16. AgileChina 2011
频繁发布
从用户那里得到反馈
Customer
Development
Agile Product
Development
Eric Ries, 《 The Lean Startup 》
19. AgileChina 2011
频繁发布
从用户那里得到反馈
减小发布的风险
真实的项目进度
项目
变更量 范围
项目范围
开发完成
测试完成
发布完成
时间 时间
25. AgileChina 2011
特性
可行性 计划 测试
探索 开发 发布
评估 与估计 与审核
与发现
3天 1周 10 天 7周 1 周 2 小时
增值时间
等待时间
1周 10 天 3天 5天 2天
26. AgileChina 2011
编译
静态检查 自动化验
收测试
本地测试 用户验收 发布
非功能性 测试
快速测试
测试
打包
DEV CI TEST UAT PRODUCTION
27. AgileChina 2011
版本控制 构建和 自动化 用户
交付团队 发布
库 单元测试 验收测试 验收测试
提交
触发
反馈 F
提交
触发
反馈 触发
P
F
反馈
提交
触发
反馈 触发
P
P
反馈 点击按钮
P
P
P
反馈
点击按键
29. AgileChina 2011
部署流水线 ( Deployment pipeline )
构建在生产环境上运行的信心指数增加
所用环境与生产环境的相似度增加
提交阶段 用户
编译 验收测试
单元测试 验收测试
生产环境
代码检查 阶段
构建安装
包 容量测试
反馈速度变慢
32. AgileChina 2011
部署流水线
全
团 开发 全
面
队 面
功
测试
自
合 自
能
部署 动
动
作 团
化 监控 化
队
持续改善
33. AgileChina 2011
原则
可重复且可靠的流程
全面自动化
一切皆版本控制
将痛点尽量前移,并频繁的练习
质量内建
“ 完成”就是指“发布”
所有人对交付负责
持续改进
34. AgileChina 2011
实践
使用相同的方式向所有环境部署
对部署进行自动化冒烟测试
让各类环境尽可能相似
任何环节出现问题,停止整个流水线
39. AgileChina 2011
关
开
配置文件
性
com.xxx.journal_sites.feedproxy = off
特
com.xxx.portal.search_history = off
页面使用
#if($switcher.isOn("portal.search_history"))
<a href="#siteUri()/search_history">
<span>Search History</span>
</a>
#end
40. AgileChina 2011
某个新功能无法在一个发布周期内完成
特性开关 ( Feature Toggle )
无用的代码要及时清理
不变的部分跟变化的部分分离
特性分支( Feature Branch )
42. AgileChina 2011
某个新功能无法在一个发布周期内完成
特性开关 ( Feature Toggle )
无用的代码要及时清理
不变的部分跟变化的部分分离
特性分支( Feature Branch )
43. AgileChina 2011
某个新功能无法在一个发布周期内完成
特性开关 ( Feature Toggle )
无用的代码要及时清理
不变的部分跟变化的部分分离
通过抽象代替分支 ( Branch By Abstraction )
44. AgileChina 2011
象
抽 支
过 分
通 替
代
实现步骤:
1. 找到边界;
2. 加入适配器;
3. 添加新的实现;
4. 如果必要,删除原有实现。
52. AgileChina 2011
定义环境及角色
'uat': {
'app': ['ms5uat-proxy-001.my.com', 'ms5uat-proxy-
002.my.com', 'ms5uat-proxy-003.my.com', 'ms5uat-proxy-
004.my.com'],
'admin': ['ms5uat-cpanel-001.my.com'],
'daemon': ['ms5uat-comm-001.my.com'],
'batcher': ['ms5uat-celery-001.my.com’]
},
53. AgileChina 2011
为任务分配角色
@roles('app', 'admin', 'daemon', 'batcher')
def prepare():
with cd(PACKAGE_DIR):
run('bin/prepare.sh')
with cd(PACKAGE_DIR / 'task'):
run(…)
54. AgileChina 2011
执行
ENV=uat fab -f deploy.py prepare stop_all copy_files
install_modules init_master_secret start_all
55. AgileChina 2011
执行
ENV=uat fab -f deploy.py prepare stop_all copy_files
install_modules init_master_secret start_all
56. AgileChina 2011
执行
ENV=uat fab -f deploy.py prepare stop_all copy_files
install_modules init_master_secret start_all
57. AgileChina 2011
执行
wget http://ci-server/build/install-1.0.44-20110712.sh
chmod +x install-1.0.44-20110712.sh
ENV=uat ./install-1.0.44-20110712.sh
62. AgileChina 2011
package { ["java-1.6.0-openjdk-devel", "git", "ant”]:
ensure => "present"
}
package { "activemq-info-provider-5.4.0-2":
provider => "rpm",
ensure => "present",
source =>
"http://www.puppetlabs.com/downloads/mcollective/activem
q-info-provider-5.4.0-2.el5.noarch.rpm",
require => Package["activemq-5.4.0-2"],
}
71. AgileChina 2011
Q&A
乔梁 李剑
微博 : http://weibo.com/Tony1130
博客 : http://www.iamxiaodao.com
博客 : http://blog.csdn.net/Tony1130
邮件 : veryfaint@gmail.com
邮件 : qiaoliang.email@gmail.com
中文站: www.continuousdelivery.info
Editor's Notes 我会和大家一起讨论。。。。。。,然后李剑将和大家一起分享。。。。。 首先让我们以一个真实的故事开始我们的讨论。 一个金融企业,对外提供金融服务平台,有 一个 60 多人的开发团队。它的情况是这样的: 两周一个迭代 每个迭代中都有分析、设计、开发、测试和演示活动 做持续集成,每次提交都会做构建,运行数千个单元测试和一些功能测试。 当计划开发的功能完成之后, 做 code frozen , 专职的测试团队做集成测试。( bug fixe ) -> 直至达到一定的质量要求。 之后得到一个可部署的版本。 1. 申请试运行部署。 2. 由运维团队按照由开发团队准备好的部署步骤进行操作(这个部署步骤通常是一个七八页的 word 文档) 3. 部署完成后进行监控 一切正常后, 开发团队提交正式上线审请,然后由运维团队执行操作。 但是,这里存在着:软件交付过程中,所谓的“最后一公里”问题。 然而,这里恰恰存在着“最后一公里”问题。 所谓最后一公里,是指软件“开发完成”之后,尚未投入实际运行并创造业务价值的阶段。 “ 最后一公里”导致: 开发完成的代码在“仓库”里保存了一段时间,这段时间,不产生投资收益。 这段时间不可预期(有长有短),使项目计划也很难预期。 做软件产品,都是持续开发。延迟的反馈,会影响下一次发布计划。 每次试运行之前都有手动回归测试 +bug fix , 时间长度不固定,一般为 2 ~ 4 周。 试运行环境和生产环境的申请都需要三、四天的审批时间 顺利的话,每次实际部署操作都需要一整天的时间 所以,该项目一切顺利的话,“最后一公里”至少需要一个月以上的时间。 而且,并不是每次都这么顺利。经常出现环境不一致导致的问题,操作部署不一致,操作失误等造成的问题。 Web2.0 ,颠覆了传统的业务模式。很多创业公司使用了另一种交付方式。比如 Flickr, Etsy , Facebook 等 平均故障诊断时间 平均故障恢复时间 Steven blank- “four steps to the epiphany” Flickr 之前是 Game Neverending ,一款大型多人同时在线游戏,运行于 2002 年至 2004 年。 Flickr 目前已经变身为一个优秀的照片管理和分享服务,在业余选手和专业摄影师中非常流行。该网站在 2007 年以 4000 万美元价格卖给雅虎。 扎克伯格创业初期开发的网站是 Facemash ,对相邻的两张照片评分。 Twitter 前身是 Odeo ,这是一款播客服务。 植物大战僵(中国游戏开发者大会, Play early, play often… ,尽早出游戏原形,得到反馈 prototype ) 很容易纠正偏差 持续部署也变得很容易 很容易纠正偏差 持续部署也变得很容易 第一条原则: 交付有用的、高质量的软件 缩短开发周期 不可预期 -> 可预期 停止交付低质量的软件 通过一键式部署尽快地给所有人带来反馈, 不但是开发人员,还包括测试人员、 DBA 和运维人员 通过价值流分析方法对整个的软件产品开发过程进行建模 让我们看一看软件产品的整个生命周期是什么样的 持续交付主要关注软件产品开发过程中的后三个环节。 为了频繁的、持续的向用户交付可用的软件,就要像流水线把零部件装配成可以付运的成品一样,有一种自动化的机制,从代码的提交开始,经过重重环节,把代码装配成可以工作的软件,最后运输到用户手中。 为了对这三个环节进行改进,让我们再来进一步分析一下。 只改动一行代码的情况下,这个新版本从提交到上线需要花多长时间? 而这个过程是可靠且可重复的吗? every build goes through this process 多个环节与活动,多个角色,全面自动化 我们首先遇到的困难就是,一个新特性,没有办法在两周甚至四周,两个月的时间内完成, 只有把它相关的大部分 user story 全都做完,才能够上线给用户提供完整的体验 OK ,现在就出现冲突了,有时候几个特性同时开发,一个特性开发的时间短,优先级高,是可以快速发布为用户提供服务的;另一个特性需要的时间长,四五周才能做完,我们不能把未完成的功能暴露给用户。这个时候怎么办? 于是,我们引入了特性开关。 这个技术的实现机制基本上都是用一个配置文件来定义某个特性是处于开还是关的状态;然后在代码中来判断。其结果就是,无论是在界面,还是 restful url ,还是后台的逻辑代码,在该 feature 处于 off 的状态的时候,对用户来说,是感受不到它的存在的;这样我们就可以做到频繁发布,不会对用户造成影响。 除了特性开关之外,我们还碰到过这种做法,为了避免新功能的引入,改了现有代码,对老功能造成影响,所以就为特性拉一个分支出来,所有跟这个特性有关的东西都在这个分支上做;于是主干保持两周一次发布,但这个特性分支上的东西直到做完以后,比如两个月,才会向主干提交合并。但是,它是不是真的行得通呢? 看一下这张图,在某个时间点上,引入了一个特性分支,然后呢,为了防止 merge 大量文件带来的冲突风险,就需要频繁 merge ,就 merge 了一次。但很不幸的是,后来在 trunk 上有人做了次重构,重构的地方呢,正好又影响到了 branch 上修改的部分,这次 merge 的工作量就比较可观了;然后又有一次 merge ;最后,终于到了特性可以发布的时候,这时候会发生什么事情呢? CI 红了 长期没有集成过的代码,很可能在无意中破坏掉了其他特性,但是自己不知道,等到提交到 trunk 上要跑完整的自动化验收测试的时候,才发现有很多功能被破坏了,要耗费大量的时间修复。 本质上,还是把变化的部分跟不变的部分隔离,小步重构,小步提交。 通过特性开关和用抽象代替分支两种方案,从开发的角度来看,我们已经基本去除了没法做到小步发布的约束。下面是部署 首先,做部署这项工作的机器,要能够通过 SSH 访问到这些要进行部署的服务器 现在,我们就有了任务、角色、环境、服务器的 hostname 这四个之间的对应关系 然后可以把这套命令写到一个 shell 脚本里面,通过两种方式进行执行 一种是在通过提交阶段之后,需要自动化部署来跑自动化测试,这个时候可以通过 CI 集成的方式来自动触发,现在很多工具都内置了执行 shell 脚本的功能,比如 hudson 另一种是在 UAT 、 Production 这样的环境中,是由客户来决定什么时候可以往这两个环境上部署的,这个时候同样是自动化部署,但是是手工触发。 这个时候可以根据需要,用 wget 把它从 Ci 上下载下来, chmod 加上可执行权限,执行就好了。 还有些事情是这个团队意识到了问题,正在进行改进,还没有做完的 基础设施 是什么:应用程序运行所需的所有资源以及它们的配置。比如 第三方的软件包,中间件 , Application server, database server, 等等 。环境跟我们的产品一样,同样会随着时间的推移发生变化,进行更新 手动升级中遇到的问题描述 耗时,易出错 环境的 update 和 provision 应该是自动的:节省时间、方便多环境之间的同步、少出错。 通过这种方式建立了代码和环境之间的对应关系,同时又使用了 DSL 进行描述让它在可执行的同时变得容易理解、容易维护。 既然是代码,那它同样应该遵守跟产品代码一样的开发实践 应用程序代码应该和环境 (infrastructure) 的配置脚本放在一起,建立起 application 版本与运行环境的关联关系。 修改环境的步骤 => 执行脚本更新环境,运行测试验证环境, 是不是如我们所期待的那样进行了升级 整个流程,从提交代码,到测试,到真正的运行,也应该是自动化的。 结果,每两周一次上线,上线时间从 7 、 8 个小时变成了半个小时不到 回顾整个过程,我们做了哪些改进,达到了这种持续交付状态。 通过这几点,保证交付的质量,提高交付速度 一开始所有人就要向着一个方向努力 保持频繁沟通 每个人都要很方便的看到其他人在做些什么 改善不断进行,最痛的点被消除,然后步伐就会变缓:下一步做什么?往哪里走? 假如,我们把没有提交的代码,正在开发的故事,以及所有没有交付,没有真正为客户、用户创造价值的代码都看作库存,看作是这一片湖水, 那么,交付周期越长,库存越多,那么我们代码中的缺陷,开发技能的不足,自动化能力的缺失,这种种问题就都好比是岩石,深藏在湖水之下。 我们所要做的事情就是,通过不断的缩短交付周期,减少库存,降低湖水,让岩石,让问题暴露出来。从而得到解决。从而走上一条持续改善的道路 在这里,我衷心的希望,在座的每一位,都能够在持续改善的过程中,不断向着持续交付的目标靠拢, 让我们的生活变得更美好 让发布这件事情变得 so easy