第十二篇:持续交付:提升产品质量和交付效率的方法论

作者:禅与计算机程序设计艺术

1.简介

持续集成、持续部署(Continuous Integration and Continuous Delivery/Deployment)是一个很重要的实践,它能够将开发人员提交的代码经过自动化构建、测试并部署到预生产环境中,从而保证应用的高质量交付。基于持续集成、部署可以降低部署风险、缩短交付周期、提升软件质量。因此,持续交付已经成为DevOps的一项主要内容。在软件工程实践中,持续交付一般指的是在CI/CD流程中,持续将新代码或者改动源代码库(Code Repository)合并到目标分支(如主干)上,并将每次更新的应用快速、可靠地发布到集成环境(Integration Environment)或预发布环境(Pre-production Environment),最终部署到生产环境。即通过自动化、标准化的流程,将代码的构建、测试和发布过程转变为自动化的、可重复执行的流程。所以,持续交付具有极高的社会和商业价值。
持续交付旨在提升软件开发的速度、频率和质量。它的核心就是引入自动化手段,将开发过程中代码的构建、测试和部署过程自动化、标准化,进而实现应用快速、可靠地向客户交付。但是,只有合理地运用持续交付,才能真正达到减少软件平均修复时间、改善软件开发效率、提升软件品质的效果。本文将深入探讨持续交付的相关理论、方法论和实践。本文适用于以下读者群体:
● 有一定编程基础,熟悉CI/CD相关概念,希望了解CI/CD的理论和方法
● 有相关项目实践经验,对CI/CD有深入理解,希望掌握CI/CD工具链的运用
● 想要深刻理解持续交付背后的理念和原理,拥护持续交付理念并实践其落地方案
● 愿意分享自己的技术观点和经验,传播持续交付相关理论及实践方法
本文将围绕CI/CD的理论、方法论、实践三个方面进行阐述,力争将这些知识和实践应用到实际工作当中,促进团队之间的沟通和协作。

二、持续集成与持续交付

2.1 持续集成

持续集成(Continuous Integration,简称CI)是一个软件开发实践,强调每一次代码的提交都需要通过自动化构建(包括编译、测试等)来验证,只有所有的测试都通过了,代码才能进入下一个阶段。持续集成是一个有益的自然法则,可以让你的软件更快、更稳定地发布。设想一下你是一个非常忙碌的项目管理者,如果你坚持不懈地推动着一个软件的迭代,也许你就会发现,迭代的节奏会越来越慢,交付的压力也会越来越大。只要有好的自动化测试,持续集成就可以帮助你把速度提升一倍。
什么是CI工具链?
持续集成工具链包括很多组件。例如,代码托管平台,比如GitHub、GitLab等;构建系统,比如Jenkins、TeamCity等;测试框架,比如Junit、TestNG等;依赖管理工具,比如Maven、NPM等。为了完成持续集成,以上这些组件之间通常还需要建立一些连接,比如集成消息系统,比如版本控制系统。这些工具都可以通过插件的方式扩展,比如SonarQube、Codecov等。
为什么要使用CI?
以下是一些常见的原因:

  1. 降低部署风险:在持续集成的过程中,你将部署频率降低,因为你可以确保代码每一次提交都是经过完整的测试,并且处于稳定的状态。也就是说,任何时候如果代码出现问题,你就能够立即发现,解决起来也相对容易得多。
  2. 提升软件质量:自动化测试覆盖范围广,而且越来越普遍,这使得开发人员可以专注于编写业务逻辑代码,而不是再花费精力去处理各种琐碎的测试事宜。同时,自动化测试可以模拟不同的用户场景,从而更加准确地找出潜在的问题。这样,你就可以及时发现和解决软件缺陷,不至于等到软件投入市场后才暴露出来。
  3. 减少反馈环节:由于部署频率减少,部署频繁导致的反馈环节也会减少,从而提高交付效率。不仅如此,还有自动化工具可以将测试结果及时的通知给相关的开发人员。
  4. 提升协作效率:对于多个开发人员,有了自动化的构建工具,他们可以互相review代码,同时也可以并行开发,彼此之间不会产生冲突,从而减少错误。这有助于提升协作效率,加快软件交付周期。
  5. 提升敏捷性:自动化的构建、测试以及部署流程,让团队成员可以快速响应需求变化,从而在短时间内快速反应,不断创造新的功能和产品。
  6. 更快、更好地迭代:由于自动化构建、测试、部署的过程,开发人员可以做更多的事情,比如处理bug,做usability测试等,这使得整个开发团队的工作效率得到提升。当然,还有一些团队甚至会用这种方式全天候开发,甚至有些公司甚至会将部署日程固定在周末。

2.2 持续交付与持续部署

持续交付(Continuous Delivery)是指持续将软件新版本、更新,直到它们可用到生产环境中的过程。换句话说,它是一种从开发到运维的自动化流程,它要求开发人员把所有的更新,无论大小,都自动地交付到指定的环境,并在部署之前,所有测试必须通过。持续部署(Continuous Deployment)是在持续交付的基础上的,是持续部署到生产环境的最后一步。它意味着,当代码通过所有测试并准备好发布时,自动部署到生产环境,并对外提供服务。
持续交付与持续部署各有所长。持续交付强调尽可能快地交付最新版软件,同时持续部署则是在这个过程中自动部署到生产环境。虽然两者存在重叠之处,但持续交付侧重于开发阶段的自动化流程,而持续部署侧重于运维阶段的自动化部署。无论是持续交付还是持续部署,均有助于提高软件交付的频率、质量和速度。
持续交付与持续部署的区别:

  1. 目的不同:持续交付是为了开发人员将软件交付到预发布环境中,而持续部署则是为了让软件直接部署到生产环境中。持续交付只是希望通过自动化构建、测试、部署等流程,更快、更高效地交付软件。
  2. 方法不同:持续交付通常采用多种方式,比如蓝绿部署、金丝雀发布等,而持续部署则可以采用自动化发布脚本。
  3. 步骤不同:持续交付一般包含多个环节,比如编码、构建、测试、打包、部署等,而持续部署则只是将部署环节自动化即可。
  4. 标准化程度不同:持续交付仍处于起步阶段,尚未形成统一的标准。但持续部署已得到大规模应用,是较为成熟的模式。
    总结来说,持续集成和持续交付是DevOps的一个重要组成部分,是提升软件交付效率、频率和质量的有效方法。

三、CI/CD实践

在实践层面上,CI/CD由以下几个方面组成:

  1. CI工具链:将代码库的代码每次提交,经过自动化构建、测试、打包、部署等流程,最终生成部署包,并进行集成测试,达到代码发布的自动化流程。
  2. 测试环境:将部署包部署到测试环境,进行单元测试、集成测试、回归测试等。
  3. 预发布环境:将部署包部署到预发布环境,进行负载测试、可用性测试、兼容性测试等。
  4. 生产环境:将部署包部署到生产环境,进行性能测试、压力测试、安全测试等。
    图1:CI/CD实践流程示意图
     
    下面我用自己理解的语言阐述一下CI/CD:

3.1 基础知识

首先,什么是持续集成、持续交付、持续部署?
持续集成(Continuous Integration,简称CI)是一个软件开发实践,强调每一次代码的提交都需要通过自动化构建(包括编译、测试等)来验证,只有所有的测试都通过了,代码才能进入下一个阶段。持续集成是一个有益的自然法则,可以让你的软件更快、更稳定地发布。设想一下你是一个非常忙碌的项目管理者,如果你坚持不懈地推动着一个软件的迭代,也许你就会发现,迭代的节奏会越来越慢,交付的压力也会越来越大。只要有好的自动化测试,持续集成就可以帮助你把速度提升一倍。
持续交付(Continuous Delivery)是指持续将软件新版本、更新,直到它们可用到生产环境中的过程。换句话说,它是一种从开发到运维的自动化流程,它要求开发人员把所有的更新,无论大小,都自动地交付到指定的环境,并在部署之前,所有测试必须通过。持续部署(Continuous Deployment)是在持续交付的基础上的,是持续部署到生产环境的最后一步。它意味着,当代码通过所有测试并准备好发布时,自动部署到生产环境,并对外提供服务。

3.2 CI工具链

持续集成工具链包括很多组件。例如,代码托管平台,比如GitHub、GitLab等;构建系统,比如Jenkins、TeamCity等;测试框架,比如Junit、TestNG等;依赖管理工具,比如Maven、NPM等。为了完成持续集成,以上这些组件之间通常还需要建立一些连接,比如集成消息系统,比如版本控制系统。这些工具都可以通过插件的方式扩展,比如SonarQube、Codecov等。
为什么要使用CI?
以下是一些常见的原因:

  1. 降低部署风险:在持续集成的过程中,你将部署频率降低,因为你可以确保代码每一次提交都是经过完整的测试,并且处于稳定的状态。也就是说,任何时候如果代码出现问题,你就能够立即发现,解决起来也相对容易得多。
  2. 提升软件质量:自动化测试覆盖范围广,而且越来越普遍,这使得开发人员可以专注于编写业务逻辑代码,而不是再花费精力去处理各种琐碎的测试事宜。同时,自动化测试可以模拟不同的用户场景,从而更加准确地找出潜在的问题。这样,你就可以及时发现和解决软件缺陷,不至于等到软件投入市场后才暴露出来。
  3. 减少反馈环节:由于部署频率减少,部署频繁导致的反馈环节也会减少,从而提高交付效率。不仅如此,还有自动化工具可以将测试结果及时的通知给相关的开发人员。
  4. 提升协作效率:对于多个开发人员,有了自动化的构建工具,他们可以互相review代码,同时也可以并行开发,彼此之间不会产生冲突,从而减少错误。这有助于提升协作效率,加快软件交付周期。
  5. 提升敏捷性:自动化的构建、测试以及部署流程,让团队成员可以快速响应需求变化,从而在短时间内快速反应,不断创造新的功能和产品。
  6. 更快、更好地迭代:由于自动化构建、测试、部署的过程,开发人员可以做更多的事情,比如处理bug,做usability测试等,这使得整个开发团队的工作效率得到提升。当然,还有一些团队甚至会用这种方式全天候开发,甚至有些公司甚至会将部署日程固定在周末。

3.3 测试环境

测试环境就是让开发人员提交的代码,经过自动化构建、测试、部署等流程,最终生成部署包,并进行集成测试,从而达到代码发布的自动化流程。目前比较流行的CI工具链有Jenkins、Travis CI、CircleCI等,这里我以Jenkins为例,介绍一下Jenkins的配置。

3.3.1 安装配置

安装Jenkins前,先确保自己的系统已经安装JDK、NodeJS等相关环境。然后下载Jenkins安装包并解压,把jenkins.war文件放到Tomcat的webapps目录下,启动tomcat服务器。启动成功后,访问http://localhost:8080 ,根据提示,按照默认配置,创建管理员账户和密码。

3.3.2 Jenkins配置

Jenkins支持多种插件,可以安装选择适合自己的插件,并进行相应的配置。这里我们以安装Git插件为例,配置Gitlab仓库作为代码源,并设置触发构建的条件。

  1. 登录Jenkins,点击“Manage Jenkins”,选择“Manage Plugins”菜单项,然后搜索“Git Plugin”并安装。
  2. 配置Gitlab仓库作为代码源
    打开“Global Tool Configuration”页面(位于Jenkins首页的左侧导航栏),找到“Gitlab API Token”配置项,输入你的gitlab账号的api token(从gitlab网站生成)。
    填写好相关信息后,点击“Test connection”按钮测试配置是否正确。
  3. 设置触发构建的条件
    打开“New Item”页面(位于Jenkins首页的左侧导航栏),选择“Pipeline”项目类型,输入项目名称并点击“OK”。
    然后,在“General”选项卡的“Scm”区域,选择“Git”类型的SCM,填写远程仓库URL,比如https://gitlab.com/xxx/xxx.git,并勾选“Poll SCM”。
    最后,在“Build Triggers”区域,勾选“PollscmTrigger”并指定间隔时间(单位为秒)。
    这样,每隔一段时间(我们指定的时间),Jenkins就会检查代码是否有更新,如果有更新,则自动触发构建。

3.3.3 Pipeline语法

Pipeline是Jenkins实现CI/CD的核心,它提供了强大的Pipeline语法,可以通过声明式的方式定义构建、测试、部署等过程,来实现CI/CD。

  1. pipeline语法概览
node {
    
    
stage('Checkout') {
    
    
checkout scm
}
stage('Build') {
    
    
sh'mvn clean package'
}
stage('Test') {
    
    
junit testResults:'reports/*.xml'
}
stage('Deploy to Dev') {
    
    
// deploy to dev environment
}
stage('UAT') {
    
    
// perform UAT testing on dev environment
}
stage('Promote to Prod') {
    
    
// promote to prod environment with certain criteria met
}
}

pipeline语法由node{}stage()两个关键字配合{}代码块来定义,其中node{}用来定义节点,比如在Jenkins中可以指定多个节点,stage()用来定义阶段,每个阶段表示一组任务。在每个阶段,都可以调用一些插件或者命令,比如在Build阶段,调用sh命令执行maven编译,在Test阶段,调用junit命令执行单元测试。
注意:在Jenkins中,插件的安装、配置、权限分配都需要进行相应的操作,详情请参阅Jenkins官方文档。
2. 使用Groovy DSL编写pipeline脚本
除了pipeline语法之外,Jenkins还支持使用Groovy DSL脚本语言来定义Pipeline,Groovy DSL语言可以在运行时解析Groovy脚本,并自动将其转换成Pipeline DSL。Groovy DSL代码与pipeline语法类似,示例如下:

def mvnHome = tool 'M3'
def mvn = "${
      
      mvnHome}/bin/mvn"
pipeline {
    
    
agent any
stages {
    
    
stage('Checkout') {
    
    
steps {
    
    
git branch:'master', url: 'https://github.com/xxxxxx/xxxxx.git'
}
}
stage('Build') {
    
    
steps {
    
    
sh "${
      
      mvn} clean package -DskipTests=true"
}
}
stage('Test') {
    
    
steps {
    
    
script {
    
    
def timestamp = new Date().format("yyyyMMddHHmmss")
sh "${
      
      mvn} test jacoco:report coveralls:report -Djacoco.reportsDirectory=target/site/jacoco/${
      
      timestamp}"
}
}
}
stage('Deploy to Dev') {
    
    
when {
    
     expression {
    
     env.BRANCH_NAME == "dev" || env.TAG_NAME =~ /^release\/.*/ }}
steps {
    
    
echo "Deploying ${
      
      params.env}..."
}
}
stage('UAT') {
    
    
when {
    
     expression {
    
     currentBuild.result!= 'SUCCESS'}}
steps {
    
    
echo "Skipping UAT as build failed."
}
}
stage('Promote to Prod') {
    
    
when {
    
     allOf {
    
     branch 'prod'; changeset([includeTarget: false])}}
steps {
    
    
echo "Promoting to production..."
}
}
}
}

该脚本与pipeline语法示例基本相同,只不过Groovy DSL脚本通过定义tool变量来指定Maven工具的路径,并使用${mvn}来调用Maven命令,而不是mvn命令。在when条件判断中,可以使用Groovy表达式进行复杂的条件判断。
注意:由于Groovy DSL语法的特性,Groovy DSL脚本的执行依赖于Jenkins的 Groovy插件,而且DSL脚本并不是完全兼容于pipeline语法,所以推荐使用pipeline语法。

3.3.4 插件列表

以下是CI/CD过程中常用的插件列表:

  1. Git Plugin:集成Git代码托管平台,支持多种SCM,包括Git、Subversion等。
  2. Multijob Plugin:支持多项目同时构建,能够按顺序或并行执行多个项目的构建,支持跨项目的依赖关系。
  3. Docker Plugin:支持在Jenkins构建环境中,快速部署Docker镜像。
  4. Ansible Plugin:支持通过Ansible来远程管理机器。
  5. Gradle Plugin:支持通过Gradle来构建Java应用程序。
  6. SonarQube Scanner Plugin:集成SonarQube,支持对代码进行静态分析,支持多种编程语言。
  7. Github Authentication plugin:集成GitHub OAuth,支持通过GitHub账号来登录。
  8. Bitbucket Server / Cloud Plugin:集成Bitbucket代码托管平台,支持对Bitbucket上代码的检出。
  9. Google Cloud Storage Plugin:支持上传构建产物到Google云存储。
  10. AWS CodeCommit Plugin:集成AWS CodeCommit,支持对CodeCommit代码库的检出和上传。
  11. Azure Artifacts Plugin:支持上传构建产物到Azure Blob存储。
  12. Artifactory Plugin:支持管理外部依赖,包括Maven、npm、NuGet等。
  13. HTTP Request Plugin:支持发送HTTP请求,比如POST、PUT等。
  14. Email Extension Plugin:支持发送邮件,比如发送构建报告、通知结果等。
  15. Job DSL Plugin:支持定义Jenkins项目,支持在Jenkins中通过配置描述语言(Configuration-as-Code)来定义构建流程。
  16. Pipeline Utility Steps Plugin:提供多个Pipeline流水线函数,比如parallel()stash()等。
  17. OpenShift Plugin:支持在OpenShift集群上进行容器化部署。
  18. NodeJs Plugin:支持在Jenkins构建环境中,运行JavaScript。
  19. Xcode Plugin:支持在Jenkins构建环境中,编译Objective-C和Swift代码。
  20. Warnings Next Generation Plugin:支持显示警告信息。
  21. JUnit Plugin:支持生成JUnit格式的测试报告。
  22. Checkstyle Plugin:支持对代码进行静态分析,查找和修复代码风格问题。
  23. PMD Plugin:支持对代码进行静态分析,查找代码质量问题。
  24. Robot Framework Plugin:支持RobotFramework自动化测试。
  25. SSH Build Executor Plugin:支持SSH方式构建,允许构建运行在远程服务器上。
  26. Assembla Plugin:支持将Jenkins构建结果同步到Assembla。
  27. Bamboo Integration Plugin:支持与Bamboo集成。
  28. S3 Bucket Publisher Plugin:支持将构建产物上传到S3云存储桶。
  29. Atlassian Confluence Publisher Plugin:支持将Jenkins构建报告同步到Confluence。
  30. Slack Notifications Plugin:支持在Slack上发送通知。
  31. HTML Publisher Plugin:支持生成HTML格式的构建报告。
  32. External Monitor Job Type Plugin:支持添加第三方监控系统,比如Pingdom、New Relic、SiteScope等。
  33. Kubernetes Plugin:支持在Kubernetes集群上进行容器化部署。
  34. OWASP Dependency Check Plugin:支持对Java应用程序依赖进行扫描,并标注潜在漏洞。
  35. Performance plugin:支持对Java Web应用程序和移动应用程序的性能进行分析。
  36. AnsibleVault integration plugin:支持读取Ansible Vault加密的配置文件。
  37. FogBugz Integration Plugin:支持与FogBugz集成,可以进行问题跟踪和缺陷管理。
  38. Prometheus Plugin:支持在Prometheus上收集Jenkins的指标数据。
  39. Windows Batch Command Plugin:支持在Windows环境上执行批处理命令。
  40. Git Changelog Plugin:支持生成Changelog。
  41. Custom Tools Deployer Plugin:支持在Jenkins部署过程中,部署自定义工具到远程机器。
  42. InfluxDB Plugin:支持在InfluxDB上保存Jenkins的指标数据。
  43. Backup&Restore Plugin:支持备份/恢复Jenkins数据。
  44. Wiki Publisher Plugin:支持将构建产物上传到Wiki。
  45. Milestone Step Plugin:支持在Jenkins构建流水线中增加里程碑功能。
  46. Timestamper Plugin:支持在日志中显示时间戳。
  47. AMQP Plugin:支持与AMQP服务集成,通过消息队列传递事件。
  48. Promoted Builds Plugin:支持设置构建优先级。
  49. GoCD Plugin:支持与GoCD集成,支持对GoCD流水线进行构建触发。
  50. Gitea Branch Source Plugin:支持Gitea代码托管平台,支持Branch Sources。
  51. PagerDuty Integration Plugin:支持PagerDuty事件回调。
  52. RunDeck Integration Plugin:支持与RunDeck集成,支持Job executions events。
  53. Dry Unification Plugin:支持自动化处理变更,并生成合并请求。
  54. WildFly Swarm Plugin:支持在Jenkins构建环境中,运行Java EE应用。
  55. Cache Cleanup Plugin:支持清理Jenkins缓存。
  56. FreeStyle Project Plugin:支持添加自由风格的项目类型。
  57. Publish Over SSH Plugin:支持SSH协议,将构建产物通过SCP传输到远程机器。
  58. CloudBees AWS Credentials Plugin:支持管理AWS凭据。
  59. Notification Plugin:支持在各种消息渠道(比如微信、钉钉等)发送通知。
  60. Parameterized Trigger Plugin:支持在构建参数变化时,自动触发后续构建。
  61. Structured Logging Plugin:支持结构化日志输出。
  62. LDAP Group Plugin:支持基于LDAP的用户组管理。
  63. View Stash Plugin:支持在Stash中查看构建记录。
  64. Microsoft Team Services (VSTS) Integration Plugin:支持与VSTS集成。
  65. Matrix Project Plugin:支持矩阵项目构建,能够并行执行多个构建任务。
  66. Parallel Execution Plugin:支持并行执行构建任务。
  67. GitLab Hook Plugin:支持GitLab webhooks。
  68. GitHub Pull Request Builder Plugin:支持GitHub pull requests。
  69. Display URL Plugin:支持在构建日志中显示链接地址。
  70. Gravatar Plugin:支持Gravatar头像展示。
  71. JWT Claim plugin:支持获取JWT token中的claims。
  72. Log Parser Plugin:支持解析日志。
  73. Apache CloudStack Plugin:支持Apache CloudStack。
  74. Active Choices Plugin:支持配置Jenkins Choice参数。
  75. ServiceNow CMDB Integration Plugin:支持与ServiceNow CMDB集成。
  76. Blue Ocean Plugin:支持Blue Ocean,提供了增强的用户界面和图表展示。
  77. JIRA Plugin:支持与JIRA集成。
  78. Collaboration Feature Plugin:支持代码协同。
  79. Restrictedsignup Plugin:支持限制注册。
  80. LDAP Authorization Strategy Plugin:支持基于LDAP的授权策略。

Guess you like

Origin blog.csdn.net/universsky2015/article/details/132014016