DevOps软件开发管理模式、CICD概念及其Jenkins基础
一、什么是DevOps
DevOps是Develop与Operations的缩写,是开发和运营维护的总称。它是企业内开发、技术运营和质量保障这三方面工作的融合,用于促进开发、技术运营和质保部门之间的沟通、协作与整合。为巩固软件设计与开发结果,将开发、运维与测试结合一起,形成了DevOps软件开发管理模式。
在很多企业中,应用程序发布是一项涉及多个团队、压力很大、风险很高的活动。然而在具备DevOps能力的组织中,应用程序发布的风险很低,原因如下:
- 与传统的瀑布式开发模型相比,采用敏捷或迭代式开发意味着更频繁的发布、每次发布包含的变化更少。由于部署经常进行,因此每次部署不会对生产系统造成巨大影响,应用程序会以平滑的速率逐渐生长。
- 强大的部署自动化手段确保部署任务的可重复性、减少部署出错的可能性。
- 靠强有力的发布协调人来弥合开发与运营之间的技能鸿沟和沟通鸿沟。
二、DevOps工具
DevOps鼓励开发和运营人员之间的沟通,自动化和协作,以提高最终输出的速度和质量。在DevOps中,主要阶段分为持续集成、持续交付、持续部署,不同的阶段使用不同的工具完成任务。
软件DevOps最佳的工具包括源代码存储库、构建服务器、配置管理工具、自动化测试工具、容器管理工具、监控工具等几大类,其中大部分工具都具有多种功能,具备CI/CD的功能,说明如下:
- 源代码存储库:维护着源代码的各种版本,常用工具有GIT、TFS、SVN等;
- 构建服务器:使用构建工具将源代码转换为可执行代码,常用构建工具包括Jenkins、SonarQube等;
- 配置管理工具:对服务器或环境进行配置,常用工具包括Ansible、Puppet等;
- 容器管理工具:容器化部署所需的工具,包括Docker、Kubernetes等;
- 测试工具:包括Jenkins、JMeter、Selenium、Appium等待;
- 监控工具:包括PagerDuty、Librato、Prometheus、Splunk等;
三、CI/CD概念
CI指持续集成,它属于开发人员的自动化流程,代码的更改会触发自动构建、测试和存储到源代码存储库中。CD指的是持续交付和持续部署,运维团队获取存储库中代码(交付)并进行部署。CI/CD共同实现了从开发到部署的自动化流程,以便可以频繁地向客户交付应用。CI/CD是实现敏捷开发模式最好的手段之一,简单来说只要开发人员提交代码后就会触发一系列的自动化流程,直到程序被部署。
四、Jenkins安装
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具。本文以windows版本Jenkins为例进行安装和功能介绍,详细的Jenkins使用请参考官方文档。
- 安装Jenkins:访问Jenkins官网,选择LTS版本的windows版本安装包进行下载安装,安装过程中需要选择安装位置、设置启动账户、设置访问端口。
- 访问JenkinsWeb页面:根据提示解锁Jenkins,安装推荐的插件。
- 创建管理员用户:也可以使用admin直接登录后再创建,使用admin登录后需要修改admin的密码以便下次登录。
- 配置实例URL:Jenkins URL 用于给各种Jenkins资源提供绝对路径链接的根地址。
- 中文汉化不完整的处理方法:找到Jenkins安装目录的jenkins.xml文件,在启动参数中增加 -Xmx256m -Duser.language=C.UTF-8 后重启服务。
五、jenKins目录和配置文件
在windows环境下,jenkins安装后会产生2个目录,如下第一张图是安装目录,第二张图是数据存放目录。
安装目录包含了Jenkins主程序和运行相关的配置文件及其运行日志。数据存放目录主要用于存储构建任务、插件、凭证、更新配置、用户信息等数据,这些数据在生产环境中通常需要备份。
六、Jenkins流水线
Jenkins 流水线是一套插件,它支持实现和集成 continuous delivery pipelines(持续提交流水线) 到Jenkins中,持续提交流水线CDP是一种将软件从版本控制、向用户和客户提交、经过多次变更、通过多个测试和部署阶段,到最终软件发布的可靠且可重复的自动化软件交付方法。
对Jenkins 流水线的定义被写在一个文本文件Jenkinsfile中,该文件可以被提交到项目的源代码的控制仓库。这是"流水线即代码"的基础,将CD 流水线作为应用程序的一部分,像其他代码一样进行版本化和审查。 创建 `Jenkinsfile`并提交它到源代码控制中提供了一些即时的好处:
-
自动地为所有分支创建流水线构建过程并拉取请求。
-
在流水线上代码复查/迭代 (以及剩余的源代码)。
-
对流水线进行审计跟踪。
-
该流水线的真正的源代码可以被项目的多个成员查看和编辑。
Jenkinsfile能使用声明式和脚本化两种语法进行流水线的定义 ,定义流水线需要使用流水线语法,语法的概念包括如下几部分:
- 流水线(pipeline):用户定义的一个CD流水线模型 。流水线的代码定义了整个的构建过程, 他通常包括构建, 测试和交付应用程序的阶段 。
- 节点(node):是一个机器 ,它是Jenkins环境的一部分。
- 阶段(stage):定义了流水线执行任务时的某个时间块,比如 "Build", "Test" 和 "Deploy" 阶段。
- 步骤(step):Jenkins 在特定的时间点要做一件事,比如执行shell脚本。
声明式流水线语法格式:
pipeline { //表示一个流水线,定义了整个流水线中完成的所有的工作。 agent any //定义执行环境,any表示在任何可用的代理上,执行流水线或它的任何阶段。 stages { //表示多个阶段的集合 stage('Build') { //定义 "Build" 阶段。 steps { //steps 是声明式流水线的一种特定语法,它描述了在这个 stage 中要运行的步骤。//具体步骤:比如执行给定的shell命令等。 } } stage('Test') { //定义"Test" 阶段。 steps { } } stage('Deploy') { //定义 "Deploy" 阶段。 steps { } } } }
脚本化流水线的语法格式:
node { //在任何可用的代理上,执行流水线或它的任何阶段。 stage('Build') { //定义 "Build" 阶段。 stage块在脚本化流水线语法中是可选的。 //执行与 "Build" 阶段相关的步骤。 } stage('Test') { //定义 "Test" 阶段。 //执行与 "Test" 阶段相关的步骤。 } stage('Deploy') { //定义 "Deploy" 阶段。 //执行与 "Deploy" 阶段相关的步骤。 } }
前面讲到了流水线的语法格式,那如何根据语法来定义流水线呢?方式主要有如下3种,为了更好地控制和扩展你的流水线,尤其是源代码管理系统中那些复杂的项目,建议使用 Blue Ocean 或 源码管理系统来定义你的 Jenkinsfile 文件。
- 手动编写:直接创建Jenkinsfile文本并编写流水线代码,并提交到源代码管理系统。
- BlueOcean:在 Blue Ocean 中设置一个流水线项目后,Blue Ocean UI 会帮你编写流水线的 Jenkinsfile 文件并提交到源代码管理系统。
- JenkinsUI界面编写:脚本被存储到Jenkins数据目录下的配置文件中,步骤如下:
- 新建任务,选择"流水线"选项,填写任务名称,该名称将会在Jenkins数据目录生成一个对应的文件夹,因此要求不能包含空格等特殊字符。
- 保存后进入下一步,滚动页面到流水线脚本填写的位置,选择Pipeline script 选项,将你的流水线代码输入到脚本文本区域,点击保存。
流水线的 Jenkinsfile 可以在文本编辑器或集成开发环境(IDE)中进行编写并提交到源码管理系统,可选择性地与需要 Jenkins 构建的应用程序代码放在一起,然后 Jenkins 从源代码管理系统中检出 Jenkinsfile 文件作为流水线项目构建过程的一部分并接着执行你的流水线。
要使用来自源代码管理系统的Jenkinsfile,需要在JenkinsUI界面中创建任务,选择流水线模式保存,进行下一步配置直到定义流水线选项的地方,选择模式为Pipeline script from SCM,然后设置代码仓库信息并指定Jenkinsfile文件的路径。
七、Blue Ocean介绍
Blue Ocean是Jenkins的一组插件集合,提供了一套可视化操作界面来帮助创建、编辑 Pipeline 任务。Blue Ocean特性:
- 流水线编辑器:用于创建贯穿始终的持续交付流水线,是一种直观并可视化的流水线编辑器。
- 流水线的可视化:对流水线的可视化表示,提高了全企业范围内持续交付过程的清晰度。
- 流水线的诊断:即刻定位自动化问题,无需持续扫描日志或关注多个屏幕。
- 个性化仪表盘:用户可以自定义仪表盘,只显示与自身相关的流水线。
Blue Ocean需要在Jenkins的插件管理中安装,安装完成后重启Jenkins可以在主页面找到 Blue Ocean入口图标,点击该图标即可进入其界面。
八、Jenkins流水线语法属性说明
在声明式流水线中有效的基本语句和表达式遵循与 Groovy的语法同样的规则,但有如下例外要求:
- 流水线顶层必须是一个 block:pipeline { };
- 没有分号作为语句分隔符,每条语句都必须在自己的行上;
- 块只能由 节段、指令、步骤或赋值语句组成。 *属性引用语句被视为无参方法调用。 常用属性如下:
- agent属性:指定了整个流水线或特定的部分, 将会在Jenkins环境中执行的位置,这取决于 agent 区域的位置。该部分必须在 pipeline 块的顶层被定义, 但是 stage 级别的使用是可选的。可选参数:
- any:在任何可用的代理上执行流水线或阶段。举例:agent any
- none:块的顶部没有全局代理,由每个stage自行定义。举例:agent none
- label:在提供了标签的 Jenkins 环境中可用的代理上执行流水线或阶段。举例:agent { label 'my-defined-label' }
- node:与label相同,但运行添加额外选项。
- docker:使用给定的容器执行流水线或阶段。该容器将在预置的 node上,或在匹配可选定义的`label` 参数上,动态的供应来接受基于Docker的流水线。
- dockerfile:执行流水线或阶段, 使用从源代码库包含的 Dockerfile 构建的容器。为了使用该选项, Jenkinsfile 必须从多个分支流水线中加载或者加载 "Pipeline from SCM"。
agent { docker { image 'maven:3-alpine' label 'my-defined-label' args '-v /tmp:/tmp' } }
- post属性:定义一个或多个steps ,这些阶段根据流水线或阶段的执行结果来决定steps要不要运行。可选参数如下:
- always{}:无论流水线或阶段的完成状态如何,都允许在 post 部分运行该步骤。
- changed{}:只有当前流水线或阶段的完成状态与它之前的运行不同时,才允许在 post 部分运行该步骤。
- failure{}:只有当前流水线或阶段的完成状态为"failure",才允许在 post 部分运行该步骤, 通常web UI是红色。
- success{}:只有当前流水线或阶段的完成状态为"success",才允许在 post 部分运行该步骤, 通常web UI是蓝色或绿色。
- unstable{}:只有当前流水线或阶段的完成状态为"unstable",才允许在 post 部分运行该步骤, 通常由于测试失败,代码违规等造成。通常web UI是黄色。
- aborted{}:只有当前流水线或阶段的完成状态为"aborted",才允许在 post 部分运行该步骤, 通常由于流水线被手动的aborted。通常web UI是灰色。
pipeline { agent any stages { stage('Example') { steps { echo 'Hello World' } } } post { always { echo '我总是会执行!' } failure{ echo '我在当前流水线或阶段执行失败时会执行!' } } }
- stages属性:包含一系列一个或多个 stage 指令, stages 部分是流水线描述的大部分"work" 的位置。 建议 stages 至少包含一个 stage 指令用于连续交付过程的每个离散部分,比如构建、测试和部署。
pipeline { agent any stages { stage('Example') { steps { echo 'Hello World' } } } }
- stage属性:流水线所做的所有实际工作都将封装进一个或多个 stage 指令中。
- steps属性:包含一个或多个步骤。
- environment属性:用于定义流水线运行时的环境变量。这些环境变量可以在流水线的任何阶段和步骤中使用。environment通常位于流水线定义的开始部分,紧接在pipeline指令之后。
pipeline { agent any environment { MY_VAR = "Hello, Jenkins!" ANOTHER_VAR = "This is a second variable." } stages { stage('Example') { steps { echo "The value of MY_VAR is: ${MY_VAR}" echo "The value of ANOTHER_VAR is: ${ANOTHER_VAR}" } } } }
- options属性:允许从流水线内部配置特定于流水线的选项。 流水线提供了许多这样的选项,比如 buildDiscarder,但也可以由插件提供, 比如 timestamps。可选参数如下:
- buildDiscarder:为最近的流水线运行的特定数量保存组件和控制台输出。例如: options { buildDiscarder(logRotator(numToKeepStr: '1')) }
- disableConcurrentBuilds:不允许同时执行流水线。 可被用来防止同时访问共享资源等。 例如: options { disableConcurrentBuilds() }
- overrideIndexTriggers:允许覆盖分支索引触发器的默认处理。
- skipDefaultCheckout:在`agent` 指令中,跳过从源代码控制中检出代码的默认情况。例如: options { skipDefaultCheckout() }
- skipStagesAfterUnstable:一旦构建状态变得UNSTABLE,跳过该阶段。例如: options { skipStagesAfterUnstable() }
- checkoutToSubdirectory:在工作空间的子目录中自动地执行源代码控制检出。例如: options { checkoutToSubdirectory('foo') }
- timeout:设置流水线运行的超时时间, 在此之后,Jenkins将中止流水线。例如: options { timeout(time: 1, unit: 'HOURS') }
- retry:在失败时, 重新尝试整个流水线的指定次数。 For example: options { retry(3) }
- timestamps:预谋所有由流水线生成的控制台输出,与该流水线发出的时间一致。 例如: options { timestamps() }
pipeline { agent any options { //该属性也可以用于stage中,但此时只能包括retry、timeout、timestamps等 timeout(time: 1, unit: 'HOURS') } stages { stage('Example') { steps { echo 'Hello World' } } } }
- parameters:提供了一个用户在触发流水线时应该提供的参数列表。这些用户指定参数的值可通过 params 对象提供给流水线步骤。参数类型只能为string或booleanParam。
pipeline { agent any parameters { string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '') } stages { stage('Example') { steps { echo "Hello ${params.PERSON}" } } } }
- triggers属性:定义了流水线被重新触发的自动化方法。对于集成了源( 比如 GitHub 或 BitBucket)的流水线, 可能不需要。可选参数如下:
- cron:接收 cron 样式的字符串来定义要重新触发流水线的常规间隔 ,比如: triggers { cron('H */4 * * 1-5') }
- pollSCM:接收 cron 样式的字符串来定义一个固定的间隔,在这个间隔中,Jenkins 会检查新的源代码更新。如果存在更改, 流水线就会被重新触发。例如: triggers { pollSCM('H */4 * * 1-5') }
- upstream:接受逗号分隔的工作字符串和阈值。 当字符串中的任何作业以最小阈值结束时,流水线被重新触发。例如: triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }
pipeline { agent any triggers { cron('H */4 * * 1-5') } stages { stage('Example') { steps { echo 'Hello World' } } } }
- tools属性:定义自动下载并安装的工具,并将其放到指定的Path中。常用工具有maven、jdk、gradle等。
pipeline { agent any tools { maven 'apache-maven-3.0.1' } stages { stage('Example') { steps { sh 'mvn --version' } } } }
- input属性:可以在pipeline或stage部分定义,用于实现流水线中的交互式操作。input属性允许流水线暂停并等待用户输入或响应,以便用户可以决定是否继续执行下一个阶段或中止流水线。配置参数如下:
- message:在用户提交 input 时呈现给用户,用于向用户显示提示信息,以便用户了解需要输入或响应的内容。
- id:input 的可选标识符, 默认为 stage 名称。
- ok:`input`表单上的"ok" 按钮的可选文本。
- submitter:可选的以逗号分隔的用户列表或允许提交 input 的外部组名。默认允许任何用户。
- submitterParameter:环境变量的可选名称。如果存在,用 submitter 名称设置。 parameters 提示提交者提供的一个可选的参数列表。
pipeline { agent any stages { stage('Example') { input { message "Should we continue?" ok "Yes, we should." submitter "alice,bob" parameters { string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') } } steps { echo "Hello, ${PERSON}, nice to meet you." } } } }
- when属性:允许流水线根据给定的条件决定是否应该执行阶段。 when 指令必须包含至少一个条件。 如果 when 指令包含多个条件, 所有的子条件必须返回True,阶段才能执行。 这与子条件在 allOf 条件下嵌套的情况相同。内置条件属性如下:
- branch:当正在构建的分支与模式给定的分支匹配时,执行这个阶段, 例如: when { branch 'master' }。注意,这只适用于多分支流水线。
- environment:当指定的环境变量是给定的值时,执行这个步骤, 例如: when { environment name: 'DEPLOY_TO', value: 'production' }
- expression:当指定的Groovy表达式评估为true时,执行这个阶段, 例如: when { expression { return params.DEBUG_BUILD } }
- not:当嵌套条件是错误时,执行这个阶段,必须包含一个条件,例如: when { not { branch 'master' } }
- allOf:当所有的嵌套条件都正确时,执行这个阶段,必须包含至少一个条件,例如: when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }
- anyOf:当至少有一个嵌套条件为真时,执行这个阶段,必须包含至少一个条件,例如: when { anyOf { branch 'master'; branch 'staging' } }
pipeline { agent any stages { stage('Example Build') { steps { echo 'Hello World' } } stage('Example Deploy') { when { branch 'production' } steps { echo 'Deploying' } } } }
- script属性:可以用于定义更复杂的逻辑、计算变量值、执行条件判断或循环等。它允许你在流水线中直接编写 Groovy 代码,从而提供更大的灵活性和控制力。
pipeline { agent any stages { stage('Example') { steps { echo 'Hello World' script { def browsers = ['chrome', 'firefox'] for (int i = 0; i < browsers.size(); ++i) { echo "Testing the ${browsers[i]} browser" } } } } } }
前面讲到的都是声明式流水线的使用,在脚本化流水线中,脚本化流水线从 Jenkinsfile 的顶部开始向下串行执行, 就像 Groovy 或其他语言中的大多数传统脚本一样。 因此,提供流控制取决于 Groovy 表达式,比如 if/else 条件, 例如:
node { stage('Example') { if (env.BRANCH_NAME == 'master') { echo 'I only execute on the master branch' } else { echo 'I execute elsewhere' } } } node { stage('Example') { try { sh 'exit 1' } catch (exc) { echo 'Something failed, I should sound the klaxons!' throw } } }
九、Jenkins界面主要功能
- 任务管理:提供创建管理流水线的功能。
- 系统管理:包括系统配置(全局变量、全局工具、插件、节点)、安全管理(全局安全配置、凭据、凭据提供者、登录用户管理)、状态信息、jenkins工具等几大模块。