项目进入稳定期后,随着日常暴露出来各种的问题,我意识到如何让团队间更高效的协同开发,如何让项目更可靠的交付,是当前阶段比较迫切的需求,于是我尝试在公司中推广并实施DevOps
,也取得了一定的成效。
在这里,我想分享下实践过程和一些要点,以便回顾和供他人参考。
发生背景
随着项目进入稳定期后,日常开发充满着‘相似’的问题,比如:
- 开发完成后的code review只由leader肉眼检查,难以发现细微的逻辑错误,流于形式。
- 新部署项目困难,不利于新启动服务和新成员快速融入。
- 项目存在多个版本,不能及时全部更新,使得测试和开发人员花费大量无用功。
- 缺乏日志分析和预警,只能被动的等客户反馈来解决问题,错过了最佳的处理时间。
这些问题消磨着大部分日常开发的精力,所以我一直想寻找一个方案来解决,也就是这时了解到DevOps
,发现这个理念以及衍生的工具很适合解决团队目前的开发困境。
什么是 DevOps
严格的来说,DevOps
只是一种规范,我在这里介绍其中几个关键点的理念,具体更详细的描述可以通过维基百科-DevOps和AWS-什么是 DevOps?了解。
-
持续集成
开发人员提交代码后,系统会自动运行构建和测试操作。
-
持续交付
当测试通过时,系统可以自动的发布到测试/生产环境,或者执行一系列预发布流程。
-
监控和日志记录
监控,采集并分析日志,程序发生故障时可及时响应,同时根据各种指标获取分析有用的用户信息和性能监控。
-
微服务
将单个应用程序构建为一系列小服务,它们之间通常是通过HTTP的API接口互相通信。
实践过程
网上关于实践DevOps的文章大多数只提及概念和大体方式上的东西,具体的细节和步骤则避而不谈,缺乏可以借鉴的经验,这带来了一定的困难。
好在平时对这方面感兴趣,阅读了不少相关的文章,根据其中的要点,便有了大致的轮廓。我的初步的设想并不复杂,大致上是以下几点:
- 项目的构建可自我描述(别人可通过配置文件来了解具体运作流程),可自动的在不同环境下正确构建和启动。
- 分支推入gitlab后,自动触发代码静态分析等任务,只有通过检查的分支才可合并。
- 相关分支合并后,可以按照预设的配置自动更新关联的服务。
- 有一个统一日志平台,可以接收应用发来的日志,分类分析并存储,异常日志通过邮箱或者集成的服务通知。
这也十分契合大多数人的DevOps
实践方式,剩下的就是如何实现了。
调研相关最佳实践&工具
俗话说的好,磨刀不误砍柴工。在正式开始之前,做一些调研还是有必要的。至少需要知道要做成什么样,是否存在最佳实践,相关可用工具有哪些,这即可验证预定设想是否可行,又可了解该用什么工具来实现,事半功倍。
经过一番调研,我决定使用以下工具:
- 程序构建:
Docker
,这个并没有过多纠结,Docker
确实是容器化领域中独占江山,也有很多实践可以借鉴。 - CI/CD服务:这部分选择有很多,比如自己搭建的话有gitlab集成的
gitlab runner
,也有目前很流行的Jenkins
,第三方的话,有github的github action
,第三方有Travis CI
,DroneIO
等。我这里因为公司使用的是自建的gitlab
,所以选择了gitlab runner
,如果不是使用的不是gitlab
的话,建议选择Jenkins
。 - 日志服务:
ELK
,Sentry
。 这里确实调研了比较长的时间,最后初步决定是尝试下ELK
作为日志分析和汇总,但是ELK
中预警功能是收费组件里的,所以选择Sentry
作为备用方案。
将程序通过Docker构建
Docker
最吸引我的地方就是它可以保持跨环境的一致性,也可以通过docker compose
来运行一组服务,同时通过Dockerfile
来构建的方式也隐约达到了我的程序可自我描述需求。
简单的学习Docker
并不难,但我在尝试应用在项目中花费了相当多的精力。
因为Docker
是自动化构建,也就意味着项目本身要执行相关命令/脚本,程序便可自行构建,而当前项目在手动部署都十分困难。于是需要做大量的梳理,改造。比如编写脚本处理项目的依赖项,梳理项目相关初期配置(同时记录整理到文档到内网),优化部分不灵活的代码。
除此外还有许多难点,部分应用的框架源码是定制修改的,打包出来的基础镜像不可推入Dockerhub
,使得移植困难。同时项目换成Docker
部署后,如何兼容当前项目的配置,降低成员间的学习成本,也是个难题。
项目依赖到的服务或者额外进程,比如,Postgresql
, Reids
等,则通过docker compose
方式来启动,并调整程序自动连入相关服务。
这改造过程中,花费的更多精力其实是为过去的野蛮开发方式买单,过去开发过程中各管各的,忽略了在整体上的协调和相关测试工具,使得早期存在的问题在此刻都爆发出来。如果一开始注重这部分并持续维护,会顺利很多。
加入CI/CD服务 (持续集成/持续交付)
把项目改造成通过Docker
构建后,接下来的主要问题就是如何实现CI/CD了。这部分顾名思义就是将把我们日常重复执行的一些更新操作,通过配置的方式,让工具自动执行。
通过gitlab runner
的配置文件,便可把任务分解成几个阶段,首先是静态代码检查阶段
,这里通过flake8
来检查代码。其次是单元测试阶段
,这部分会跑写好的单元测试。当一些列检查都通过时,执行部署阶段
,这里会自动更新测试环境中相关服务。
日志分析
日志是应用开发的很重要的一环,因为当程序上线运行后无法单步调试的,所以当线上发生异常时,日志是很重要的参考依据,良好的日志让问题更顺利的定位和解决。
由于ELK
服务已经是相对完善的工具,所以集成起来并不困难,但是还是很快碰到了难题:日志的解析。
因为项目中使用到了不同的框架,因为不同框架间输出的日志格式不同,会造成采集到的数据不同,会给统计和分析带来一定困扰。 针对这部分,我做法是提议在团队间规范一个日志格式来方便处理。
最后则是预警部分,鉴于ELK
这部分功能是收费的,而Sentry
有免费额度,所以我决定尝试Sentry
作为日志预警的试验。
团队间介绍,展示
经过上述三个改造点后,我设想的DevOps
已经以一个最小方式展现出来了,下一步便是准备好相关文档,向团队间的成员相关的理念,以及能带来什么改变。同时展示已经实现好的流程。
可能团队成员间也对那些问题恼火已久,所以大家都很快接受了这部分理念,一致同意在目前测试环境中试用一下,这也算是达成我的一个小目标了。
总结
在这段经历中,除了思考过去开发的缺陷外,也试着从不同人员的角度去看待问题,我有了以下的体会:
保持沟通
团队间及时的沟通是十分重要的,除了日常开发需求,人员/团队间的协作,及时的沟通可以避免误会和没考虑到的点,更高效的完成任务。还有想做一些性能/架构优化,工具推广等事情,及时的跟上司沟通并获取他们的支持,也是十分重要的,这可以让你获取到相关的资源助力更容易达成目标。
学会灵活应变
软件开发是一件复杂的事,除了技术上的因素,也需要考虑用户的需求,预算,项目间的规划,所以开发过程中充满了取舍,当一些难题难以解决的话,不妨考虑下转变思路,也许问题就迎刃而解了。
从项目初期起保持适度文档和维护构建流程
开发过程中,如果项目紧或者相关人员偷懒,难免会有这样的念头:“先把功能做出来,文档后面再补上”。或者“我们先这样快速做出来,后期我们再改进一下”。实际上这些承诺很可能到后面会有更多的任务/改造成本巨大而无限推迟,有的东西一开始没有的话,后期也很难有。所以我建议团队在一开始就持续的进行维护,这样每次只需要花费一点点精力,但是带来的好处确是巨大的。