持续集成流水线
Hi,我是阿昌
,今天学习记录的是关于持续集成流水线
的内容。
从团队协作的角度上来看,在版本发布过程中,经常出现测试依赖开发手工生成制品、版本发布也从开发本地出版本的问题。而且项目架构如果从单体演进至组件化架构,随着越来越多的组件分离,以前一次构建可能就能出制品,但是组件化后需要先构建多个组件,然后再进行组件的集成,协作的复杂度也会更高。
最终后果就是团队的协作效率低,版本的质量也没办法控制。开发同学日常的开发工作经常被打断,沦为名副其实的“打包工程师”。
如何解决这些问题呢?最好的方式就是创建可靠、可重复的软件发布过程,让整个过程尽可能地自动化,从而提高整体的集成发布效率。通过自动化减少低价值的重复工作。
一、持续集成流水线
持续集成流水线 是一种软件开发实践。
如下图所示,每当开发提交代码后,都会触发流水线执行对应的步骤,这些步骤通常包含扫描检查、构建、测试、部署等环节。
如果提交的代码不满足流水线上设置的检查时,流水线的执行就会失败,不允许代码合入仓库。
那么使用持续流水线能够给团队带来什么价值呢?
- 一方面是明显的效率提升。在没有使用持续集成流水线前,版本的构建发布都得依赖本地构建,如果一天需要构建多个版本,那么效率非常低下。有了流水线,就可以自动化地帮我们
完成这些低价值的工作
。另外,也可以在团队内形成协作规范,大家都以流水线推送的版本为准,可以减少不必要的沟通。 - 另一方面是明显的
质量提升
。本地构建的版本不可控的因素非常多,例如开发本地的构建环节、代码是否拉取了最新、签名是否正确等等,都可能影响最终的制品质量。有了持续集成流水线,就有了统一的构建环境和规范的构建过程,有效保证制品质量稳定。另外,可以在流水线上设置相应的质量门禁,如静态代码检查、自动化测试验证、架构守护验证等等,当提交代码不符合要求时,可以不允许入库,这有助于团队尽快发现相关错误。
要让流水线发挥最佳的效果,关键还需要团队能够关注流水线的运行状态,并且及时响应。下面我2 个在实践过程中需要遵循的流水线纪律。
- 第一个是流水线如果构建失败了,不允许提交代码,尽快修复。当流水线构建失败时,应该立马排查失败的原因,尽快修复,避免影响出版本。如果短时间内无法修复,应该及时回滚代码,不要影响团队其他人的代码合入。
- 第二个是每天下班前一定要保证最后一次流水线构建是成功的。这个纪律叫 CI 红不过夜,通常要保证至少每天都有一个可用于测试的版本,这样才不会影响第二天的测试及相关人员拿到版本作验证。
二、Sharing 流水线设计
对于组件化的架构来说,由于抽离了多个组件,通过自动化来管理组件的发布及集成作用就更加明显了。
如果不能通过自动化来转移这部分复杂度,那么对于团队来说,拆分组件也许是另外一种负担,需要频繁地手工管理组件的构建发布,组件的集成发布等问题。因此,需要设计组件化架构的流水线,实现组件管理的自动化。Sharing 来看看如何设计流水线。
首先,需要给流水线做个分级,拆分为组件流水线以及基座流水线。
组件流水线的设计分主要分为 4 个操作步骤,也就是质量门禁检查、代码检视、组件制品管理及发布通知。
具体步骤是后面这样。
- 组件开发人员提交代码后自动触发流水线质量门禁检查,质量门禁包含代码扫描、编译及自动化测试等环节。
- 团队内架构师进行检视后代码合入。
- 发布最新的组件版本到 maven 制品库。
- 将构建结果及制品通知到相关干系人。
基座流水线的设计主要分为 5 个操作步骤,分别是提交组件集成清单、进行质量门禁检查、代码检视、发布制品到版本库及最后确认进行发布。
- 产品团队根据版本规划,提交组件集成版本清单。
- 质量门禁包含代码检查、编译、集成测试、性能测试等。
- 团队内架构师进行检视,产品经理进行确认后代码合入。
- 发布最新的应用版本到制品库。
- 团队确认后选择渠道(内测、灰度、应用市场、全量)进行发布。
在实际过程中,可以根据项目情况以及内部的工具完善度,灵活调整流水线的各个步骤。
流水线的设计应该和代码一样,可以持续迭代,而不是一成不变。
比如通常来说,最后的发布阶段不会是自动化的,还需要进行人工测试确认后再触发流水线进行发布部署。
三、使用 GitHub Action 搭建流水线示例
目前持续集成工具非常多,例如 Jenkins、GitLab CI、GitHub Action、AzureDevOps 等等,由于 Sharing 项目目前在 GitHub 托管,所以使用 GitHub Action 来演示如何搭建流水线。首先来看看如何基于 GitHub Action 配置
流水线。
GitHub Action 采用 yml 配置文件
的方式来描述 CI 的构建状态,在.github/workflows 目录下创建对应的 yml 文件即可。
可以参考后面的代码,在每个配置上备注了具体的注释。
//配置工作流的名称
name: Sharing CI
//配置当master分支有PR或者代码提交时会触发该流水线
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
//配置运行的任务
jobs:
build:
//配置运行的服务器环节,一般使用默认
runs-on: ubuntu-latest
//配置流水线的步骤
steps:
//配置系统的构建环境
- uses: actions/checkout@v3
- name: set up JDK 11
uses: actions/setup-java@v3
with:
java-version: 11
distribution: 'temurin'
cache: gradle
//检查Gradle运行环境
- name: Grant execute permission for gradlew
run: chmod +x gradlew
//执行静态代码扫描,使用lint检查
- name: Code Scan
run: ./gradlew app:lint
//执行代码架构检查
- name: Arch Test
run: ./gradlew app:testDUT --tests com.jkb.junbin.sharing.ArchRuleTest
//执行功能自动化冒烟测试
- name: Smoke Test
run: ./gradlew app:testDUT --tests com.jkb.junbin.sharing.SmokeTesting
//构建版本
- name: build
run: ./gradlew app:assembleRelease
//推送版本到artifact制品库
- name: Upload apk to artifact
uses: actions/upload-artifact@v3
if: always()
with:
name: sharing_app
path: ${{ github.workspace }}/app/build/outputs/apk/release/*.apk
完成了流水线的配置以后,当有代码合入时则会触发流水线的运行,可以在项目的 Action 选项中查看对应的构建情况。
另外,除了自动触发以外,也可以点击进入详情,手动重新触发流水线的执行。
当流水线执行成功以后,则可以在详情中查看到构建的制品。
这里特别推荐采用配置文件的方式来定义流水线,这样一方面可以将流水线的变更和代码也一同纳入到版本管理中,另外由于配置文件和代码在一起管理,也可以让开发的同事更关注流水线的设计。
目前主流的持续集成工具都支持使用配置文件定义流水线的方式,只是不同的工具配置的语法稍有差异,整体的流水线设计是通用的。
四、总结
持续流水线 是一种软件开发的实践,目的是通过自动化为软件的发布创造一个稳定且可重复的过程。
流水线带来的效果是显而易见的,从效率上帮助减少低价值的重复工作,例如本地编译打包,另外也能减少团队成员间不必要的沟通。
从质量上看,统一了构建发布环境,整个环境会更可靠,减少了人工操作
带来的意外风险。另外,结合流水线增加质量门禁,可以在版本发布前检查代码质量,避免不符合规范及要求的代码合入代码仓库中。
当然要让流水线发挥最佳的作用,还得依靠团队成员共同来遵循流水线的纪律,保障流水线红不过夜,当运行失败时能及时修复。
对于组件化架构的流水线设计,可以采用分层分级的方式。具体就是通过设计组件的流水线来管理组件的构建和版本管理,另外再设计集成的流水线来管理组件的集成和发布。
通过 GitHub Action 给你演示了如何搭建一个持续集成流水线,GitHub Action 采用 yml 配置的方式来定义流水线,这种方式对于开发人员来说更加友好,只需要按照特定的语法格式描述步骤即可,同时这个配置文件也能和代码一同进行版本管理。
在实践过程中推荐使用这种配置文件定义流水线的方式。