Atlassian 套件玩转持续交付
Atlassian 公司,成立于 2002 年,是澳大利亚一家面向企业提供协作、开发和问题跟踪软件的 SaaS 公司。旗下产品包括企业知识管理与协同软件 Confluence,团队问题跟踪和敏捷项目管理软件 Jira,直观地针对任何项目进行协作的在线看板工具 Trello,Git 代码管理软件 Bitbucket,Git 和 Mercurial 代码管理客户端 Sourcetree,持续集成和发布管理软件 Bamboo,以及协同 IT 服务管理软件 Jira Service Desk 等。
下图为使用 Atlassian 套件做持续交付的业务流程图,其中的持续集成与持续交付部分展示了开篇视频的大致操作流程。在这篇文章【Atlassian全家桶系列】产品需求管理中,我跟大家分享了在产品需求管理过程中 Jira 与 Confluence 工具如何双剑合璧、发挥集成带来的益处,覆盖了产品规划、需求文档与过程管理、迭代计划与跟踪管理和报表管理等。接下来,我们一起进入软件研发世界,瞧瞧 Atlassian 套件如何实现“从代码到客户,持续交付”的目标。
01
—
CI/CD 与持续部署介绍
持续集成(Continuous Integration 或 CI)是一种软件工程实践,团队开发成员经常地集成 TA 们的工作,通常每个成员每天至少集成一次,意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译、自动化测试等)来验证,从而尽早地发现集成问题。持续集成原则之一是“快速失败”,强调对“构建失败”能尽早地检测、通知和纠正。早期检测容许早期纠正,减少对项目的影响。另外,如果我们更早地检测到问题,我们也没必要执行其他构建过程,所以节省了时间和资源。
持续交付(Continuous Delivery 或 CD)是一种软件团队端到端的交付能力,“部署流水线”确保代码和基础设施始终处于可部署状态,所有提交到主干的代码都可以安全地部署到生产环境给用户使用。将持续集成构建的制品(Artifacts)部署到不同环境中测试,如果通过测试,那么该制品会被部署到下个阶段的环境中。这样,开发人员从每个阶段环境的测试中获得新的反馈,如果出现错误,他们可以更容易地知道问题所在,并在代码发布到生产环境前解决。
持续部署(Continuous Deployment)指在持续交付的基础上,把部署到生产环境的过程自动化。部署与交付是完全不同的概念,部署属于技术领域的操作,而交付是一个业务决策活动,通常也称为发布,即:将新构建的特性交付到用户手里使用。我们可以向环境多次部署,但只有当业务需要时才向用户发布。
02
—
持续交付工具链配置
Atlassian 通过应用程序链接(Application Links)将 Confluence、Jira、Bitbucket 和 Bamboo 等系统集成在一起,系统之间使用 oAuth 协议进行用户资源的授权与共享。
1.Jira 配置
为了实现在研发过程中自动更新相应的 Jira 状态,比如:在创建新代码分支时将 Jira 用户故事的状态从 To Do 更新到 In Progress,我们需要配置 Jira 问题类型“用户故事”对应的工作流。在工作流转换动作的触发器(Trigger)设置中,添加相应触发器,目前 Jira 系统提供的触发器有:
Branch created:当代码仓库中有新分支被创建时自动转换工作流;
Commit created:当有新的代码提交到代码仓库时自动转换工作流;
Pull request created:当有新的拉取请求创建时自动转换工作流;
Pull request declined:当拉取请求被拒绝时自动转换工作流;
Pull Request reopened:当拉取请求被重新打开时自动转换工作流;
Pull request merged:当拉取请求被合并到主干时自动转换工作流;
2.Bitbucket 配置
软件开发人员主要通过代码进行沟通和协作,一款优秀的源代码版本控制系统至关重要。Bitbucket 采用 Git 和 Mercrurial 作为分布式版本控制系统,团队借助 Bitbucket 可以集中规划项目、开展代码协作以及进行测试和部署。其特点有:
提供无限个私有代码库(5 人以下小型团队免费);
与 Jira 和 Trello 无缝集成,可以直接从 Jira 问题或 Trello 卡片创建 Bitbucket 分支;
通过代码评审构建高质量软件,通过拉取请求更高效地批准代码评审,通过内嵌的评论直接在源代码中讨论;
通过内置的持续交付功能实现频繁部署,Bitbucket Pipelines with Deployments 使用集成式 CI/CD 构建、测试和部署,获得配置即代码和快速反馈回路带来的优势;
保护工作流,通过 IP 白名单和双重验证确保云上代码的安全性;
当第一次使用 Bitbucket 时,我们先创建 Bitbucket 项目,在项目下创建所需数量的代码仓库。在仓库设置(Repository Settings)中对仓库和分支安全、工作流、拉取请求检查等进行设置,比如:设置拉取请求的代码合并到主干之前至少有 2 个人审批通过,否则将无法合并。Sourcetree 是适用于 Windows 和 Mac 的免费 Git 客户端,可以简化与 Git 代码库的交互,让软件开发人员集中精力编写代码。功能完善的图形用户界面,开箱即用,可与 Git 和 Mercurial 搭配使用。使用 Bitbucket 左侧菜单栏中的 Clone 功能,将新建的服务端代码仓库克隆到开发人员的本地环境中。
3.Bamboo 配置
Bamboo Server 是一款持续集成和交付工具,在简单的工作流程中整合了自动化构建、测试和发布,可以完美配合 Jira Software 和 Bitbucket 的工作,提供完全可跟踪的部署流水线。Bamboo 适用于任何语言,以及 AWS CodeDeploy、Docker 和 Amazon S3 等其他热门技术。借助 Bamboo 的专用代理功能可以立即运行修补程序和关键构建。另外,Bamboo 最多支持 100 个远端构建代理,能够并行地运行批量测试,从而使队列保持流动,并快速为开发人员提供反馈。
Bamboo 模型将构建项目与部署项目独立开,但是可以通过触发器在构建项目执行成功后自动触发部署过程。我们先创建构建项目,然后在项目下创建所需数量的计划(Plans):
每个 Plan 定义了整个构建过程的所有配置信息,比如:关联的 Bitbucket 代码仓库、计划分支(Plan Branch)创建规则、通知配置和构建任务编排等;
每个 Plan 下可以配置多个串行执行的 Stages,用来控制工作流的执行,每个 Stage 表示构建流程的一个步骤,比如:为编译创建一个 Stage,紧跟着测试、部署 Stages;
每个 Stage 中可以配置多个并行执行的 Jobs,每个 Job 代表构建代理服务器上运行的任务集合,需配置构建的输入物、所需的可执行程序、运行构建的代理服务器和构建过程的输出物等;
每个 Job 中可以配置多个串行执行的 Tasks,每个 Task 是进行自动化构建的基本块,比如:Maven、Ant 和自定义脚本等;
在构建计划中,Bamboo 提供了多种触发器触发构建过程,比如:由 Bitbucket 服务器代码仓库触发(有变更被提交时触发)、远程触发器、代码仓库轮询(如:每小时轮询一次,检查到代码变更时触发)、按计划运行(如:工作日工作时间段内每小时触发一次)、每日构建(如:每天凌晨 4:00 触发)。在我们的 Demo 中,配置成“由 Bitbucket 服务器代码仓库触发”。计划分支(Plan Branch)让我们可以使用同样的计划配置在不同的分支上运行构建,可以设置在什么情况下创建和删除计划分支,比如:手动创建、在新建拉取请求时自动创建、在创建分支时自动创建、在创建分支且匹配指定正则表达式时自动创建。在我们的 Demo 中,配置成“在创建分支时自动创建”。
Bamboo 还提供了自动合并和通知偏好等功能,带计划分支的特性分支模型为开发人员提供了灵活且精确的冲突规避工具,通过频繁且规律的代码合并,减少了“代码漂移”(Code Drift),减少在项目中实施带缺陷的代码。当开发人员有权限打开或关闭“自动合并”开关以适应各自的开发周期时,特性分支模型会运作得尤为突出,而 Bamboo 系统提供了一个理想的环境供开发人员自由掌控这个权限。关于计划分支的特性(如:自动合并门禁和分支更新器策略),请参考之前写的文章Atlassian持续集成系统之Plan Branches介绍。
在 Maven Build Job 中配置了 4 个 Tasks,它们的作用如下:
Source Code Checkout:将源代码从仓库中检出到 Bamboo 工作目录中,需配置代码仓库;
Maven 3.x:Apache Maven 是构建和管理 Java 项目的工具,需配置可执行的 Maven 程序及相关参数、JDK 和工作目录等;
Sonar Maven 3:做 Sonar 静态代码扫描与分析,需配置 Maven 程序、JDK、SonarQube 服务器、分支与拉取请求选项等;
JUnit Parser:解析构建后的测试结果,需配置 JUnit 测试报告目录,比如:**/surefire-reports/*.xml
我们 Demo 的目标是将构建的制品(Artifacts)自动部署到阿里云服务器上,并发布给终端用户使用。接下来,我们需要创建部署项目,关联以上配置好的构建计划,可以选择使用主干计划分支(基于 master)或自定义计划分支(Plan Branch)。一般针对不同阶段配置不同的部署环境(如:测试环境、预生产环境和生产环境),部署通常运行在代理服务器上,也可以配置到 Docker 容器中。每个环境需定义将发布部署到该环境所涉及的步骤及部署的触发器等。为了简化流程,这个 Demo 仅配置了一个生产环境,持续部署的触发条件是:在主干计划分支构建成功后。部署到生产环境的 Tasks 配置如下:
Artifact download task:用于在不同的构建计划之间共享制品,或者在部署环境中共享构建计划的制品,而不需要每次重新构建。需将制品名称配置成构建计划中 Job 产出的制品;
SCP Task:用于将 Bamboo 中的文件直接上传到远程服务器,可以拷贝多个文件,并保留拷贝文件的完整目录结构。需配置远程服务器地址、身份认证、制品名称和远程目录等;
SSH Task:用于执行远程服务器上的 SSH 命令,比如:调用数据库迁移脚本、启停服务等。需配置远程服务器地址、身份认证、SSH 命令等;
3.与 SonarQube 集成
SonarQube 是一个代码质量管理平台,可以将各种代码质量和覆盖率检测工具的结果(如:CheckStyle 和 Jacoco)直接展示给用户,还可以通过不同的插件算法对结果进行再加工,并最终以量化的方式来衡量代码质量,从而方便地对不同规模和种类的工程进行相应的代码质量管理,以便进行有针对性的代码修复或重构。同时,SonarQube 还对大量的持续集成工具提供了接口支持,可以很方便地在持续集成中使用。
下图是将 SonarQube 集成到 Atlassian 持续集成中的解决方案,需要在 Bitbucket 和 Bamboo 中分别安装 Sonar for Bitbucket Server 和 Sonar for Bamboo 插件。另外,由于要实现基于 Branch 的静态代码分析,我们采用的解决方案是:SonarQube Community (V8.3) + Community Branch Plugin (V1.3)。Bamboo 中持续集成会触发 SonarQube 分析,通过构建计划分支,Bamboo 中的持续集成程序会自动触发 SonarQube 分析,将分析结果发布到 SonarQube 服务器上,同时将 feature 分支的构建结果通知开发人员。在开发人员为 feature 分支创建拉取请求时,Bitbucket 会收集 Sonar 度量和代码问题,并显示在拉取请求中,供拉取请求的发起人和评审人参考。我们接下来会介绍下 Sonar 在 Bitbucket 和 Bamboo 中的具体配置。
在安装好 Sonar for Bitbucket Server 插件后,Bitbucket 提供从项目和代码仓库两个层级配置 Sonar。在 Sonar 项目设置中,我们可以设置代码分析模式、是否在拉取请求的代码比较中显示 Sonar 问题、是否在拉取请求中显示 Sonar 统计信息、在质量未达标时是否要阻止拉取请求的代码合并等。
在代码仓库设置中,需启用 Sonar,配置 SonarQube 服务器、Sonar master 项目、构建类型,以及是直接复用项目配置还是为该仓库自定义配置。
在 Bamboo 后台管理-->管理插件-->Sonar for Bamboo 中添加 SonarQube 服务器,配置 Sonar 服务器名、主机 URL、身份认证、质量门禁构建失败规则等。在构建计划的 Sonar Maven 3 task 中配置通用任务选项(Maven 可执行程序、JDK 和工作目录)、Sonar 服务器配置、构建失败选项、分支策略与拉取请求选项、是否启用增量代码扫描模式等。
在分支策略与拉取请求选项中,必须配置 Replacement for illegal branch characters 为“_”,因为 Sonar 无法解析 Git 分支命名中常用符号“/”,比如:必须将 feature/user-story-xyz 替换成 feature_user-story-xyz。另外,为了在 Sonar 分析报告中显示测试覆盖率,需要在构建计划的 Maven 3.x task 中增加额外参数:clean org.jacoco:jacoco-maven-plugin:prepare-agent install,同时配置 Maven 中的 Sonar 服务器信息(*\Atlassian\Bamboo\tools\apache-maven-3.5.0\conf\settings.xml):
Java 项目采用 SpringBoot 框架搭建,使用 IntelliJ IDEA 开发,项目目标是:根据身高和体重计算 BMI 值,并给出计算结论。针对核心业务代码逻辑,我编写了部分单测用例,旨在模拟自动化测试在持续集成中的作用。
03
—
持续集成与部署 Demo
在 Jira 看板中,选择 Jira 用户故事卡片,右侧将展示详情信息。在开发 Panel 中点击“创建分支”,在弹窗中确认代码仓库、分支类型、代码分支来源、分支名称。分支类型前缀在 Bitbucket 的项目或仓库的分支模型中设置,比如:feature 的默认分支类型前缀为/feature,Release 为/release。确认无误后,点击 Create branch 进入 Bitbucket 页面。
此时,返回 Jira 看板将显示 Jira 用户故事自动被更新到了“处理中”,这是因为我们在 Jira 工作流的转换动作的触发器中设置了:当代码仓库中有新分支被创建时自动转换工作流。在开发 Panel 中将显示“1 branch”,点击可以查看具体的代码仓库和分支名称。在 Bamboo 持续集成系统中,计划分支(Plan Branch)被自动创建并成功完成第一次构建,这是因为我们在 Bamboo 构建计划中设置了:当代码仓库有新分支被创建时自动触发计划分支的创建。
打开 Sourcetree,从 Bitbucket 服务器获取全部更新,并将 BUDDHA-22 分支代码检出到本地。打开 IntelliJ IDEA 开发代码,开发完成后,在 Sourcetree 中将修改的文件暂存所选,然后输入备注(注意:必须包含 Jira 编号),勾选“立即推送变更到 xxx”,点击“提交”将本地代码变更推送到远程 feature 分支。
打开 Bitbucket,确认最新代码变更已成功提交到远程分支,且自动触发了基于 feature 分支的计划构建。点击构建图标会弹出构建详情,点击链接后跳转到 Bamboo 构建页面。
在构建页面,我们可以实时看到构建进度和结果。构建结果包含了自动化测试用例执行结果(6 个用例全部通过)、Sonar 分析结果(质量门禁通过)、关联的 Jira 问题及代码提交信息、构建的输出物(共享制品)、制品部署信息、构建日志等。如果构建失败,比如:某个单元测试用例未通过,那么在测试(Tests)中将显示详细的失败用例代码。这时需要尽快修复阻碍构建成功的所有问题,否则无法将拉取请求合并到 master 分支。
在 feature 分支构建成功(通过了 Sonar 代码质量扫码和自动化测试)后,我们需要在 Bitbucket 中发起拉取请求(Pull Request,简称 PR),将最新代码提交合并到 master 分支。选择来源和目标分支,输入描述和评审人(可以在 Bitbucket 后台设置默认评审人),点击“创建”完成 PR 的创建。这时,返回 Jira 看板查看 Jira 用户故事被自动更新到“评审中”。
使用评审人账号登录 Bitbucket,将看到所有待评审的 PR 记录(包括评审人、Sonar 检查结果和构建结果),选择 BUDDHA-22 拉取请求,通过 Diff 查看具体的代码改动,可以对每行改动添加评语,也可以针对整个 PR 添加评语,评审通过后点击右上角“Approve”。而代码的合并可以由 PR 的发起人或评审人操作,具体由团队规则决定。返回 Jira 看板将显示 Jira 用户故事自动被更新到了“完成”,这是因为我们在 Jira 工作流的转换动作的触发器中设置了:当拉取请求被合并到主干时自动转换工作流。
此时,切换到 PR 发起人账号登录 Bitbucket,查看到 PR 状态依然是 Open,点击 PR 右上角的 Merge 按钮执行代码合并,PR 状态变成 Merged。合并代码到 master 会自动触发 master 分支构建,如果构建成功,则会自动触发持续部署,从构建计划的产物共享制品(shared artifacts),创建发布版本(Release),部署到远程服务器上。
构建过程产出的制品可以在其他构建项目或部署项目中共享。Bamboo 自身管理制品(Artifacts),所以在构建和部署阶段所需的任何制品,Bamboo 会自动传输到所需远程服务器上。一个发布版本(Release)创建自单次构建结果,发布版本是用来准确跟踪部署到某个环境中的软件包,本质上是在部署过程使用的制品和相关元数据(如:Jira 问题、代码提交和测试数据)的一个快照(Snapshot),元数据可以用在发布说明和质量控制中,也可以通过元数据比较两个发布版本之间的差异。
在发布版本的部署阶段,主要做的事情是:使用 Bamboo SCP Task 将构建制品(jar 包)从 Bamboo 服务器传输到阿里云发布服务器上的指定目录,然后使用 Bamboo SSH Task 执行阿里云服务器上 deploy.sh 脚本,完成 jar 包部署和重启服务等具体部署过程。最后,在生产环境中进行 BMI 计算器的手工测试验证,验证通过后,本次发布完成。
而在持续交付实践中,部署到生产环境是通过手动触发的。在 Bamboo 部署项目中,我们手动创建新的发布版本,需要选择计划分支及其构建结果、定义发布版本(版本号+构建 ID)、自上个发布版本的所有变更(Jira 问题和代码提交信息),然后将这个发布版本手动部署到生产环境中。部署成功后,各环境部署状态列表中的触发器为 Manual run by XXX。
04
—
写在最后
Atlassian 套件从提出功能请求一直到完成部署,提供了完整的可追溯性。无论是 Confluence 记录每次团队对需求达成共识后的版本变更记录,还是 Jira 对需求过程每个细节的全面跟踪,亦或在研发过程中分支创建、代码提交、拉取请求、持续集成、发布版本(Release)创建和部署,无一不是以 Jira 问题(用户故事)为主线,体现了需求作为唯一受信源的原则。
在研发过程中,以代码仓库为唯一受信源,保存所有源代码的变更历史(如:产品源代码、测试代码、自动化脚本等),无论是拉取请求评审,还是持续构建亦或发布版本部署,都是围绕着提交(Commits)。 制品库也作为唯一受信源,在构建计划的 Job 中产生制品(Artifacts),Bamboo 提供的共享制品用于在不同的构建计划之间共享,或者在不同阶段的环境中共享构建计划的制品,满足后续环节的快速取用,而无需每次重新构建,比如:从构建计划的制品创建发布版本后,如果测试环境测试通过(无法任何代码改动),那么将该发布版本直接提送(Promote)到预生产环境中测试,测试通过后,直接提送到生产环境中。所有团队都以唯一受信的需求/缺陷、源代码和构建制品仓库中内容为基准,相互沟通与协作。
版权声明: 本文为 InfoQ 作者【YY哥-杨勇】的原创文章。
原文链接:【http://xie.infoq.cn/article/f43244d0151b9be467d460ca8】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论