在过去的几年里,我们不断的在文章、演讲、谈话中了解到DevOps这个词。DevOps声称能够在提升整体系统稳定性的同时,建立更快的反馈回路,并降低产品迭代成本。DevOps的目标令人印象深刻,但作为新生概念,它无法证明能够达到这种预期目标,所以相关的活动很容易会被忽视或是撤销。随着DevOps的发展,有不少公司因DevOps获益,同时还出现大量采用DevOps的组织。现在,正是你调研并实践DevOps的好时机。
对外行来说,容易认为采用DevOps只是一个简单的变化,更像打开了灯泡的开关一样。从这种角度来看,实施这样一个变化会是令人畏惧、可能是无法实现的任务。就像传统工程学一样,试图建立复杂事物而不经分解时,通常结果就是失败。还好,DevOps可以分解成一系列的阶段。而各阶段内改变的内容和时限完全可以由你所在组织自行掌控。
为便于理解,这里用时间轴风格的图表来说明:横轴最左边表示传统运维方式,最右侧表示DevOps方式。这样,就没人会提出“贵公司已经实施DevOps了吗?”的问题,而是更为精确的,如“能谈一下DevOps在贵公司的深入程度吗?”
需要说明一下,本文中的观点和案例基于特定的组织结构,并非普遍适用。这些假设是基于我个人的经验——我曾在多家公司中与运维和开发团队一同工作(运维团队要负责开发环境的维护),也曾做过几个项目。如果这些假设如果和你的组织现状不同,那么观点可能就不适用了。当然,好处是这些观点都可以实际应用在类似的团队中,它们结合了我们在多个工作环境中实际实施的经验。
DevOps的范围
为了更好的理解我们在实施DevOps过程中所跨越的阶段,很有必要详细谈一下时间轴最左边和最右边所表示的内容。
最左边表示传统运维的文化和实践。
传统运维的一种极端情况可以被描述为“黑盒运维”。在这种文化中,运维与开发是分开的,相互间一般不合作,就算合作,也是极为不情愿的。其特点就是开发和运维有着相反的目标。开发团队的任务是为产品增加新功能、不断升级产品,并以此制定绩效。运维团队的目标,则是稳定第一。如果没有进行足够的沟通交流,两个团队就会产生矛盾,当开发人员兴致勃勃的快速开发新功能的时候,运维人员可没什么心情去部署新功能。对稳定系统实施任何类型的变更,都会导致系统产生隐患,因此运维人员会尽可能避免变更。
举个例子:应用开发人员提交了的代码中有一个bug,在特定的边界条件下会导致无限循环,而QA或测试人员均没有发现这个问题。如果运维人员部署了这个变更,会导致一些服务器CPU飙升至100%,造成服务不稳定。如果运维人员不去实施变更,那么就不会发生问题,至少是没有新问题。这就是最左边传统运维的理念。
最右边表示全面实现DevOps的情况,在这里开发和运维是一个角色。这时,开发就是运维,运维就是开发,团队在的共同目标是既要增加新特性,又要确保一定程度的可靠性。
当了解了时间轴两边所表示内容时——特别强调下,两边都是极端——从一个极端跨越到另一个极端,看起来是很不可思议的。但发生这种不可思议的情况是因为你认为这种转变是一气呵成的。如果把这个时间轴划分为不同个可管理的子阶段,那么实施DevOps就会更容易,利益也更加明确,结果也是可以预期的。
DevOps中的文化与技术改变
DevOps需要在组织内部进行文化和技术的改变。从团队文化角度来说,运维和开发的传统思维需要改变,这样才能更开诚布公的进行沟通,实现目标的统一。从技术角度来讲,开发人员需要了解运维团队的工作方式,并加深对系统架构的认识。运维人员需要明白开发流程,并深入了解代码内容。
当把DevOps分解成各个阶段后,我发现通过文化和技术交替的改变来引入DevOps的观念要更加容易一些。后续的工作都会以这种理念进行。这么做的理由是:改变是困难的,变革是几乎不可能的。通过交替的改变,每一个变化将更容易被接受。所以不用进行变革,而是通过一系列文化和技术上交替的变化来进行,最终实现DevOps。通过这种方式,团队不会感到环境一下子变得无法适应了。变化的发生更加自然,组织也更容易接受这些变化。
指标监控无处不在
向DevOps方向迈出的第一步,就是在组织内对架构和应用层面启用指标监控。或者,我更喜欢称之为:监控无处不在。这里有很多演说讨论这个话题,但归根结底就是一个关键性的问题:我的代码到底做了什么?
对于这个问题,开发人员更乐意通过给你看代码的方式来回答。不幸的是,代码仅能反映出代码应该做什么,而不能说明它实际做了什么。代码如同一本烹饪食谱:它记载着制作美味所需的步骤,但是并不能控制最终出产的是不是美味佳肴。生活中,我们都曾按照食谱尝试过烹饪,但是结果却不尽人意。同样的,代码描述了实现期望目标的过程,但是代码对系统的实际影响是不可从代码自身预测的。下例中,开发人员将缓存的过期时间从3600秒修改到了1800秒。当然,这些变化显而易见,但是整个系统会受到什么影响就不得而知了。
运维人员解答这个问题的方式,是登陆入这台机器,从运行中的系统中获取内存利用率、CPU利用率等信息,来确定缓存过期时间修改对整个系统的影响。这才是正确的方式!这种方式能够反映出代码修改对系统的真正影响。运维人员通过更多的数据分析出具体的影响。这些数据为很多重要问题提供了答案,如“这个变更在系统层面上有什么影响?”或“为什么服务X部署后,服务Y就慢下来了?”以前,开发人员在回答这些问题时,仅会考虑代码(在理论上)是如何运行的。但是,实际的数据会比理论依据更有说服力。下图是运维人员所看到的数据:生产系统的运行数据。
这里需要牢记我们在DevOps进程中所处的位置。我们只是从最左侧向DevOps迈进了一小步,仍旧处于传统运维的环境中。因此,目前给开发人员访问生产环境的权限起不到什么作用。大部分开发人员不适应这个新环境,所以他们自然而然的会回到原有的环境中,这是人的天性。在组织内部尝试改变的时候,如果不考虑人员的接受情况,将没人支持这种改变,最终导致不得不回到原有的方式。
可以简单的使用一种对开发友好的方式来展现这些数据:图表。绘图技术发展了很多年,但是在前几年Graphite和Statsd出现后才流行起来。在Graphite中监控系统指标,并提供开发人员相关的API,就能同时完成两件事:运维人员能够展示系统指标,开发人员可以展示应用指标。开发人员除了查看应用登录登出等事件的统计数据外,现在他们也可以查看CPU、内存利用率等数据了。
开发人员可以加入一行代码来计算相关监控指标:
根据监控数据,可以通过Graphite绘制出下述图像:
对于传统运维团队来说,搭建一个监控系统来展示这些指标数据是小菜一碟,而调用Statsd和Graphite的接口使用起来是非常简单的,对于开发团队来说,只需几行代码。通过这些技术的变化,开发人员现在就能全面的了解代码对系统的影响,并对运维工作有一个大致的了解。在这个阶段,开发和运维的合作已经开始了,虽然只是一个小的方面,但可以说你们已经向DevOps迈进了一步。我们选择了一个合适的切入点,那么在此基础上继续发展,未来这种合作会更加广泛。
基础架构的文档化
开发人员在了解生产系统性能及状态之后,会自然而然的对相关的底层系统产生兴趣。对于很多开发人员来说,大规模的生产系统如同一个黑盒:输入一个请求进去,返回一个响应,但是完全不清楚究竟经过了哪些系统。
为了解决这个问题,基础架构应该被文档化。前期,可以使用通过基本的高阶流程图绘制请求处理流程,并反映各种软件在各个环节对请求处理的情况。随着文档化进程的不断深入,文档中应当记录系统架构中每一个模块的具体作用,以及该模块相比于其他方案的优势。除了特定的软件外,文档还应该记录新服务器的上线过程,潜在故障和解决方案,Unix系统工具简介等等。文档中记录的这些内容,是为了让开发人员更容易的从较高层面了解生产系统的架构。
有了这些文档,开发人员随时可以对系统架构进行更深入的了解。通过我们之前部署的监控系统,开发人员能够以更简单的方式来了解系统的运行状态,所以他们更可能对基础架构产生兴趣。在设置了监控指标和记录文档之后,运维黑盒的问题将逐渐解决。虽然目前两支团队之间协作仍不是很多,但是之间的隔阂正在很快消失。
让开发环境成为生产环境的镜像
到目前,开发和运维之间主要是通过监控的数据和文档进行沟通。基于这些认知,开发人员更希望能够在实际环境上做一些测试,对系统的内部机制进行了解。在生产环境上进行这些操作不仅不现实,还会影响到系统的稳定性。较好的方案是提供一些沙盒供开发人员测试。
以此为需求,出现了Vagrant这种工具,它能够以VirtualBox虚拟机的方式将开发环境打包并分发。这些虚拟机通过标准的配置管理工具——如Chef,Puppet或最基础的shell脚本——建立。运维人员可以使用这些工具快速配置出和生产环境相同的开发环境。开发人员很希望在这样的环境中工作,因为和生产环境基本一致。除此之外,开发人员再也不用担心需要手动配置开发环境了,因为通过Vagrant这个工具,运维人员包揽了这些工作。
这种基于生产环境配置的开发环境,相当于为开发人员真实系统的沙盒。如果出现了任何问题,直接将虚拟机删除然后重新建立一个即可。沙盒表面上很简单,但具体的配置过程使可以开发人员了解服务器的分配过程,运维实施变更的过程,以及系统的实际架构。
DevOps的办公时间
开发人员现在有一个沙盒可以在“真正的系统”上进行测试,还可以通过文档去深入了解系统,更可以获取生产系统的监控数据。尽管如此,运维工作仍然令开发人员望而却步。幸运的是,大家都很友善,而现在是两个团队真正开始合作的时候了。合作可以源自论坛、帮助台,甚至是直接过去找某人交流。
关于这方面的实践,我发现在办公时间进行合作是最佳的方案。上班对于运维或开发工程师都是固定的日程安排,此段时间可以用于解答任何类型的问题。这些问题可以简单到“我怎么在机器上搜索文件?”或是复杂到“你能解释一下为什么要这么配置HAProxy的参数么?”办公时间的优势是,无论你问什么问题,别人都不会评论你。工程师在办公时间内可以提出任何的相关问题而无需产生顾虑。
在这个阶段中,一个重要的里程碑已经达到了,那就是:沟通交流!开发和运维团队已经互相理解,他们相互沟通,相互合作,相互影响。
规避开发团队进行运维工作的风险
在继续下一个环节之前,我需要指出,在当前阶段,你的组织中DevOps文化已经比大多数组织的要健全多了。到这一个阶段为止,我们通过低风险的方式,缓慢的,有条不紊的引入了DevOps文化。接下来,我们即将达到前文所述的DevOps时间轴的最右边。相比前面几个阶段,这一阶段会更加激进,而且尚未有完备的定义。但是,有些组织已经完整的转变成为DevOps,并且也慢慢体会到这些变化的好处。
开发人员现在已经有了工具的支撑,开始进行真正的运维工作,并对其负责。和前面的阶段一样,这一阶段也可以划分成更小的阶段,以规避风险,并使人们更容易接受。
第一步是用标准的开源模式进行变更:Pull请求和代码复审。当开发人员希望加入一些新东西时,他(或她)可以直接进行变更并发布一个Pull请求。开发人员可以使用提前在Vagrant中配置好的虚拟机测试这些变更。
Pull请求为运维团队提供了一个对这些变更进行审查和完备性测试的机会。如果有问题,反馈至开发人员,这样就可以避免问题重复出现。最后,Pull请求被合并,这时,开发人员可以为实施一个变更而感到自信和骄傲,而运维人员也会放心,因为变更的审查是由运维负责的。
第二步,这一步在本文撰写时仍具有实验性质:对运维进行一些持续集成。最基础的,是通过类似Jenkins的持续集成服务器去验证运维人员用于创建沙盒环境(可能使用Vagrant管理)的脚本是否正确。也可以进行基本的冒烟测试,如基础设施能够成功产生一个HTTP请求。
当上面的工作部分或全部都准备完成时,开发人员就可以安全的进行变更了。运维人员仍旧负责变更审查工作,所以他们会对此放心。从现在开始,运维和开发的才真正共同工作,并共同承担责任。虽然开发和运维团队依然存在一些区别,但是很快这种区别就会消失。
开发人员们:疯狂吧!
现在,我们准备进入DevOps时间线的最右端:开发团队负责所有运维工作。经过了前面的几个阶段,技术和文化的改变已经使DevOps成为可能。实际情况中,这些阶段是连续的,即不断让两个独立的团队越来越多的在一起工作。运维团队可以不断缩减,而开发团队可以不断扩大。开发人员在少数运维的指导下进行运维工作。在应对系统中断时,开发人员应该随时待命,而运维人员则退居二线。
再次重申一下,能进入这个阶段的前提是前几个阶段的基础十分稳固。监控指标的数据收集是为了能够了解开发的代码对系统整体的影响。文档化的工作使开发人员能够了解更多关于生产环境架构的信息,以便于更好的了解不同变更对系统的影响。使用由自动配置脚本构建的虚拟机以及工作流系统不仅能够节约运维人员的时间,也为开发人员提供了进行研究的沙盒环境。办公室或是论坛,都是开发和运维人员相互了解、学习的可靠环境,你可以畅所欲言问你想要了解的问题。自动化架构测试以及代码审查给开发和运维增加了一层安全保障,降低了运维人员变更的风险。最终的结果就是,团队之间的沟通更加自由,更加信任彼此,使得团队之间的界限更加模糊。
DevOps
采用DevOps的益处很多。首先,组织内的信任和合作将会更加广泛。新功能特性的交付频率也会更高,运维团队不用再说“不”了——因为有更多的人参与运维,而且开发人员同样要对变更负责。DevOps同样能够提升系统稳定性,信不信由你——因为现在有更多的人在关注变更对系统的影响。因为新功能特性的快速交付,需要停机进行大规模升级的变更就会减少。相对的,变更的规模会更小,更可控,可能完全不需要停机了。
在这个时间轴上,你处于什么位置?你想到达什么位置?只要你不在最左边,那就说明你所在的组织已经开始向DevOps迈进了。将DevOps分解成这些子阶段,是为了减少风险,并提升你的自信,如果你认为这些改变没有按照预想中进行,也可以先退回至上一阶段,过段时间再进行尝试。
|