持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。
前言
传统的开发过程中的坑:
- BUG 总是在最后发现
- 越到项目后期,加班越严重
- 交付无法保障
- 变更频繁导致效率低下
- 无效的等待多,用户满足度低

CI/CD的优势:
- 不用为开发/测试环境不一致而苦恼
- 不用麻烦运维人员帮忙调试环境
- 不用手动进行测试,模拟环境中进行自测
- 不用手动发布、部署,自动化实现发布部署
- 不用管开发/测试环境,专注代码的开发
CI/CD 解决了什么问题?
- 提高软件质量
- 效率迭代
- 便捷部署
- 快速交付
- 便于管理
课程的主要内容:
- 什么是 CI/CD
- 介绍 CI/CD 流程
- 前端项目: 结合CI/CD流程,实现快速迭代
- Dockers 的使用,Jenkins+ gitlab+nodes 自动化项目
- 持续集成工具介绍:Jenkins、Travis CI、Circle CI
环境准备:
- Linux 服务器(Centos7.6/ Ubuntu16.04LTS)
- Vscode+插件 Dockerfile
- 注册 github 账号
持续集成
核心概念
集成,就是一些孤立的事物或元素通过某种方式集中在一起,产生联系,从而构成一个有机整体的过程。在软件行业中,集成并不是一个简单的“搬箱子“的过程。因为软件工业是一个知识生产活动,其内在逻辑非常复杂,需求又很难一次性确定,完成的产品与最初的设计往往相差很远。敏捷宣言中就有一条是说响应变化重于遵循计划。而且由于软件行业的迅猛发展,软件变的越来越复杂,单靠个人是根本无法完成。大型软件为了重用及解耦,往往还需要分成好几个模块,这样集成就成了软件开发中不可或缺的一部分。
持续就是指长期的对项目代码进行集成。
持续集成
持续集成(英文:Continuous Integration,简称 CI)。
在软件工程中,持续集成是指将所有开发者工作副本每天多次合并到主干的做法。
Grady Booch 在 1991 年的 Booch method 中首次命名并提出了 CI 的概念,尽管在当时他并不主张每天多次集成。而 XP (Extreme programming,极限编程)采用了 C 的概念,并提倡每天不止一次集成。
在《持续集成》一书中,对持续集成的定义如下:持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。自从在团队中引入这样的实践之后,Martin Fowler 发现这种方法可以显著减少集成引起的问题,并可以加快团队合作软件开发的速度。

持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。
对于一天需要集成多少次数,并没有一个明确的定义。一般就是按照自己项目的需要来设置一定的频率,少则可能几次,多则可能达几十次。可以设置按照代码的变更来触发集成,或者设置一个固定时间周期来集成,也可以手工点击集成的按钮来“一键集成”。
持续交付
持续交付(英文:Continuous Delivery,简称 CD)。
完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。为了实现高效的持续交付流程,务必要确保已内置于开发管道。持续交付的目标是拥有一个可随时部署到生产环境的代码库。

在持续交付中,每个阶段(从代码更改的合并,到生产就绪型构建版本的交付)都涉及测试自动化和代码发布自动化。在流程结束运维团队可以快速、轻松地将应用部署到生产环境中。
比如,我们完成单元测试后,可以把代码部署到连接数据库的 Staging 环境中测试。如果代码没有问题,可继续手动部署到生产环境中。
持续部署
持续部署(英文:Continuous Deployment,简称 CD)。
对于一个成熟的 CI/CD 管道来说,最后的阶段是持续部署。作为持续交付ー一自动将生产就绪型构建版本发布到代码存储库的延伸,持续部署可以自动将应用发布到生产环境。由于在生产之前的管道阶段没有手动门控,因此持续部署在很大程度上都得依赖精心设计的测试自动化。

实际上,持续部署意味着开发人员对应用的更改在编写后的几分钟内就能生效(假设它通过了自动化测试)。这更加便于持续接收和整合用户反馈。总而言之,所有这些CI/CD的关联步骤都有助于降低应用的部署风险,因此更便于以小件的方式(而非一次性)发布对应用的更改。不过,由于还需要编写自动化测试以适应 CICD 管道中的各种测试和发布阶段,因此前期投资还是会很大。
持续部署则是在持续交付的基础上,把部署到生产环境的过程自动化。
持续集成组成要素
一个最小化的持续集成系统需要包含以下几个要素:
- 版本管理系统:项目的源代码要托管到适合的版本管理系统中,一般我们使用 git 作为版本控制库,版本管理软件可以使用 github、gitlab、stash 等。
- 构建脚本和工具:每个项目都需要有构建脚本来实现对整个项目的自动化构建。比如 Java 的项目就可以使用 gradle 作为构建工具。通过构建工具实现对编译、静态扫描、运行测试、样式检查、打包、发布等活动串起来,可以通过命令行自动执行。
- CI 服务器:服务器可以检测项目中的代码变动,并及时的通过构建机器运行构建脚本,并将集成结果通过某种方式反惯给团队成员。
应用场景
- 打包平台:常见的打包,Java 应用(Gradle/ Maven)、Nodejs 应用(npm/yarn) 、移动端打包: (Android/iOS) 。
- 测试平台:接口测试、自动化测试(Robotium、Testlink)、单元测试(Junit)、性能测试(Jmeter)。
- 自动部署:FTP、Shell、Tomcat/Dokcer、Kubernetes/Rancher/Cluster。
- 持续集成:Git(gitlab、github、gitee)、Jenkins/TravisCI/CircleCI、Docker。
工作流
传统的工作流
参与人员:开发、项目经理、测试。
主要流程:
- 项目一开始先划分好模块,分配模块给相应的开发人员;
- 开发人员开发好一个模块就进行单元测试;
- 等所有的模块都开发完成之后,由项目经理对所有代码进行集成;
- 集成后的项目由项目经理部署到测试服务器上,被交由测试人员进行集成测试;
- 测试过程中出现 Bug 就提把问题记录在 Bug 列表中;
- 项目经理分配 Bug 给相应的责任人进行修改;
- 修改完成后,项目经理再次对项目进行集成,并部署到测试服务器上;
- 测试人员在下一次的集成测试中进行回归测试;
- 通过之后就部署到生产环境中;
- 如果测试不通过,则重复上述“分配 Bug→修改 Bug→集成代码部署到测试服务器上→集成测试”工作。
这也是传统的瀑布式开发模式。
带来的问题:
- 重复性劳动,无效的等待变多
重复的进行发布部署。
流程上:有可能开发在等集成其他人的模块;测试人员在等待开发人员修复 Bug;产品经理在等待新版本上线好给客户做演示;项目经理在等待其他人提交代码。不管怎么样,等待意味低效。
自动化部署工作可以解放了集成、测试、部署等重复性劳动,而且机器集成的频率明显可以比手工的高很多。
- 很晚才发现缺陷,且难以修复
实践证明,缺陷发现的越晚,需要修复的时间和精力也就越大。从上个可工作的软件到发现缺陷之间可能存在很多次提交,而要从这些提交中找出问题井修复的成本会很大,因为开发人员需要回忆每个提交的上下文来评估影响点。
- 低品质的软件,软件交付时机无法保障
由于集成时每次包含的代码很多,所以大家的关注点主要都是如何保证编译通过、自动化测试通过,而往往很容易忽略代码是否遵守了编码规范、是否包含有重复代码、是否有重构的空间等问题。而这些问题又反过来会影响今后的开发和集成,久而久之集成变得越来越困难,软件的质量可想而知。
- 项目缺少可见性
某些项目,程序会经常需要变更,特别是敏捷开发的实践者。由于产品经理在与客户交流过程中,往往实际的软件就是最好的原型,所以软件会被当作原型作为跟客户交流的工具。当然,客户最希望的当然是客户的想法能够马上反映到原型上,这会导致程序会经常被修改的。那么也就着“分配 Bug → 修改 Bug → 集成代码 → 部署到测试服务器上 → 集成测试”工作无形又爆增了。
常见工作流
DevOps

该系统的各个组成部分是按如下顺序来发挥作用的:
- 开发者检入代码到源代码仓库。
- CI 系统会为每一个项目创建了一个单独的工作区(沙盒)。当预设或请求一次新的构建时,它将把源代码仓库的源码存放到对应的工作区。
- 系统会在对应的工作区内执行构建过程。
- 配置如果不存在:构建完成后,系统会在一个新的构建中执行定义的一套测试。完成后发通知(Email, RSS 等等)给相关的当事人。
- 配置如果存在:如果构建成功,这个构建会被打包并转移到一个部署目标(如应用服务器)或存储为软件仓库中的一个新版本。软件仓库可以是系统的一部分,也可以是一个外部的仓库,诸如一个文件服务器或者像 Java.net、Sourceforge 之类的网站。
- CI 系统通常会根据请求发起相应的操作,诸如即时构建、生成报告,或者检索一些构建好的构建。
解决的问题
- 高效率
高效率的发布,避免了重复性的劳动;更快的修复 BUG,更快的交付成果,少了等待时间。
- 高质量
只有在完成集成测试、系统测试后,才能得到可用的软件,整个过程中只有最后时刻才能拿到可运行软件。如果集成活动不在一个标准的构建机器上生成,而是在某个开发入员的机器上构建的,那么可能存在在其他机器上无法运行的问题。
- 高产出
快速开发和上市一个新产品,并快速取得预期的投资回报是每个企业孜孜以求的目标。便捷的部署+项目的可预期,使得团队的开发变成了一种开心的事情。
持续集成可以让你在任何时间发布可以部署的软件。在外界看来,这是持集成最明显的好处,对客户来说,可以部署的软件产品是最实际的资产。利用持续集成,你可以经常对源代码进行一些小改动,并将这些改动和其他代码进行集成。
常见问题
- 思维转变后,新技术抵触
无法接受新事物:不管怎么样,求稳心态的人还是多。总是有人认为老的技术代表稳定,新的事物往往会带来问题。
认为手工集成也没有多少工作量:不是所有的人都参与到了整个持续集成的环节,所以没有办法认识到问题全貌。
针对这个问题,可以通过设置一定的持续集成技术培训、宣讲得到改观。
- 管理层的抵触
培训持续集成需要投入资金。持续集成服务器要增加软硬件成本。
针对这一点,可以从开发人员的成本和持续集成的投入(软硬件)的成本两者做下估算。
- 生产环境的复杂
比如部署的生成环境是在内网,无法从互联网直接访问等。
最佳实践
实施持续集成的开发人员可以尽早并经常提交代码,这允许他们尽早发现冲突。并且,如果存在任何问题,使用较小的提交可以更轻松地对代码进行故障排除。每天或甚至更频繁地提交对于持续集成是必要的,但还不够。要成功使用持续集成,团队必须:
- 使测试成为开发过程中不可或缺的一部分。应该在创建代码时编写测试。
公司成功持续集成所需的最重要因素是严格的测试文化。为了将新代码自信地集成到主线中,团队需要确信代码是健全的。这是通过测试来实现的,这应该定期进行。工程师应该在开发每个功能时编写测试用例。
- 确保测试环境与生产环境一致。
为了支持您严格的测试文化,测试环境必须反映生产环境。否则,您无法保证您正在测试的内容将在生产中运行良好。这意味着测试环境应使用相同版本的数据库、Web 服务器配置、工件等。
- 使用编码最佳实践,例如结对编程。
软件开发的另一个最佳实践是在编码期间进行结对编程。对于更复杂的功能,团队在编写单行代码之前讨论体系结构方法。在将任何代码合并到生产环境之前,其他开发人员始终会检查代码。这有助于确保使用编码最佳实践,代码不会与其他开发人员正在处理的现有代码发生冲突,并且新功能是可扩展的。
- 自动化部署工作流程。
为确保软件开发流程快速高效,构建需要快速,部署工作流程应该自动化。通过自动化部署工作流程,团队可以更快地生成代码。
效率工具对比
Jenkins
Jenkins,原名 Hudson,2011 年改为现在的名字,它是一个开源的实现持续集成的软件工具。Jenkins 能实时监控集成中存在的错误,提供详细的日志文件和提醒功能,还能用图表的形式形象地展示项构建的趋势和稳定性。
Jenkins 特点:
- 易安装:Jenkins 是一个独立的基于 Java 的程序,随时可以运行,包含 Windows, MacOSX 和其他类 Unix 操作系统的软件包。仅仅一个 java -jar jenkins.war,从官网下载该文件后,直接运行,无需额外的安装,更无需安装数据库。
- 易配置:提供友好的 GUI 配置界面。
- 变更支持:Jenkins 能从代码仓库中获取并产生代码更新列表并输出到编译输出信息中。
- 支持永久链接:用户是通过 web 来访问 Jenkins 的,而这些 Web 页面的链接地址都是永久链接地址,因此,你可以在各种文档中直接使用该链接。
- 集成EMail/RSS/IM:当完成一次集成时,可通过这些工具实时告诉你集成结果。
- Junit/ TESTNG 测试报告:以图表等形式提供详细的测试报表功能。
- 支持分布式构建:Jenkins 可以把集成构建等工作分发到多台计算机中完成。
- 文件指纹信息:Jenkins 会保存哪次集成构建产生了哪些 jars 文件,哪一次集成构建使用了哪个版本的 jars 文件等构建记录;
- 支持第三方插件:使得 Jenkins 变得越来越强大;凭借更新中心中的数百个插件,Jenkins 几乎集成了持续集成和持续交付工具链中的所有工具。
- Rest APl:可以访问控制您获取的数据量、获取/更新 config.xml、删除作业、检索所有构建、获取/更新作业说明、执行构建、禁用/启用作业等。
Jenkins 优点:价格(免费)、定制、插件系统、完全控制系统。
Jenkins 缺点:需要专用服务器(或多个服务器),这导致额外的费用;配置/定制所需的时间。
Travis CI
Travis CI 是一个托管的持续集成服务,用于构建和测试在 Github 上托管的软件项目。
Travis CI 的特点:
- 基于云:TravisCl 是一个基于云的系统,不需要专用服务器,您无需管理它。
- 支持 Docker 运行测试。
- 使用 YAML 文件进行配置。
- 可选择 Linux 和 Mac OSX 上同时运行测试。
- 开箱即用的支持的语言。
- 支持多环境构建矩阵。
构建矩阵是一种工具,可以使用不同版本的语言和包运行测试。您可以以不同的方式自定义它。例如,某些环境的失败可以触发通知但不会使所有构建失败(这对包的开发版本有帮助)。
Travis CI 优点:开箱即用构建矩阵、快速启动、轻量级 YAML 配置、开源项目的免费计划、无需专用服务器。
Travis CI 缺点:与 CircleCI 相比,价格更高,没有免费的企业计划、定制。
Circle CI
在 Github 或 Bitbucket 上的软件存储库被授权并作为项目添加到 circleCI 之后,每个代码更改都会在干净的容器或 VM 中触发自动化测试。
Circle Cll 的特点:
- 云&本地化:CircleCI 是一个基于云的系统,不需要专用服务器,您无需管理它。但是,它还提供了一个本地解决方案,允许您在私有云或数据中心中运行它。
- 商业&免费:即使是商业帐户,它也有免费计划。
- Rest API:您可以访问项目,构建和工件(artifacts)。构建的结果将是工件或工件组。工件可以是已编译的应用程序或可执行文件(例如,android APK)或元数据(例如,关于测试成功的信息)。
- 按需安装:CircleCI 缓存必要的安装(requirements installation)。它会检查第三方依赖项,而不是持续安装所需的环境。
- SSH 模式:您可以触发 SSH 模式访问容器并进行自己的调查(如果出现任何问题)。
- 最小化配置:这是一个完整的开箱即用解决方案,需要最少的配置调整。
Circled 优点:快速启动、有一个免费的企业项目计划、轻量级,易读的 YAML 配置、不需要任何专用服务器来运行。
