CI/CD
15.3 CI/CD
什么是CI?
CI的英文名称是Continuous Integration,中文翻译为:持续集成。

CI中,开发人员将会频繁地向主干提交代码,这些新提交的代码在最终合并到主干前,需要经过编译和自动化测试流进行验证。 持续集成(CI)是在源代码变更后自动检测、拉取、构建和(在大多数情况下)进行单元测试的过程。持续集成的目标是快速确保开发人员新提交的变更是好的,并且适合在代码库中进一步使用。CI的流程执行和理论实践让我们可以确定新代码和原有代码能否正确地集成在一起。
通俗点讲就是:通过持续集成, 开发人员能够在任何时候多次向仓库提交作品,而不是独立地开发每个功能模块并在开发周期结束时一一提交。这里的一个重要思想就是让开发人员更快更、频繁地做到这一点,从而降低集成的开销。 实际情况中,开发人员在集成时经常会发现新代码和已有代码存在冲突。 如果集成较早并更加频繁,那么冲突将更容易解决且执行成本更低。当然,这里也有一些权衡,这个流程不提供额外的质量保障。 事实上,许多组织发现这样的集成方式开销更大,因为它们依赖人工确保新代码不会引起新的 bug 或者破坏现有代码。 为了减少集成期间的摩擦,持续集成依赖于测试套件和自动化测试。 然而,要认识到自动化测试和持续测试是完全不同的这一点很重要。
CI 的目标是将集成简化成一个简单、易于重复的日常开发任务, 这样有助于降低总体的构建成本并在开发周期的早期发现缺陷。 要想有效地使用 CI 必须转变开发团队的习惯,要鼓励频繁迭代构建, 并且在发现 bug 的早期积极解决。
什么是CD?
这里的CD可对应多个英文名称,持续交付Continuous Delivery和持续部署Continuous Deployment。下面我们分别来看看上面是持续交付和持续部署。
- 持续交付
持续交付(CD)实际上是 CI 的扩展,其中软件交付流程进一步自动化,以便随时轻松地部署到生成环境中。 成熟的持续交付方案也展示了一个始终可部署的代码库。使用 CD 后,软件发布将成为一个没有任何紧张感的例行事件。 开发团队可以在日常开发的任何时间进行产品级的发布,而不需要详细的发布方案或者特殊的后期测试。
完成 CI 中构建及单元测试和集成测试的自动化流程后,持续交付可自动将已验证的代码发布到存储库。为了实现高效的持续交付流程,务必要确保 CI 已内置于开发管道。持续交付的目标是拥有一个可随时部署到生产环境的代码库。

在持续交付中,每个阶段(从代码更改的合并,到生产就绪型构建版本的交付)都涉及测试自动化和代码发布自动化。在流程结束时,运维团队可以快速、轻松地将应用部署到生产环境中或发布给最终使用的用户。
CD 集中依赖于部署流水线,团队通过流水线自动化测试和部署过程。此流水线是一个自动化系统, 可以针对构建执行一组渐进的测试套件。CD 具有高度的自动化,并且在一些云计算环境中也易于配置。在流水线的每个阶段,如果构建无法通过关键测试会向团队发出警报。否则,将继续进入下一个测试, 并在连续通过测试后自动进入下一个阶段。流水线的最后一个部分会将构建部署到和生产环境等效的环境中。 这是一个整体的过程,因为构建、部署和环境都是一起执行和测试的,它能让构建在实际的生产环境可部署和可验证。
- 持续部署
持续部署扩展了持续交付,以便软件构建在通过所有测试时自动部署。在这样的流程中, 不需要人为决定何时及如何投入生产环境。CI/CD 系统的最后一步将在构建后的组件/包退出流水线时自动部署。 此类自动部署可以配置为快速向客户分发组件、功能模块或修复补丁,并准确说明当前提供的内容。采用持续部署的组织可以将新功能快速传递给用户,得到用户对于新版本的快速反馈,并且可以迅速处理任何明显的缺陷。 用户对无用或者误解需求的功能的快速反馈有助于团队规划投入,避免将精力集中于不容易产生回报的地方。
随着 DevOps 的发展,新的用来实现 CI/CD 流水线的自动化工具也在不断涌现。这些工具通常能与各种开发工具配合, 包括像 GitHub 这样的代码仓库和 Jira 这样的 bug 跟踪工具。此外,随着 SaaS 这种交付方式变得更受欢迎, 许多工具都可以在现代开发人员运行应用程序的云环境中运行,例如 GCP 和 AWS。但是对于一个成熟的CI/CD管道(Pipeline)来说,最后的阶段是持续部署。作为持续交付——自动将生产就绪型构建版本发布到代码存储库——的延伸,持续部署可以自动将应用发布到生产环境。

什么是CI/CD的管道?
CI / CD管道是与自动化工具和改进的工作流程集成的部署管道。 如果执行得当,它将最大程度地减少人为错误,并增强整个SDLC的反馈循环,使团队可以在更短的时间内交付较小的发行版。

典型的CI / CD管道必须包括以下阶段:
- 构建阶段
- 测试阶段
- 部署阶段
- 自动化测试阶段
- 部署到生产
如何理解DevOPS?
DevOps是Development和Operations的组合,是一种方法论,是一组过程、方法与系统的统称,用于促进应用开发、应用运维和质量保障(QA)部门之间的沟通、协作与整合。以期打破传统开发和运营之间的壁垒和鸿沟。
CI、CD和DevOps之间的关系 :

在完全部署到所有用户之前,有哪些方法可以测试部署?
由于必须回滚/撤消对所有用户的部署可能是一种代价高昂的情况(无论是技术上还是用户的感知),已经有许多技术允许“尝试”部署新功能并在发现问题时轻松“撤消”它们。这些包括:
- 蓝/绿测试/部署
在这种部署软件的方法中,维护了两个相同的主机环境 —— 一个“蓝色” 和一个“绿色”。(颜色并不重要,仅作为标识。)对应来说,其中一个是“生产环境”,另一个是“预发布环境”。
在这些实例的前面是调度系统,它们充当产品或应用程序的客户“网关”。通过将调度系统指向蓝色或绿色实例,可以将客户流量引流到期望的部署环境。通过这种方式,切换指向哪个部署实例(蓝色或绿色)对用户来说是快速,简单和透明的。
当新版本准备好进行测试时,可以将其部署到非生产环境中。在经过测试和批准后,可以更改调度系统设置以将传入的线上流量指向它(因此它将成为新的生产站点)。现在,曾作为生产环境实例可供下一次候选发布使用。
同理,如果在最新部署中发现问题并且之前的生产实例仍然可用,则简单的更改可以将客户流量引流回到之前的生产实例 —— 有效地将问题实例“下线”并且回滚到以前的版本。然后有问题的新实例可以在其它区域中修复。
- 金丝雀测试/部署
在某些情况下,通过蓝/绿发布切换整个部署可能不可行或不是期望的那样。另一种方法是为金丝雀测试/部署。在这种模型中,一部分客户流量被重新引流到新的版本部署中。例如,新版本的搜索服务可以与当前服务的生产版本一起部署。然后,可以将 10% 的搜索查询引流到新版本,以在生产环境中对其进行测试。
如果服务那些流量的新版本没问题,那么可能会有更多的流量会被逐渐引流过去。如果仍然没有问题出现,那么随着时间的推移,可以对新版本增量部署,直到 100% 的流量都调度到新版本。这有效地“更替”了以前版本的服务,并让新版本对所有客户生效。
- 功能开关
对于可能需要轻松关掉的新功能(如果发现问题),开发人员可以添加功能开关。这是代码中的 if-then 软件功能开关,仅在设置数据值时才激活新代码。此数据值可以是全局可访问的位置,部署的应用程序将检查该位置是否应执行新代码。如果设置了数据值,则执行代码;如果没有,则不执行。
这为开发人员提供了一个远程“终止开关”,以便在部署到生产环境后发现问题时关闭新功能。
- 暗箱发布
在暗箱发布中,代码被逐步测试/部署到生产环境中,但是用户不会看到更改(因此名称中有暗箱一词)。例如,在生产版本中,网页查询的某些部分可能会重定向到查询新数据源的服务。开发人员可收集此信息进行分析,而不会将有关接口,事务或结果的任何信息暴露给用户。
这个想法是想获取候选版本在生产环境负载下如何执行的真实信息,而不会影响用户或改变他们的经验。随着时间的推移,可以调度更多负载,直到遇到问题或认为新功能已准备好供所有人使用。实际上功能开关标志可用于这种暗箱发布机制。
什么是持续测试?
持续测试是一个过程,它将自动化测试作为软件交付通道中内嵌的一部分,以尽快获得软件发布后业务风险的反馈。
持续测试与自动化测试的侧重点?
- 自动化测试旨在生成一组与用户故事或应用程序要求相关的通过/失败的数据点。
- 持续测试侧重于业务风险,并提供有关软件是否可以发布的判断。要实现这一转变,我们需要停止询问“我们是否已完成测试?”而是集中精力在“发布版本是否具有可接受的业务风险级别?”
为什么我们需要持续测试?
今天,整个行业的变化要求测试更多,同时使自动化测试更难实现(至少使用传统工具和方法):
- 应用程序体系结构越来越分散和复杂,包含云,API,微服务等,并在单个业务事务中创建几乎无限的不同协议和技术组合。
- 由于Agile,DevOps和持续交付,许多应用程序现在每两周发布一次,每天发布数千次。因此,可用于测试设计,维护和特别是执行的时间大大减少。
既然软件是业务的主要接口,那么应用程序故障就是业务失败, 如果它影响用户体验,即使是看似微不足道的小故障也会产生严重后果。因此,与应用相关的风险已成为即使是非技术性商业领袖的主要关注点。
如何做版本管理?

- Master 分支 主分支,这个分支最近发布到生产环境的代码,最近发布的Release, 这个分支只能从其他分支合并,不能在这个分支直接修改
- Develop 分支 这个分支是我们是我们的主开发分支,包含所有要发布到下一个Release的代码,这个主要合并与其他分支,比如Feature分支
- Feature 分支 这个分支主要是用来开发一个新的功能,一旦开发完成,我们合并回Develop分支进入下一个Release
- Release 分支 当你需要发布一个新Release的时候,我们基于Develop分支创建一个Release分支,完成Release后,我们合并到Master和Develop分支
- Hotfix 分支 当我们在Production发现新的Bug时候,我们需要创建一个Hotfix, 完成Hotfix后,我们合并回Master和Develop分支,所以Hotfix的改动会进入下一个Release