在传统的开发模式下,开发、运维、物理机三者之间的关系是非常紧密的。当开发完成项目后,运维会负责把项目部署到一台物理机上,由这台物理机向外提供服务。
由于服务和物理机关系紧密,导致服务非常依赖于物理机的环境。一旦需要调换物理机器,运维同事又需要在另一台物理机上安装服务依赖的环境,经过一顿折腾后,才能完成服务的部署。
为了解决这个问题,出现了一种名为虚拟机的操作系统虚拟化产品。不过还发展没有太久,就已经被一种更轻量级的操作系统容器化产品替代了,它就是Docker。
运用Docker容器技术,运维可以把服务依赖的环境资源都编入 Image 中,然后把服务运行在 Container 上,实现服务与物理机的解耦。开发人员也可以将运维的工作以可编程的方式编入 Dockerfile 文件中,从此打破了开发和运维之间的壁垒,大大降低了部署成本。
敏捷开发把一个产品交付过程拆分为了多个小周期,创新性的通过不断重复迭代的方式,实现产品的逐步改进和提前交付。从此改变了以往瀑布流模式下的大周期开发问题,可以提前了解市场需求,规避风险。
正是在基于容器、敏捷开发、j9九游会老哥俱乐部appCI/CD 等各种前瞻技术思想的发展下,催生了一场名为 Devops 的文化运动。在这场文化运动中,更加强调加强开发、测试、运维之间的沟通。现在已经越来越多的公司或团队开始重视和投入到 Devops 的建设中,基于 CI/CD 构建服务端的自动化,让整个开发模式高效高质量的同时,也更加流程化、规范化。
从上可以发现,随着技术发展,RD 与测试、运维之间的不再是泾渭分明的工作线,反而他们之间的关系愈加紧密,RD 的整个开发模式也开始向自动化方向演进。
在目前的实际工作中,遇到了一系列影响效率和质量的问题。虽然目前有现成的 CI/CD 机制可以使用,但它的接入成本较高且不易扩展。
所以开始尝试运用 Devops 思想并结合 CI/CD 技术,创建一个基于CI的服务端自动化,把项目的开发、单测、集测、部署、检测、监控等整个完整的项目流程,都闭环集成至这个自动化中,实现更加快速高效高质量地交付产品。
经过一段时间的实践,效果很好,验证了想法的正确性,故总结和分享此文章,为大家提供思路与经验。
本文会以 CI/CD 技术为核心,重点介绍它能为我们带来什么,我们为什么要设计自己的CI服务端自动化,以及如何设计。
在瀑布流开发模式下,一个项目的周期是足够长的,一般有充足的时间来完成整个项目流程。但在敏捷开发模式下,开发内容的缩减,伴随而来的也是需求、测试等环节时间的缩减,导致迭代速度也越来越快。
举例 :今天需要开发一个功能,但可能不经过测试,产品验收后就可以上线。
市面上流行的各种第三方工具大都非常重,功能繁多,依赖复杂,甚至还都会附带一个后台管理系统。导致很多时候我们只需要某个工具10%的功能,但不得不接受它90%附加的功能,这类重型工具只适合稳定发展的项目。
对于快速迭代的项目,需要的是轻量、轻量、还是轻量!
举例 :接口文档自动生成工具中,大部分都需要私有服务器部署而且会附有各种管理系统。
在传统项目流程中,测试一直是时间分配最少的环节,再加上多端测试、Bug验证以及整体回归,导致测试时间不足的问题很常见也很难避免。
举例 :QA在验某个功能时发现一直有问题,由于RD没有写单元测试,较久后才排查出原因,导致QA测试时间更加紧张
在上面已经说道,敏捷开发下的节奏整体是非常快的。对于RD而言,无论是需要 QA、OP、还是 SRE 等任何一方的需求,满足速度虽然可能不慢,但还是不能支持敏捷开发下迭代的速度。
举例1 :某个业务接口需要自动化测试支持,但 QA 可能需要排期才能完成
举例2 :后端服务上线时可能由于配置缺少等问题发生 panic,需要 SRE 在 CI 中新增配置检查,但需要排期才能完成
在面对以上种种问题下,如果没有一个完整健全的机制,是难以轻松应对敏捷开发这种快迭代速度的,交付质量也会大打折扣。
所以为了解决这个问题,我们开始运用 Devops 思想,基于 CI 来建立一套完整的、覆盖广的服务端自动化,打破不同部门之间的壁垒,适应快速迭代,满足质量要求。
在设计之初,最主要的目标就是轻量化 。轻量绝不代表着不完整或不成熟,反而是省去了所有的细枝末节后,用一种更少的成本,更快速的满足实现了我们的需求。 所以在整个设计中,都会贯穿轻量化的思想。
在微服务架构下,一套代码被划分到多个代码库中,多个代码库下都有自己的 CI 代码,一旦 CI 中任意一个流程有变动,那么所有项目都需要配合修改,造成的整体联动调整过大。
为了解决这个问题,采用了如下多项目共用的设计。在这个设计中,不需要再把 CI 运行逻辑写在 gitlab-ci.yml 文件中了,而是写在 CommonCI 这样的仓库中,并由 start.sh 脚本启动。
基于插拔式扩展的思想,所有的任务也都是可插拔、易扩展且完全可控的,还可以实现多任务的编排。
在运行过程中,虽然 gitlab CI 提供了如 cache 和 artifacts 这样的中间产物功能,但它们会有很多限制,有时候可能无法良好满足。所以会设计自己的第三方 Cache 库,用来存放已经编译好的二进制文件,加快 CI 的执行时间。
基于 CI 建立的服务端自动化架构如下所示,它一共分为三层 :
从上图架构中的代码仓库层可知,除了业务代码仓库外,还有通用代码仓库,其中最重要的就是我们设计的 CommonCI 仓库。CommonCI仓库是解决多项目 CI 共用的核心实现,它的目录结构如下所示。
详情请见源代码 .gitlab/apidoc_gen.sh
在执行 CI 前,可能需要大量的安装操作,我们都放在了 .gitlab/pre_install.sh 预安装脚本中。
详情请见源代码 .gitlab/check_code.sh
一般情况下,对于代码检查工具的使用,不仅仅是为了规范代码,更多更强烈的需求是希望它能尽可能的帮助我们检查出大部分的代码错误。
通过代码扫描、词法/语法分析、控制流分析等技术实现程序的静态分析,甚至还可以针对我们的业务做定制化的 Bug 分析。
所以我们在 CI 中添加了 golangci-lint 代码检查工具,让RD可以更加放心的提交代码。
如以下代码是在业务中比较常见且易犯的错误,基于定制化 Bug 分析的这种场景需求,还可以开发更加轻量的内部代码检查工具,它可以简单的分析识别出以下语法错误。