如何实践 DevOps
为希望实施 DevOps 的团队提供的分步指南
Warren Marusiak
高级技术传播者
您的软件开发生命周期是不是充斥一堆混乱的工具和工作流程?您的团队和项目是孤立的吗?如果您对其中一个问题的回答是肯定的,那么现在是考虑 DevOps 的最好时机。DevOps 通过创建新的软件开发生态系统,帮助简化和优化开发和部署工作流程。
但您是如何实现 DevOps 的呢?DevOps 的主要挑战之一是没有标准流程,因为每个团队的需求和目标都各不相同。数量庞大的 DevOps 工具和资源可能导致“分析瘫痪”,从而抑制其采用。以下步骤可以帮助您的团队实施 DevOps。
为什么选择 DevOps?
简短的答案是,DevOps 允许开发人员做自己最擅长的事情,从而提高工作效率:构建出色的软件,而不是手动执行诸如手动检查日志文件之类的低价值工作。DevOps 实践可自动执行重复性工作,例如运行测试和部署、监控生产软件是否存在问题,以及构建具有问题弹性的部署方法。开发人员能够进行构建和实验,从而提高工作效率。
DevOps 有很多定义。在本文中,DevOps 意味着团队拥有软件的整个生命周期。DevOps 团队负责设计、实施、部署、监控、修复问题并且更新软件。DevOps 团队拥有代码和运行代码的基础架构。不仅对最终用户体验负责,还要对生产问题负责。
DevOps 的宗旨是构建一个能够预测问题并使开发人员能够有效应对问题的流程。每次部署后,DevOps 流程应为开发人员提供有关系统运行状况的即时反馈。问题发现的越早,问题造成影响就越小,团队就能越早进入下一个工作。如果可以轻松部署变更并从问题中恢复过来,开发人员便可以试验、构建、发布和尝试新想法。
DevOps 的本质并非是技术。如果您只是购买了 DevOps 工具就将其称为 DevOps,那就是本末倒置。DevOps 的本质是建立责任共担、透明和加快反馈的文化。技术只是实现这一目标的一种工具。
相关资料
免费试用
相关资料
详细了解 DevOps 最佳实践
免责声明
鉴于每个团队都有独特的起点,因此以下某些步骤可能不适用。此外,此列表并不详尽。此处介绍的步骤旨在作为帮助团队实施 DevOps 的起点。
在本文中,DevOps 被用作一个包罗万象的术语,指的是使 DevOps 发挥作用的文化、流程和技术。
实现 DevOps 的 8 个步骤
第 1 步 - 选择一个组件
第一步是从小处着手。选择当前正在生产的组件。理想的组件具有简单的代码库,几乎没有依赖关系和最少的基础架构。该组件将成为团队在实施 DevOps 时起步训练的试验场。
第 2 步 - 考虑采用像 Scrum 这样的敏捷方法
DevOps 通常会搭配敏捷工作方法,例如 Scrum。没有必要采用与某种方法(如 Scrum)相关的所有仪式和做法。Scrum 的三个要素通常易于采用并能快速提供价值:待办事项列表、冲刺和冲刺规划。
DevOps 团队可以在 Scrum 待办事项中添加工作并确定其优先级,然后将该工作的一部分提取到冲刺中,这是完成特定工作部分的固定时间长度。冲刺规划是决定哪些任务将从待办事项列表转入下一冲刺的流程。
第 3 步 - 使用基于 Git 的源代码控制
版本控制是一项 DevOps 最佳实践,它可以加强协作和缩短发布周期。像 Bitbucket 这样的工具允许开发人员共享、协作、合并和备份软件。
选择分支模型。本文概述了这个概念。对于刚接触 Git 的团队来说,GitHub Flow 是一个很好的起点,因为这个概念易于理解且易于实现。基于 Trunk 的开发通常是首选,但需要更多的纪律,这使得首次尝试 Git 变得更加困难。
第 4 步 - 将源代码控制与工作跟踪相结合
将源代码管理工具与工作跟踪工具集成。通过在一个集中位置查看与特定项目相关的所有内容,开发人员和管理层将节省大量时间。以下是某一 Jira 事务的示例,该事务附带来自基于 Git 的源代码管理存储库的更新。Jira 事务包括一个开发部分,其中汇总了在源代码管理中针对 Jira 事务所做的工作。此事务有一个分支、六个提交、一个拉取请求和一个构建。
您可以深入查看 Jira 事务的开发部分,以了解更多详细信息。“提交”选项卡列出了与 Jira 事务相关的所有提交。
本部分列出了与 Jira 事务相关的所有拉取请求。
与此 Jira 事务相关的代码已部署到“部署”部分列出的所有环境中。这些集成的工作方式通常如下所示:添加 Jira 事务 ID(在本例中为 IM-202)来提交与 Jira 事务相关的工作的消息和分支名称。
代码选项卡提供指向与项目相关的所有源代码控制存储库的链接。它可以帮助开发人员在将自己分配给 Jira 事务时找到他们需要处理的代码。
第 5 步 - 编写测试
CI/CD 管道需要测试来验证部署到各种环境的代码是否正常运行。首先为代码编写单元测试。虽然宏伟的目标是 90% 的代码覆盖率,但这在刚开始时是不现实的。为代码覆盖率设置较低的基准,并随着时间逐步提高单元测试覆盖率的标准。您可以将工作项目添加到待办事项列表来解决此问题。
修复生产代码中发现的缺陷时使用测试驱动的开发。发现一个缺陷时,编写单元测试、集成测试和/或系统测试,这些测试会在存在缺陷的环境中失败。然后修复缺陷,观察测试现在是否通过。随着时间的推移,此流程会有组织地提高代码覆盖率。如果此缺陷是在测试或暂存环境中发现的,则测试可确保代码在进入生产环境后能正常运行。
如果从一开始就进行,此步骤很费力,但也很重要。最终用户接触到这些代码变更之前,测试使团队能够看到代码变更对系统行为产生的影响。
单元测试
单元测试将验证源代码是否正确,并且应作为 CI/CD 管道中的第一步运行。开发人员应针对绿色路径、有问题的输入以及已知的极端情况编写测试。在编写测试时,开发人员可以模拟输入和预期输出。
集成测试
集成测试可验证两个组件之间的通信是否正确。模拟输入和预期输出。在将 CI/CD 管道在部署到任何环境之前,都必须首先进行这些测试。这些测试通常需要比单元测试更广泛的模拟才能让组件正常运行。
系统测试
系统测试可验证系统的端到端性能,并确保系统在每个环境中都能按预期运行。模拟组件可能接收的输入并执行系统。接下来,验证系统是否返回了必要的值并正确更新系统的其余部分。应在部署到每个环境后运行这些测试。
步骤 6 - 构建 CI/CD 流程来部署组件
在构建 CI/CD 管道时,需考虑部署到多个环境。如果团队构建仅部署到单个环境的 CI/CD 管道,则会对某些内容进行硬编码。为基础设施和代码构建 CI/CD 管道非常重要。首先构建 CI/CD 管道,在每个环境中部署必要的基础架构。然后,再构建一个 CI/CD 管道来部署代码。
管道结构
该管道首先运行单元测试和集成测试,然后再部署到测试环境。系统测试在部署到环境后执行。
上方的粗略模板可通过多种方式进行扩展。在单元测试和集成测试之前,最好是添加一些额外步骤,比如代码校验、静态分析和安全扫描。代码校验可以强制执行编码标准,静态分析可以检查是否存在反面模式,安全扫描则可以检测是否存在已知漏洞。
用于部署基础设施和代码的 CI/CD 管道可能有所不同。基础设施的 CI/CD 管道通常没有单元测试或集成测试。将在每次部署后运行系统测试,以确保系统没有停止运行。
基础设施
环境之间基础架构的差异使得在某一环境中运行的软件难以在另一个环境中正确执行。防火墙规则、用户权限、数据库访问和其他基础架构级组件必须采用已知配置,这样软件才能正常运行。手动基础架构部署可能很难正确重现。由于此过程涉及许多步骤,因此依靠记忆力来使用正确的参数以正确的顺序执行每个步骤,这可能会导致错误。必须尽可能在代码中定义基础架构,以缓解这些问题以及其他问题。
可以通过各种工具在代码中定义基础设施,这些工具包括 AWS CloudFormation、Terraform、Ansible、Puppet 或 Chef。
编写多个管道来部署基础架构。与编写代码一样,保持基础架构部署的模块化也很有帮助。尽可能将所需的基础设施分解为不相交的子集。假设 A、B、C 和 D 是可以相互依赖的基础架构组件的抽象。例如,A 可能是 EC2 盒子,B 可能是 S3 存储桶。基础架构组件 A(仅有 A)依赖组件 B 的依赖关系应该一起保存在同一 CI/CD 管道中。A、B 和 C 依赖 D(但 A、B 和 C 相互独立)的依赖关系应分解到多个 CI/CD 管道。在本例中,有四个独立的管道。在此情况下,您应该为 D 构建一个其他三个组件都依赖的管道,并为 A、B 和 C 各构建一个管道。
代码
CI/CD 管道是为部署代码而构建的。这些管道通常易于实施,因为由于之前的工作,基础架构已经可供使用。这里的重要考虑因素是测试、可重复性以及从错误部署中恢复的能力。
可重复性是指在不损害系统的情况下重复部署同一变更的能力。部署应该是可重入且等效的。部署应将系统的状态设置为已知配置,而不是对现有状态应用修改器。不能重复应用修改器,因为在第一次部署之后,修改器正常运行所需的起始状态已经发生了变化。
对于不可重复更新,一个简单示例是通过向配置文件追加数据来更新该文件。请勿在配置文件中追加行或使用任何此类修改技术。如果通过追加方式完成更新,则配置文件最终可能会出现数十行重复行。正确做法是,将配置文件替换为源代码管理中正确写入的文件。
这一原则也应适用于数据库更新。数据库更新可能会出现问题,需要注意细节。必须使数据库更新流程具备可重复性和容错能力。在应用更改之前立即进行备份,以便可以恢复。
另一个考虑因素是如何从错误的部署中恢复。有两种情况:部署失败,系统处于未知状态;部署成功,警报被触发,故障单开始流入。有两种一般的处理方法。第一种方法是回滚。第二种方法是使用功能标志并关闭必要的标志,以恢复到已知的良好状态。有关功能标志的更多信息,请参阅本文的步骤 8。
在检测到错误的部署后,回滚会将先前已知的良好状态部署到环境中。这应该在一开始就做好计划。在操作数据库之前,请先进行备份。确保您可以快速部署前一版本的代码。定期在测试或暂存环境中测试回滚过程。
步骤 7 - 添加监控、警报和工具
DevOps 团队需要监控每个环境中正在运行的应用的行为。日志中有错误吗?对 API 的调用超时了吗?数据库崩溃了吗?监控系统的每个组件是否存在问题。如果监控检测到问题,则会提交故障单,以便有人能够解决该问题。作为解决过程的一部分,需要编写可以发现该问题的其他测试。
修复缺陷
监控和响应问题是运行生产软件的一部分。具有 DevOps 文化的团队负责软件的运营,并借鉴站点可靠性工程师 (SRE) 的行为。对问题进行根本原因分析,编写测试以检测问题,修复问题,并验证这些测试现在是否通过。这一过程在前期往往很费力,但从长远来看却能带来收益,因为它能减少技术债务,保持运营的敏捷性。
性能优化
一旦实现了基本的运行状况监控,下一个常见的步骤便是性能优化。了解系统各个部分的运行状况,并对慢速部分进行优化。正如 Knuth 所说:“过早的优化是万恶之源”。不要优化系统中所有组件的性能。只优化最慢、最昂贵的部分。监控有助于确定哪些组件速度慢且成本高昂。
第 8 步 - 使用功能标记来实现金丝雀测试
要启用金丝雀测试,请将每项新功能封装在一个功能标记中,并附上包含测试用户的允许列表。只有在部署到环境后,新功能代码才会为允许列表中的用户运行。让新功能在每个环境中充分应用,然后再将其推广到下一个环境。当新功能渗入到某个区域时,请注意指标、警报和其他工具,以发现问题迹象。具体而言,请留意新的故障单的增加情况。
在将问题推广到下一环境之前,先解决该环境中的问题。在生产环境中发现的问题的处理方式应与在测试或暂存环境中发现的问题的处理方式相同。确定问题的根本原因后,编写测试以确定问题,实施修复,验证测试是否通过,然后通过 CI/CD 管道推广该修复方法。新的测试将通过,故障单数量将下降,而更改将渗透到检测到问题的环境中。
总结...
回顾一下将第一个组件移入 DevOps 的项目。找出痛点或具有挑战性或困难的部分。改进该计划以解决这些痛点,然后转到第二个组件。
在一开始就使用 DevOps 方法将组件投入生产似乎是一项艰巨的工作,但以后一定会有所回报。一旦奠定了基础,第个二组件的实施应该会更容易。可以采用与第一个组件相同的流程,并针对第二个组件稍做修改,因为工具已经到位,技术已能理解,团队也已受过培训,可以按照 DevOps 风格工作
要开始 DevOps 的旅程,我们建议您试用 Atlassian Open DevOps,这是一个集成的开放式工具链,包含开发和操作软件所需的一切,并且能够随着需求的增长集成其他工具。
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。