0%

我的DevOps实践经历

项目进入稳定期后,随着日常暴露出来各种的问题,我意识到如何让团队间更高效的协同开发,如何让项目更可靠的交付,是当前阶段比较迫切的需求,于是我尝试在公司中推广并实施DevOps,也取得了一定的成效。

在这里,我想分享下实践过程和一些要点,以便回顾和供他人参考。

发生背景

随着项目进入稳定期后,日常开发充满着‘相似’的问题,比如:

  1. 开发完成后的code review只由leader肉眼检查,难以发现细微的逻辑错误,流于形式。
  2. 新部署项目困难,不利于新启动服务和新成员快速融入。
  3. 项目存在多个版本,不能及时全部更新,使得测试和开发人员花费大量无用功。
  4. 缺乏日志分析和预警,只能被动的等客户反馈来解决问题,错过了最佳的处理时间。

这些问题消磨着大部分日常开发的精力,所以我一直想寻找一个方案来解决,也就是这时了解到DevOps,发现这个理念以及衍生的工具很适合解决团队目前的开发困境。

什么是 DevOps

严格的来说,DevOps只是一种规范,我在这里介绍其中几个关键点的理念,具体更详细的描述可以通过维基百科-DevOpsAWS-什么是 DevOps?了解。

  • 持续集成

    开发人员提交代码后,系统会自动运行构建和测试操作。

  • 持续交付

    当测试通过时,系统可以自动的发布到测试/生产环境,或者执行一系列预发布流程。

  • 监控和日志记录

    监控,采集并分析日志,程序发生故障时可及时响应,同时根据各种指标获取分析有用的用户信息和性能监控。

  • 微服务

    将单个应用程序构建为一系列小服务,它们之间通常是通过HTTP的API接口互相通信。

实践过程

网上关于实践DevOps的文章大多数只提及概念和大体方式上的东西,具体的细节和步骤则避而不谈,缺乏可以借鉴的经验,这带来了一定的困难。

好在平时对这方面感兴趣,阅读了不少相关的文章,根据其中的要点,便有了大致的轮廓。我的初步的设想并不复杂,大致上是以下几点:

  1. 项目的构建可自我描述(别人可通过配置文件来了解具体运作流程),可自动的在不同环境下正确构建和启动。
  2. 分支推入gitlab后,自动触发代码静态分析等任务,只有通过检查的分支才可合并。
  3. 相关分支合并后,可以按照预设的配置自动更新关联的服务。
  4. 有一个统一日志平台,可以接收应用发来的日志,分类分析并存储,异常日志通过邮箱或者集成的服务通知。

这也十分契合大多数人的DevOps实践方式,剩下的就是如何实现了。

调研相关最佳实践&工具

俗话说的好,磨刀不误砍柴工。在正式开始之前,做一些调研还是有必要的。至少需要知道要做成什么样,是否存在最佳实践,相关可用工具有哪些,这即可验证预定设想是否可行,又可了解该用什么工具来实现,事半功倍。

经过一番调研,我决定使用以下工具:

  • 程序构建:Docker,这个并没有过多纠结,Docker确实是容器化领域中独占江山,也有很多实践可以借鉴。
  • CI/CD服务:这部分选择有很多,比如自己搭建的话有gitlab集成的gitlab runner,也有目前很流行的Jenkins,第三方的话,有github的github action,第三方有Travis CIDroneIO等。我这里因为公司使用的是自建的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已经以一个最小方式展现出来了,下一步便是准备好相关文档,向团队间的成员相关的理念,以及能带来什么改变。同时展示已经实现好的流程。

可能团队成员间也对那些问题恼火已久,所以大家都很快接受了这部分理念,一致同意在目前测试环境中试用一下,这也算是达成我的一个小目标了。

总结

在这段经历中,除了思考过去开发的缺陷外,也试着从不同人员的角度去看待问题,我有了以下的体会:

保持沟通

团队间及时的沟通是十分重要的,除了日常开发需求,人员/团队间的协作,及时的沟通可以避免误会和没考虑到的点,更高效的完成任务。还有想做一些性能/架构优化,工具推广等事情,及时的跟上司沟通并获取他们的支持,也是十分重要的,这可以让你获取到相关的资源助力更容易达成目标。

学会灵活应变

软件开发是一件复杂的事,除了技术上的因素,也需要考虑用户的需求,预算,项目间的规划,所以开发过程中充满了取舍,当一些难题难以解决的话,不妨考虑下转变思路,也许问题就迎刃而解了。

从项目初期起保持适度文档和维护构建流程

开发过程中,如果项目紧或者相关人员偷懒,难免会有这样的念头:“先把功能做出来,文档后面再补上”。或者“我们先这样快速做出来,后期我们再改进一下”。实际上这些承诺很可能到后面会有更多的任务/改造成本巨大而无限推迟,有的东西一开始没有的话,后期也很难有。所以我建议团队在一开始就持续的进行维护,这样每次只需要花费一点点精力,但是带来的好处确是巨大的。