作者:禅与计算机程序设计艺术
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?
以下是一些常见的原因:
- 降低部署风险:在持续集成的过程中,你将部署频率降低,因为你可以确保代码每一次提交都是经过完整的测试,并且处于稳定的状态。也就是说,任何时候如果代码出现问题,你就能够立即发现,解决起来也相对容易得多。
- 提升软件质量:自动化测试覆盖范围广,而且越来越普遍,这使得开发人员可以专注于编写业务逻辑代码,而不是再花费精力去处理各种琐碎的测试事宜。同时,自动化测试可以模拟不同的用户场景,从而更加准确地找出潜在的问题。这样,你就可以及时发现和解决软件缺陷,不至于等到软件投入市场后才暴露出来。
- 减少反馈环节:由于部署频率减少,部署频繁导致的反馈环节也会减少,从而提高交付效率。不仅如此,还有自动化工具可以将测试结果及时的通知给相关的开发人员。
- 提升协作效率:对于多个开发人员,有了自动化的构建工具,他们可以互相review代码,同时也可以并行开发,彼此之间不会产生冲突,从而减少错误。这有助于提升协作效率,加快软件交付周期。
- 提升敏捷性:自动化的构建、测试以及部署流程,让团队成员可以快速响应需求变化,从而在短时间内快速反应,不断创造新的功能和产品。
- 更快、更好地迭代:由于自动化构建、测试、部署的过程,开发人员可以做更多的事情,比如处理bug,做usability测试等,这使得整个开发团队的工作效率得到提升。当然,还有一些团队甚至会用这种方式全天候开发,甚至有些公司甚至会将部署日程固定在周末。
2.2 持续交付与持续部署
持续交付(Continuous Delivery)是指持续将软件新版本、更新,直到它们可用到生产环境中的过程。换句话说,它是一种从开发到运维的自动化流程,它要求开发人员把所有的更新,无论大小,都自动地交付到指定的环境,并在部署之前,所有测试必须通过。持续部署(Continuous Deployment)是在持续交付的基础上的,是持续部署到生产环境的最后一步。它意味着,当代码通过所有测试并准备好发布时,自动部署到生产环境,并对外提供服务。
持续交付与持续部署各有所长。持续交付强调尽可能快地交付最新版软件,同时持续部署则是在这个过程中自动部署到生产环境。虽然两者存在重叠之处,但持续交付侧重于开发阶段的自动化流程,而持续部署侧重于运维阶段的自动化部署。无论是持续交付还是持续部署,均有助于提高软件交付的频率、质量和速度。
持续交付与持续部署的区别:
- 目的不同:持续交付是为了开发人员将软件交付到预发布环境中,而持续部署则是为了让软件直接部署到生产环境中。持续交付只是希望通过自动化构建、测试、部署等流程,更快、更高效地交付软件。
- 方法不同:持续交付通常采用多种方式,比如蓝绿部署、金丝雀发布等,而持续部署则可以采用自动化发布脚本。
- 步骤不同:持续交付一般包含多个环节,比如编码、构建、测试、打包、部署等,而持续部署则只是将部署环节自动化即可。
- 标准化程度不同:持续交付仍处于起步阶段,尚未形成统一的标准。但持续部署已得到大规模应用,是较为成熟的模式。
总结来说,持续集成和持续交付是DevOps的一个重要组成部分,是提升软件交付效率、频率和质量的有效方法。
三、CI/CD实践
在实践层面上,CI/CD由以下几个方面组成:
- CI工具链:将代码库的代码每次提交,经过自动化构建、测试、打包、部署等流程,最终生成部署包,并进行集成测试,达到代码发布的自动化流程。
- 测试环境:将部署包部署到测试环境,进行单元测试、集成测试、回归测试等。
- 预发布环境:将部署包部署到预发布环境,进行负载测试、可用性测试、兼容性测试等。
- 生产环境:将部署包部署到生产环境,进行性能测试、压力测试、安全测试等。
图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?
以下是一些常见的原因:
- 降低部署风险:在持续集成的过程中,你将部署频率降低,因为你可以确保代码每一次提交都是经过完整的测试,并且处于稳定的状态。也就是说,任何时候如果代码出现问题,你就能够立即发现,解决起来也相对容易得多。
- 提升软件质量:自动化测试覆盖范围广,而且越来越普遍,这使得开发人员可以专注于编写业务逻辑代码,而不是再花费精力去处理各种琐碎的测试事宜。同时,自动化测试可以模拟不同的用户场景,从而更加准确地找出潜在的问题。这样,你就可以及时发现和解决软件缺陷,不至于等到软件投入市场后才暴露出来。
- 减少反馈环节:由于部署频率减少,部署频繁导致的反馈环节也会减少,从而提高交付效率。不仅如此,还有自动化工具可以将测试结果及时的通知给相关的开发人员。
- 提升协作效率:对于多个开发人员,有了自动化的构建工具,他们可以互相review代码,同时也可以并行开发,彼此之间不会产生冲突,从而减少错误。这有助于提升协作效率,加快软件交付周期。
- 提升敏捷性:自动化的构建、测试以及部署流程,让团队成员可以快速响应需求变化,从而在短时间内快速反应,不断创造新的功能和产品。
- 更快、更好地迭代:由于自动化构建、测试、部署的过程,开发人员可以做更多的事情,比如处理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仓库作为代码源,并设置触发构建的条件。
- 登录Jenkins,点击“Manage Jenkins”,选择“Manage Plugins”菜单项,然后搜索“Git Plugin”并安装。
- 配置Gitlab仓库作为代码源
打开“Global Tool Configuration”页面(位于Jenkins首页的左侧导航栏),找到“Gitlab API Token”配置项,输入你的gitlab账号的api token(从gitlab网站生成)。
填写好相关信息后,点击“Test connection”按钮测试配置是否正确。 - 设置触发构建的条件
打开“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。
- 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过程中常用的插件列表:
- Git Plugin:集成Git代码托管平台,支持多种SCM,包括Git、Subversion等。
- Multijob Plugin:支持多项目同时构建,能够按顺序或并行执行多个项目的构建,支持跨项目的依赖关系。
- Docker Plugin:支持在Jenkins构建环境中,快速部署Docker镜像。
- Ansible Plugin:支持通过Ansible来远程管理机器。
- Gradle Plugin:支持通过Gradle来构建Java应用程序。
- SonarQube Scanner Plugin:集成SonarQube,支持对代码进行静态分析,支持多种编程语言。
- Github Authentication plugin:集成GitHub OAuth,支持通过GitHub账号来登录。
- Bitbucket Server / Cloud Plugin:集成Bitbucket代码托管平台,支持对Bitbucket上代码的检出。
- Google Cloud Storage Plugin:支持上传构建产物到Google云存储。
- AWS CodeCommit Plugin:集成AWS CodeCommit,支持对CodeCommit代码库的检出和上传。
- Azure Artifacts Plugin:支持上传构建产物到Azure Blob存储。
- Artifactory Plugin:支持管理外部依赖,包括Maven、npm、NuGet等。
- HTTP Request Plugin:支持发送HTTP请求,比如POST、PUT等。
- Email Extension Plugin:支持发送邮件,比如发送构建报告、通知结果等。
- Job DSL Plugin:支持定义Jenkins项目,支持在Jenkins中通过配置描述语言(Configuration-as-Code)来定义构建流程。
- Pipeline Utility Steps Plugin:提供多个Pipeline流水线函数,比如
parallel()
、stash()
等。 - OpenShift Plugin:支持在OpenShift集群上进行容器化部署。
- NodeJs Plugin:支持在Jenkins构建环境中,运行JavaScript。
- Xcode Plugin:支持在Jenkins构建环境中,编译Objective-C和Swift代码。
- Warnings Next Generation Plugin:支持显示警告信息。
- JUnit Plugin:支持生成JUnit格式的测试报告。
- Checkstyle Plugin:支持对代码进行静态分析,查找和修复代码风格问题。
- PMD Plugin:支持对代码进行静态分析,查找代码质量问题。
- Robot Framework Plugin:支持RobotFramework自动化测试。
- SSH Build Executor Plugin:支持SSH方式构建,允许构建运行在远程服务器上。
- Assembla Plugin:支持将Jenkins构建结果同步到Assembla。
- Bamboo Integration Plugin:支持与Bamboo集成。
- S3 Bucket Publisher Plugin:支持将构建产物上传到S3云存储桶。
- Atlassian Confluence Publisher Plugin:支持将Jenkins构建报告同步到Confluence。
- Slack Notifications Plugin:支持在Slack上发送通知。
- HTML Publisher Plugin:支持生成HTML格式的构建报告。
- External Monitor Job Type Plugin:支持添加第三方监控系统,比如Pingdom、New Relic、SiteScope等。
- Kubernetes Plugin:支持在Kubernetes集群上进行容器化部署。
- OWASP Dependency Check Plugin:支持对Java应用程序依赖进行扫描,并标注潜在漏洞。
- Performance plugin:支持对Java Web应用程序和移动应用程序的性能进行分析。
- AnsibleVault integration plugin:支持读取Ansible Vault加密的配置文件。
- FogBugz Integration Plugin:支持与FogBugz集成,可以进行问题跟踪和缺陷管理。
- Prometheus Plugin:支持在Prometheus上收集Jenkins的指标数据。
- Windows Batch Command Plugin:支持在Windows环境上执行批处理命令。
- Git Changelog Plugin:支持生成Changelog。
- Custom Tools Deployer Plugin:支持在Jenkins部署过程中,部署自定义工具到远程机器。
- InfluxDB Plugin:支持在InfluxDB上保存Jenkins的指标数据。
- Backup&Restore Plugin:支持备份/恢复Jenkins数据。
- Wiki Publisher Plugin:支持将构建产物上传到Wiki。
- Milestone Step Plugin:支持在Jenkins构建流水线中增加里程碑功能。
- Timestamper Plugin:支持在日志中显示时间戳。
- AMQP Plugin:支持与AMQP服务集成,通过消息队列传递事件。
- Promoted Builds Plugin:支持设置构建优先级。
- GoCD Plugin:支持与GoCD集成,支持对GoCD流水线进行构建触发。
- Gitea Branch Source Plugin:支持Gitea代码托管平台,支持Branch Sources。
- PagerDuty Integration Plugin:支持PagerDuty事件回调。
- RunDeck Integration Plugin:支持与RunDeck集成,支持Job executions events。
- Dry Unification Plugin:支持自动化处理变更,并生成合并请求。
- WildFly Swarm Plugin:支持在Jenkins构建环境中,运行Java EE应用。
- Cache Cleanup Plugin:支持清理Jenkins缓存。
- FreeStyle Project Plugin:支持添加自由风格的项目类型。
- Publish Over SSH Plugin:支持SSH协议,将构建产物通过SCP传输到远程机器。
- CloudBees AWS Credentials Plugin:支持管理AWS凭据。
- Notification Plugin:支持在各种消息渠道(比如微信、钉钉等)发送通知。
- Parameterized Trigger Plugin:支持在构建参数变化时,自动触发后续构建。
- Structured Logging Plugin:支持结构化日志输出。
- LDAP Group Plugin:支持基于LDAP的用户组管理。
- View Stash Plugin:支持在Stash中查看构建记录。
- Microsoft Team Services (VSTS) Integration Plugin:支持与VSTS集成。
- Matrix Project Plugin:支持矩阵项目构建,能够并行执行多个构建任务。
- Parallel Execution Plugin:支持并行执行构建任务。
- GitLab Hook Plugin:支持GitLab webhooks。
- GitHub Pull Request Builder Plugin:支持GitHub pull requests。
- Display URL Plugin:支持在构建日志中显示链接地址。
- Gravatar Plugin:支持Gravatar头像展示。
- JWT Claim plugin:支持获取JWT token中的claims。
- Log Parser Plugin:支持解析日志。
- Apache CloudStack Plugin:支持Apache CloudStack。
- Active Choices Plugin:支持配置Jenkins Choice参数。
- ServiceNow CMDB Integration Plugin:支持与ServiceNow CMDB集成。
- Blue Ocean Plugin:支持Blue Ocean,提供了增强的用户界面和图表展示。
- JIRA Plugin:支持与JIRA集成。
- Collaboration Feature Plugin:支持代码协同。
- Restrictedsignup Plugin:支持限制注册。
- LDAP Authorization Strategy Plugin:支持基于LDAP的授权策略。