孙敬云 –Worktile 高级系统架构师,WTC 成员
1. 研发的困境
互联网的环境
互联网这个环境比较特别,包括现在不只是互联网,就算是被互联网赋能的这些“互联网 +”的企业也在改变,用户在发生变化,用户构成的群体在发生变化,群体造成场景的变化,场景营造新需求,需求养成新用户习惯,新用户习惯造就一批新用户,周而复始。我们一直在追赶用户,但从用户的角度来说,他一直都期望有一个好的产品和一个稳定的服务。相信在座各位既是技术从业者也是普通的用户,大家会发现自己总是想尝试一些新的东西和好的东西。
软件交付的困境
进度不可控: 我们的研发团队会面临一个问题,一些传统的行业也好,或者现在在实行 Sprnit 的团队也好,你会发现研发 进度非常不可控。你有时候感觉一切都很可控,完成任务的时候前 80% 也觉得没问题,一定能交付。但一旦到了后 20%,测试报出海量的 bug,运维问你怎么部署?好多东西还没有定,越来越忙。尤其是上线的晚上,一定要搞一个通宵才能把所有的问题解决。这种复杂的困境是技术不可控的;
流程不可靠: 我们公司总是有各式各样的流程发生,但你会发现这个流程走着走着总是需要有一些 关键角色 蹦出来,必须有一些企业大牛或团队经理站出来说这个事情应该怎样做,或者说今天谁谁没来,这个流程没法往下做。
环境不稳定: 线上怎么就出问题了?测试环境好好的,本地就没问题,是不是因为线上没有按照我说的做?环境这个问题在哪个公司都会遇到。
沟通不顺利: 研发同学跟运维同学在争论,研发同学说上线之后跑脚本,运维跑完了上线出了问题。研发同学就问他“你跑脚本了吗?”他说“跑了”,“是部署前跑的还是部署后跑的?”他说“你没有跟我说这个。”这就是沟通不顺畅,这个本来是可以避免的。
我们需要一种工程手法,让软件在很短的周期内稳定部署上线。 关键词是 “很短” 和 “稳定”,甚至一键部署到任何版本任何环境中,甚至这些操作都在可视化的环境进行。我们在研发团队中说,凡是要定目标做计划,怎么办?我们今天每个人给自己定一个目标:从今天开始每个团队一天部署三次。大家觉得不可能,安排计划 Sprint 两天就够呛了,怎么可能一天上线三次?
举一个真实的例子
汇丰银行在 2014 年的时候全年 release24 次,这个数字相当于 两周有一个 release 的版本,很高效。但是 2018 年全年 release12000 次,这是什么概念?你今天一天 release 几十 次,大家觉得这不可能,开发代码能写完吗?这就是一种思维方式的转变。
如果我们今天说一定要达成这个目标,不管可能不可能,给我一个执行方案和参考的借鉴点。
概念的组合
我们把这个事情分为四个步骤:
第一步 ,自动化的流水线,这是稳定可重复使用的。
第二步 ,支持构建流水线所需要的技术平台和工具。
第三步 ,运行这些平台完成流水线所需要的人和角色。
第四步,支持能够把这些所有东西全部落地并有稳定持续改善方案的文化与规则。
2.DevOps 是什么?
DevOps 在维基百科上的定义
DevOps 是一种重视软件开发人员和 IT 运维技术人员之间沟通合作的文化、运动或惯例,透过自动化软件交付和架构变更的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。
所以前面所有的都是定语,只有最后一句最关键,就是:频繁可靠的发布软件,这就是我们的终极目标。
针对刚才定义的原始阐述,从这个环形图上的工作方式,一直在持续演进,好像看起来没有什么特别的,这个神奇点在哪?
如果你跟别人说你今天看了一篇分享是 DevOps,或者你去搜 DevOps,会发现所包含的含义和相关的含义特别多,包括 精益思想、自动化、持续集成、持续部署、价值流、三步工作法、持续交付、分级部署、敏捷思想、敏捷开发、团队合作。
在我看来这是大家对于美好事物的一种期望,期望 DevOps 能承担更多。即使我们今天不提 DevOps 这个词,把敏捷这个词说出来,你也会说敏捷包含这些部分,换个词也是这样。我认为我们 千万不要陷入于这个词的含义是什么 ,我是想谈 工程化 ,谈 工程化背后美好的东西。
“持续交付”和“DevOps”
我们挑两个特别容易被网上的人或大家所对比的词汇,一个是 持续交付,一个是 DevOps。
持续交付也好,DevOps 也好,他们的共同点是秉持交付思想,他们都崇尚精益思想,他们都喜欢自动化,他们都以快速和稳定的变更为目标,这是两个共同点。持续交付偏向于将不同的过程集中起来,并且更快更频繁地执行这个过程。
虽然我们对比了这两个词,但我希望大家不要过度陷入于概念本身,不是说我今天学的究竟是 DevOps 还是持续交付,这个没有意义。我们要把好的思想带回项目组,带回团队,能不能落地是我们的关注点,我们不要过多对比概念。
基础参与人
凡是涉及人的话题,一定是比较特别的,你只要不把人的范围说清楚,这个事情就别想落地。只要你没说这个事情让他做,他就不会主动问你,如果你主动问你说明这个人是优秀员工。
把敏捷开发单独四个字列出来,持续部署跟持续交付看似范围一样,但持续交付指的是我有交付能力,但我没说一定要部署到线上环境。持续部署讲的是现在既然已经完成了构建的流水线,那么就从头走到尾就结束了,这个讲的是自动化。DevOps 讲的是什么?范围好像一模一样,但 DevOps 不强调每一个角色应该干什么,而是将所有的角色汇集在一起 ,有点像敏捷思想里面的 角色互换,大家谁都能干这个事情,不用指定这个事情,大家可以角色互换一起来做,所以 DevOps 不强调每一个人谁是谁,而是强调这些人汇集到一起之后,你能够将开发编译测试一次性完成,这是他们的区别点。
3.DevOps 工程化
工程化这个词不知道大家怎么理解,你在写代码的时候,我们说你的代码结构好,你的框架设计得好,这其实是一个工程,因为它落地。我们今天谈的 DevOps 工程化也指的这个含义,到现在为止都是一些比较抽象的概念,它是一些比较好的理念,没有具体的落地点,你无法感受到它真正的好。
如果你的团队想要去实施 DevOps,从我的观点来说它由 四部分 组成。
流水线: 流水线一定要自动化,自动化的流水线必须是可靠、可重复、高效的流水线,你的流水线一定要可视化,全程可见,出了问题可以提示你,将你的部署交付给他,完成到哪一步,完成的效果怎么样,我们需要有实时反馈和实时监督。
技术平台和工具: 这个技术平台我列了 容器 和 集群,有人可能说我们公司也做了流水线,也做了自动化,没有用容器做也挺好的。不知道有没有人最近关注国际和国内比较流行的词汇,最近我发现有两种思维比较大,一个是微服务,一个是云原生。
大家知道云原生是什么意思吗?你的服务无论部署在哪一个云服务的提供商上,它都可以正常去跑,这是一个基金会发起的非常好的倡议。你在百度云上做的好好的,可以拿到阿里云、华为云去做,代码一行都不用变。如果你的部署方式基于物理机而不是容器,将来想做云原生就很难,云原生一定是历史趋势,我建议如果想实施,你可以提前往前多走一步,直接到容器化。使用容器有这么几点。一是既然使用容器一定要有标准化,你的容器是怎么构建的,里面包含哪些东西,需要启动的方式是怎样的,需要怎样的运行,这都是需要你自己规划跟设计的。
有了容器就要有私有镜像仓库,往 DockerHub 去推,如果被别人拿下来可能会造成代码泄露的问题,所以我们要搭建私有镜像仓储。再往下要有集群,当前的集群非常多,而且都非常成熟,从今年开始聊 Kubernetes 的人越来越多,因为去年它已经赢得了集群的胜利。自从发表了 1.3,现在有 1.4,马上要发布 1.5,现在越来越强大了,集群这个事情越早越好,我相信有梦想的工程师都想创造出一个 QPS 几十万的服务。当这一瞬间突然来的时候,你的服务能不能扛得住?你的基础设施够不够稳定?这就造成了极大的挑战,这时候就需要集群帮你管理一切。
如果有集群,要提前构想微服务怎么搭,怎么充分利用集群的价值。如果用微服务也好,用集群也好,部署管理怎么做,每一份要怎么布,怎么做熔断机制,怎么做监控报警,怎么做扩容,所有的这些东西都需要自己提前考虑,需要提前想清楚。
人和角色: 主要分两类,开发测试 和 运维。开发跟测试放在一起,因为我认为这两个角色按道理来说是属于一个工种。在谷歌其实是没有测试这个职业的,他们都叫 QA,都是质量控制帮你把控质量。在百度的时候也没有测试的概念,QA 前线大到什么程度?开发了代码就不让你上线,就怀疑有问题,因为我有数据,我发现你的执行速度慢了一毫秒,你将影响我们多少用户?这些用户加到一起是多少小时?你能承担起吗?他们一说我就没话了,承担不起就不上了,不上了老板找谁?因为已经答应了上线。所以开发跟测试一定要搞好关系,我们是一起的,你一定要让我上,你让我上了请你吃饭,我们俩是一家人。这个是玩笑话,这两个角色不要对立,它们是一起的,要共同搭建分支策略。大家一定会听过标准代码分支管理,它们需要共同搭建持续集成。你提交任何一个代码进行持续集成,保证整个代码的质量持续稳定交付,就是需要持续集成作为保证和前提。
文化规则: 讲到团队文化,大家可能会觉得很虚,觉得不切实际,好像离我们很远。
举个例子,一个好的团队文化,尤其是 DevOps 团队或敏捷团队,一定要讲角色的互换。今天你做这件事情,明天可以做另一件事情。我们不是说缺了谁就不能上线,缺了谁公司就没法转,我们应该灵活转变自己。现在有一个非常好的职位叫 DevOps 工程师,什么都能干,甚至 DevOps 工程师要强到什么程度?他需要出来讲课培训 DevOps,有时候客户一咨询,我解答不了,可能 DevOps 工程师写着写着代码就去回答问题了。
说完了整个架构图,我们再从头看一下 流水线的概念。
这是 DevOps 和持续交付里面标准的流水线。
程序编译 – 这个不用多说,无论开发哪个语言,除了脚本语言之外,多数的语言都有编译环节,原文件要编译要编译成另外一种形态才能运行。
单元测试 – 我建议大家有空都要写单元测试,单元测试是非常好的东西,因为你写了单元测试之后就会发现,你跟 QA 的关系会变得非常好,你就没必要麻烦他了。
集成测试 – 每一块独立的东西测试没问题,放到一起之后测能不能正常工作?
性能测试 – 你今天上的东西对于我们现在已经有的东西性能是有提升还是有损耗?
日志测试 – 很多东西表现没问题,但日志中总是报奇怪的错误,有些人意识好,可能会打各种各样的 debug。如果你有了日志分析这一步,一定会发现潜在地方有潜在的漏洞,也许到了线上会变更成严重的问题,这个东西在写单元测试的时候可能考虑不到,我们需要这几步来保证持续集成的正确性。到这为止是持续集成的核心。
镜像 – 将现在所有的东西放到一起,打成最终的镜像,把镜像上传到云端,专业术语叫制品库。
预发布、验收、部署上线 – 验收是预发布环境做回归测试,没有问题就可以直接上线,这个地方可以手动也可以自动,我们只讲流水线不讲到底指持续部署还是持续交付。
实战入门
演示时用到的技术如果大家没有接触过也没关系,一步一步来就好了。
Gitlab、Docker、Kubernetes、Helm、Harbor、Jenkins 这些都是比较标准的,只是入门,我们只是加强这个意识。
首先我们要进行代码分支规范。主干分支切开发分支,完成之后向开发分支提代码,这时候会触发持续集成,验证向分支提交代码是否安全是否对,刚才的东西跑没跑过,跑过要加入代码质量跟代码的 review,没有问题往下走,开发分支结束,我们把东西提交到个人分支上,把代码部署到某一个环境,假如说是测试环境。
这是持续部署的简单示意图
Github 发起通知 Jenkins Job1,Job1 告诉 Job2,在 Job2 中上传镜像,把镜像传到 Helm 里,通过 Kubernetes 部署到 Pod 节点中,完成部署。我们把 Job2 打开,Job2 被触发。为什么我刚才把 Job1 跟 Job2 分开?因为对应的不一样。Job1 对应项目代码,Job2 对应部署代码,我们现在把它们解耦分开,现在 Job2 可以复用,可以构建非常多的项目。
在构建的时候需要制作镜像、上传镜像、部署镜像,每一步都可以用脚本语言实现,通过 Jenkins、file 串联起来,入门的时候做好这块就可以了。
这套流水线能不能用在不同的环境上?可以,要做环境的配置管理,需要你在集群里面做一些操作,在 Kubernetes 的文件里说明这里面需要部署多少的资源,需要使用多少东西。Chart 文件可以帮你辅助,把不同的环境区分开。
讲完了工具讲文化,实施之后进一步落地 DevOps 怎么办?资源管理必不可少,分成几步:监控报警、行为规范、常用脚本、操作指南。每一步都很重要,怎么去监控?监控要注意哪些事项?怎么定义行为规范?脚本很重要,脚本越多越好,能自动化不要手动,多写一些文档,供别人使用,新人文档也好,甚至是操作指南,或者线上文档怎么布,用文档记录下来总没有坏处。
相信一小时之后,你可能就已经忘记我说的是什么了,没关系我不在意,但你一定要记住这张图。
如果你的团队想实施 DevOps,四个因素一定要有:
- 自动化流水线
- 技术平台和工具
- 人和角色
- 文化和规则
这四个一个都不能缺,缺一个都不能叫 DevOps 团队,只能叫感觉还不错的团队。
总结
没有最好的实践,只有最合适的实践,每个公司落地的方案都不尽相同。希望大家在不断探索更好的过程中,找到自己团队适合的 DevOps 解决方案。
认真可以把一件事做对,用心可以把一件事做好。
文章来源:Worktile 敏捷博客
欢迎访问交流更多关于技术及协作的问题。
文章转载请注明出处。