本文译自《DevOps2.0的工具集(DevOps黑宝书)——打造自动化的持续交付流程》一书。
做小型的新项目感觉很棒,上一次我做这样的项目还是在2015年的夏天。虽然那个项目有不少问题,但做起来确实很高兴。因为在做这种小型而且相对来说比较新的项目产品时,我们可以按照自己的喜好选择技术手段、方法策略以及整体框架等。
我们能用微服务么?当然可以!我们能试试Polymer和GoLang么?必须的!无拘无束自由自在的做项目真的很爽。虽然我们或许会做错误的决定,而且这个决定可能会让我们的进度延缓一周,但起码不会像其他项目那样,一着不慎满盘皆输。简单来说,我们不需要考虑保留系统的影响,一门心思只管做新项目。
但是我大部分的职业生涯并不是在做新项目。曾经我有过很好的机会,或者说很差的机会,从事于大的保留系统工作。我所在的公司底蕴深厚,早已经形成了它们的固有系统,也不知道是好是坏。现有的业务必须保持运行不中断,但又很明显需要创新和改善,这时我就必须做出权衡。那段时间里,我一直努力在寻找新的方式方法对系统进行改进。不得不承认,这让我很苦恼,而且我所做的诸多改进尝试均以失败告终。
在本书中,我将会对过去的失败一一进行分析,从而做出改善,取得进步。
持续集成、持续交付、持续部署
接触并了解CI(持续集成)和CD(持续交付)对我来说至关重要,而且这两种概念本身也意义非凡。在过去,集成的推迟意味着整体进度延迟几天、几周甚至是数月,等待着实让人受尽折磨。我们几个小组分别负责开发不同的服务和应用,经过了数月的辛勤工作,迎接我们的却是集成阶段第一天的人间炼狱。我只想说,Dante确实是一位不错的开发人员,不过在集成阶段他写的代码都是地狱焰火。
令人不爽的集成阶段第一天,大家都来到办公室,阴沉着脸。集成工程师宣布整个系统已经设置好,可以开始“游戏”了,办公室里鸦雀无声。然后他启动了系统,界面不时显示黑屏,我们也心如死灰,数月的工作至此再次被证明徒劳无功。服务和应用无法集成,接下来就是长时间的修补工作。在一些案例中,我们可能会做好几周的重复工作。事先确定的各种需求总会有不同的理解,而这些不同的理解又最终会在集成阶段暴露无遗。
终于,极限编程(XP)软件出现了,在XP的帮助下,我们迎来了CI。今天,持续集成的理念听起来再合理不过了。很明显,怎么可能直到最后一刻才开始集成!但当时,在瀑布式开发的时代,人们确实还没有持续集成的概念。我们部署了持续集成的流程,开始检查每一份提交、进行动态分析、单元测试、功能测试、打包、部署以及运行集成测试。
如果其中任何一个阶段出现问题,我们就会中止流程,优先对流程中发现的问题进行处理。流程本身的速度很快,某个开发人员向库提交仅仅几分钟后,我们就能知道是否出现问题。再后来,持续交付(CD)逐渐发展壮大,而我们在使用CD的情况下,应该可以保证任何一个通过流程的提交都可以直接应用投入到生产中。不仅如此,除了保证开发中的每一部分都可直接投入应用,我们还能够直接使用持续交付部署任意一部分,无需任何人的任何批准或认证。最厉害的是,所有这些过程都是全自动化的。
梦想成真,真的!当时这种流程对于我们来说就是一个梦想,并非是我们设法实现的,为什么呢?我们曾经犯过错误,我们以为CI/CD是运营部门的工作(现在我们叫它们DevOps),我们以为我们可以创造出一种流程对应用和服务进行环绕式处理,我们以为CI工具和框架已经成熟了,我们还天真的以为架构、测试、业务沟通和其他工作是他人的任务。事实证明我们错了,我错了。
现在我明白了,成功的CI/CD意味着渗透到每一个环节,不积跬步无以至千里。我们需要考虑周全,从架构、测试、开发、运营一直到管理和企业期望,确保万无一失才能取得成就。那么,我所经历的那些失败的开发项目,到底是哪里错了呢?
架构
许多研发人员历经好几年开发出来的一个巨石应用,不经测试就进行紧耦合,而且还使用过时的技术。这种尝试无异于让一位80岁的老太婆返老还童。我们可以改变她的容颜,但不论我们如何努力,最多只能让她看起来不那么老,不可能让她重返18岁。同样,有些系统本身也“上了年纪”,无法跟得上现代化的脚步。我尝试过,将老的系统与现代技术相结合,但屡屡失败,总是事与愿违。而且有时候,尝试让这些老系统容光焕发是亏本的。而且,我也不可能直接对客户(例如银行)说,“你系统太破了,我要给你重新搞一个系统。”重新做系统的风险太大,即便可行,考虑到系统的紧密耦合、年代、过时的技术等等,改变系统的一部分得不偿失。
常见的方法是在新建系统的同时,保持旧系统正常运作,直到新系统完工。但这样做也无异于天方夜谭,类似重做系统这样的大项目需要数年的时间,我们也都清楚这种长期项目通常都没有什么好结果。这种做法比瀑布式的方法还蠢,就像一个人站在尼亚加拉大瀑布下,自个儿还纳闷为什么身上会湿。还不如做一些琐碎的事情,更新JDK都比这有用。很庆幸我自己没有做这些蠢事情,但是面对像Fortran或者Cobol基础代码这样的东西,你会怎么做呢?
这时,我听说了微服务,当时听到微服务的我有如听到了天籁之音。它的种种概念对我来说好到难以置信,可以由不同小组负责不同的小型的独立服务、可以快速理解基本代码、可以在不影响系统其它部分的前提下改变框架、编程语言或基础代码、并且独立的部署微服务。我们总算可以放心的把巨石应用中的一部分拿出来进行操作,不用担心会给整个系统带来风险(比较明显的风险)。这在当时听起来真的是好到难以置信,但它是真的!
可是,凡事皆有利弊,微服务也不例外。在应用过程中,我们发现部署和维护大量的微服务会带来很大的负担。因此我们只好开始将服务标准化(砍掉创新),我们创建了共享库(再次耦合),将各种库部署在每个小组(拖延了时间)等等。换句话说,以往巨石应用产生的服务器配置和冗乱问题,此时又被微服务放大了数倍,而微服务本应带来的优势却荡然无存。我们又一次失败了,但我没有气馁,反而愈挫愈勇。
这次我要循序渐进,挨个解决问题,而最重要的问题之一就是部署。
部署
部署过程想必大家也很清楚,将各种代码(JAR、WAR、DLL、或任何你用编程语言编写的东西)装配好,部署到服务器中,服务器本身已经、、、我都不知道怎么说了,因为很多情况下,我们压根不清楚服务器里面到底有什么。随着时间的积累,任何人工维护的服务器都会“爆满”。各种库、可执行文档、配置信息和乱七八糟的文件(gremlins and trolls)。
服务器也会形成自己的性格,年纪大、脾气差、速度还行但不可靠、费时又费力等等。所有服务器唯一的共同点就是他们各不相同,没人能够确定在服务器的预生产环境中进行软件测试的结果与最终投入应用时的表现是否一致。和买彩票没什么区别,全靠运气,而且大部分情况下你都不会中奖,总是失望,总是绝望。
或许你可能会问,为什么当初不用虚拟机呢?好吧,整个问题我有两个答案,取决于“当初”的定义。一个答案是在“当初”,我们还没有虚拟机,或者说当时虚拟机的概念还太新,管理层对使用虚拟机还是持保留态度。另外一个答案是当初我们的确使用了虚拟机,也的确取得了一定的进步。
我们可以用虚拟机拷贝生产环境,用来测试环境等等。但虚拟机也带来了很多更新配置和网络的工作。而且,我们也不知道,这些虚拟机长年累月的使用下来会变成什么样。我们只知道如何复制虚拟机,但一台虚拟机的配置信息和另一台虚拟机还是不一样的,拷贝的信息也只有在一开始拷贝后很短的时间内是保持一致的。做好部署后,改变一些配置信息,瞬间你又回到了一开始,面对着测试结果和投入应用效果不一致的问题。这些差异随着时间的推移会不断积累,除非摒弃人工干涉,用可靠的自动化方式进行重复更新。如果这种方法真的存在,我们就可以创造出不可变服务器(无敌服务器)。
除了在现有服务器上部署应用,然后不断积累差异这条路,我们还可以在CI/CD流程中创建新的虚拟机作为流程的一部分。这样一来,我们就不需要创建JAR、WAR、DLL等等,我们只需创建虚拟机就好了。每当有新应用发布时,我们都可以创建虚拟机把将其当做是一个全新的服务器,这样一来我们就能够确保测试的东西和最后投入应用的东西是一样的。
创建新的虚拟机,部署相应的软件,进行测试,这样生产节点就从老的服务器转换到了新的虚拟机上面。听起来很棒,对吧!但是创建新的虚拟机会延缓进度而且耗费大量资源。老实说,为每一个业务和应用都单独创建一个虚拟机真的不算高明之举。我还是推荐不可变服务器那种方法,但目前我们的技术水平和方式方法还不达不到,所以只能耐心等待。
编排
系统的编排也十分重要。Puppet和Chef工具在这方面起到了关键的作用。能够用编程实现所有与服务器设置和部署有关的东西也是巨大的进步,不仅大大减少了设置服务器和部署软件的时间,而且使研发人员能够完成更加可靠的处理过程。如果让人来做这些工作的话,结果肯定是漏洞百出。那么总归有办法皆大欢喜吧?非也,你可能也注意到了,现在的情况是这样的,每当我们成功改进了系统,取得了成就,通常意味着成本也更高。如果给足够的时间,那么Puppet和Chef脚本和配置也会变成一大堆xxx(此处和谐,请使用想象力自行填写),光是维护这些东西的花费就不敢想象。但我们不得不承认,有胜于无,编排工具虽然存在问题,但也确实极大的减少了我们创建不可变服务器的时间。
部署流程的希望之光
关于研发遇到的问题我可以讲很多,但大家不要误解,我的初衷是寻找改进方法,这些问题在软件历史中都有其一定的作用。但历史的车轮已过,我们应活在当下,放眼未来。很多过去的问题在今天已经得到了解决。Ansible也证实了实现设置和维护的编排并不需要多么复杂和困难。随着Docker的出现,容器逐渐取代了虚拟机,成为创建不可变部署的不二之选。新的操作系统层出不穷,而且都完美的支持容器技术。用于服务发现的各种工具也为我们展示了不一样的软件前景。Swarm、Kubernetes和Mesos/DCOS正为我们打开一扇通往未来的大门,而这一切在几年前几乎是不可想象的。
在搭建大型、维护简便且高扩展性系统方面,随着Docker、CoreOS、etcd、Consul、Fleet、Mesos、Rocket和其他工具的出现,微服务也逐渐成为人们的首选。不得不说,微服务的概念一直都是非凡的,只不过我们当时没有相应的工具来百分百发挥它的作用,但是现在我们做到了!当然,这并不是说我们解决了所有的问题,相反,这意味着每当我们解决一个问题,我们的标准就上升了一个级别,新的问题就会出现。
一开始我对过去的种种满是抱怨,但这不会再发生了。本书讲述的是我们走向未来时应作何准备,讲述的是迈向未来,在全新的领域中冒险,以全新的视角看待事物。谨以此书奉献给那些愿意活在当下而非过去的读者。
这是你最后的机会了,做出选择就没有了退路。选择蓝色药丸,游戏结束,你从梦中醒来,继续相信你愿意相信的假象。选择红色药丸,你仍然活在假象之中,但我会为你揭开这世界的弥天大谎。
--孟菲斯(黑客帝国)
如果你选择了蓝色药丸,我宁愿你没有因为阅读免费章节而买这本书,还看到这里。请不要见怪,道不同不相为谋。但是,如果你选择了红色药丸,那么欢迎来到勇敢者的世界,本书会带你坐上云霄飞车,我们一同发现未来,迎接探索旅程中的未知与挑战。