随着互联网软件行业快速发展,为了抢占市场先机,企业不得不持续提高软件的交付效率。特别是现在国内越来越多企业已经在逐步引入 DevOps 研发模式的变迁,在这些背景催促之下,对于企业研发团队所需要具备的持续集成和持续交付(简称 CI/CD)能力变得越来越不可或缺。
相信现在不管是开发人员、测试人员或者是运维人员,在求职招聘时,基本上如果是面试的是中高级以上的职位,大多都要求要具备相关 CI/CD 的项目建设或参与搭建经验。
为了帮助到更多技术读者,从本周起,将以《持续集成实践系列》为主题,分享几篇搭建 CI 持续集成实践的技术干货。
关于持续集成和持续交付(CI/CD)概念的介绍,之前的文章:《DevOps 研发模式下 CI/CD 实践详解指南》 中有过较详细的介绍,如果还不清楚什么是 CI/CD 的读者,可以在阅读本文前先,参考一下这篇文章。
市面上关于 CI/CD 的建设如果仅从工具、框架层面来讲,方案有挺多,如TeamCity
、GitLab CI
、Bamboo
、Circle CI
、Travis CI
、Jenkins
、公司自研
(在研发建设 CI/CD 能力时,除了 CI/CD 工具、框架链的建设外,还包括研发协同文化的建设等, 文化层面的这个不在本系列的讨论范围内)。
而在众多的持续集成 CI 建设工具体系中,Jenkins 基本上可以说是独占鳌头,也是大多数公司最常用、最首选的工具之一,占据了将近 70% 以上的市场。
而随着 Jenkins 本身的不断发展,当前 Jenkins 已演变发展到了 2.x 系列,在 Jenkins 2.x 系列中,其中最核心的特性是引入了流水线机制,并提出了流水线即代码(pipeline as code)的理念。
因此本系列也将以 Jenkins 2.x 作为《持续集成实践系列》的载体,为大家介绍在结合 Jenkins 2.x 搭建持续集成 CI 能力过程中常见的一些知识要点和实现过程。
系列大纲分为(初步拟订):
PS: 当然 Jenkins 2.x & CI 流水线的知识要点远不止如此。
Jenkins 2 本身的概念比较宽泛。在特定的上下文环境中,它用来泛指支持流水线即代码及其它类似 Jenkinsfile 等新特性的新版 Jenkins。
Jenkins 1.X 版本主要通过插件的方式来实现,确切地讲,Jenkins 2 也是通过对已有插件的重点升级和新插件的引入来获取新功能。
相比之前,用户只能通过 WEB 界面进行配置的方式来定义 Jenkins 任务,Jenkins 2 则通过使用 Jenkins DSL 和 Groovy 语言编写程序,用户可以定义流水线并执行各种任务。
这里提到的 DSL 代表领域特定语言(Domain-Specific Language),可以理解为一种适用于 Jenkins 的编程语言。DSL 基于 Grovvy 实现,并通过概念和结构封装了 Jenkins 的特定功能。
Jenkins 2 推荐使用名为 Jenkinsfile 的文件保存任务配置和流水线信息,不同的项目和分支都会有自己的 Jenkinsfile,其内容各不相同。你可以将全部代码写在一个 Jenkinsfile 中,也可以通过共享库的方式调用外部代码。
当我们通过 Jenkins 2.x 实现流水线时,有两种不同的语法样式:脚本式语法(script syntax)和声明式语法(declarative syntax)。
脚本式语法(script syntax)是 Jenkins 最开始实现流水线即代码的方式,这是一种命令式风格,在以前版本的 Jenkins 中,流水线即代码大体就是 Groovy 脚本,其中插件部分针对 Jenkins 的 DSL 步骤。这种方式几乎没有结构上的约束,程序流程也基于 Groovy 语法结构实现。
这种模式现在被称为脚本式流水线。在脚本式流水线中,DSL 支持为数众多的任务步骤,但是仍然缺失了部分面向 Jenkins 任务的核心特性,比如,构建后处理、流水线结构错误检查以及基于不同执行状态发送通知的功能。当然大多数功能都可以通过 Groovy 编程机制来模拟实现,比如 try-catch-finally 语法。但是这在面向 Jenkins 编程的基础上对 Groovy 语言技能提出了更高的要求。
而声明式语法,是 Jenkins 提供的一种新的选择,声明式风格的流水线代码被编排在清晰的段落中,相对于只关注实现逻辑。
那么有哪些因素会影响选择脚本式语法或声明式语法呢?和大多数事情一样,这也不是一个严谨的科学问题。在特定的情况下,对比需求、实现的结构和流程以及构建流水线的人员技能和背景,二者可能各有千秋。
比如,脚本式流水线具有以下优点:
但同时,脚本式流水线也具有以下缺点:
看一则简单的,脚本式流水线示例:
node("worker_node1"){
stage("Source"){
//从Git仓库中获取代码
git 'git@github.com:zhoujinjian/intelligent-test-platform.git'
}
stage("Compile"){
//运行Gradle进行编译和单元测试
sh "gradle clean comileJava test"
}
}
而声明式流水线优点有:
但如此同时,声明式流水线的缺点也很明显:
声明式流水线示例:
pipeline{
agent{
lable "worker_node1"
}
stages{
stage("Source"){
steps{
//从Git仓库中获取代码
git 'git@github.com:zhoujinjian/intelligent-test-platform.git'
}
}
stage("Compile"){
steps{
//运行Gradle进行编译和单元测试
sh "gradle clean comileJava test"
}
}
}
}
简而言之,对于新用户和那些希望流水线具备传统 Jenkins 一样可读性的用户来说,声明式流水线更容易学习和维护。脚本式流水线更加灵活,允许用户不受结构结束实现更多功能。
不过,总的来说,任何一种流水线类型对大多数场景而言同样适用。好了本文作为 CI 持续集成系列的开篇,先介绍到这里吧。
详细可查看:原文阅读