云原生
Kubernetes基础
容器技术介绍
Docker快速入门
Containerd快速入门
K8S主要资源罗列
认识YAML
API资源对象
Kubernetes安全掌控
Kubernetes网络
Kubernetes高级调度
Kubernetes 存储
Kubernetes集群维护
Skywalking全链路监控
ConfigMap&Secret场景应用
Kubernetes基础概念及核心组件
水平自动扩容和缩容HPA
Jenkins
k8s中部署jenkins并利用master-slave模式实现CICD
Jenkins构建过程中常见问题排查与解决
Jenkins部署在k8s集群之外使用动态slave模式
Jenkins基于Helm的应用发布
Jenkins Pipeline语法
EFKStack
EFK日志平台部署管理
海量数据下的EFK架构优化升级
基于Loki的日志收集系统
Ingress
基于Kubernetes的Ingress-Nginx解决方案
Ingress-Nginx高级配置
使用 Ingress-Nginx 进行灰度(金丝雀)发布
Ingress-nginx优化配置
APM
Skywalking全链路监控
基于Helm部署Skywalking
应用接入Skywalking
服务网格
Istio
基于Istio的微服务可观察性
基于Istio的微服务Gateway实战
Kubernetes高可用集群部署
Kuberntes部署MetalLB负载均衡器
Ceph
使用cephadm部署ceph集群
使用Rook部署Ceph存储集群
openstack
glance上传镜像失败
mariadb运行不起来
创建域和项目错误_1
创建域和项目错误_2
安装计算节点
时钟源
网络创建失败
本文档使用 MrDoc 发布
-
+
首页
Jenkins Pipeline语法
作为一种流行的持续集成和交付工具,Jenkins有多种方式来实现交付流水线。其中, Jenkins Pipeline是一种比较流行的方式,它提供了一个DSL(Domain Specific Language 的缩写,中文翻译为: 领域特定语言)来描述交付流水线。 官方:[Pipeline Syntax (jenkins.io)](https://www.jenkins.io/) # 1、什么是Jenkins Pipeline Jenkins Pipeline是一种基于Groovy编写的DSL,它可以描述交付流水线。Pipeline支持串行和并行的执行,可以将多个任务组合成一个流水线。Pipeline也支持将上下文传递给不同的阶段,使得阶段之间的数据共享变得更加容易。 **Pipeline提供了三种编写Pipeline的方式** - **Declarative Pipeline**: 是基于YAML编写的声明式语言,它可以更容易地描述交付流水线。 - **Scripted Pipeline**: 是基于Groovy编写的脚本语言,它是一种灵活的方式来描述交付流水线。 - **Jenkinsfile**: 是一种将Pipeline脚本保存为Jenkins源代码管理系统中的文件的方式。 # 2、Declarative Pipeline(声明式)流水线 ## 2.1 特点 - 最外层必须由pipline{ //do something }来进行包裹 - 不需要分号作为分隔符,每个语句必须在一行内 - 不能直接使用groovy语句(例如循环判断等),需要被script {}包裹 下面是一个简单的Pipeline脚本示例 ```yaml pipeline{ // 最外层必须由pipeline包裹 agent any // agent表示再哪个节点执行 stages{ stage("build"){ steps{ // 具体执行步骤 echo "Build..." } } stage("test"){ steps{ echo "Test..." } } stage("depoly"){ steps{ echo "Deployment..." } } } post{ // 最后执行 success{ // 测试成功时执行(需要安装 Email Extension 插件) emailext body: 'Build succeeded!', subject: 'Build Success', to: 'xx@example.com' } failure{ // 失败时会执行 emailext body: 'Build failed!', subject: 'Build Failure', to: 'xx@example.com' } } } ``` 在这个示例中,我们使用了三个阶段:build、test 和 deploy。 每个阶段都是一个stage块。在每个阶段中,我们可以使用Jenkins提供的一些API来执行任务,例如sh命令来执行shell脚本或者Jenkins提供的其他插件。 ## 2.2 声明式核心概念 - 1、pipeline: 声明其内容为一个声明式的pipeline脚本; - 2、agent: 执行节点(job运行的slave或者master节点); - 3、stages: 阶段集合,包裹所有的阶段(例如:打包,部署等各个阶段); - 4、stage: 阶段,被stages包裹,一个stages可以有多个stage; - 5、steps: 步骤,为每个阶段的最小执行单元,被stage包裹; - 6、post: 执行构建后的操作,根据构建结果来执行对应的操作; **2.1 pipeline** ```bash 作用域:应用于全局最外层,表明该脚本为声明式pipeline 是否必须:必须 参数:无 ``` **2.2 agent** ```bash 作用域:可用在全局与stage内 是否必须:是, 参数:any, none, label, node, docker, dockerfile 参考示例: //运行在任意的可用节点上 agent any //全局不指定运行节点,由各自stage来决定 agent none //运行在指定标签的机器上,具体标签名称由agent配置决定 agent { label 'master' } //node参数可以扩展节点信息 agent { node { label 'master' customWorkspace 'xxx' } } //使用指定运行的容器 pipeline{ agent none stages{ stage('build Test'){ agent {docker 'maven:3-alpine'} steps{ echo "Build Test" } } stage('Example Test'){ agent {docker 'openjdk:8-jre'} steps{ echo "Exmaple Test" } } } } ``` **2.3 stages** ```yaml 作用域:全局或者stage阶段内,每个作用域内只能使用一次 是否必须:全局必须 参数:无 参考示例: pipeline{ agent any stages{ stage("first stage"){ stages{ //嵌套在stage里 stage("inside"){ steps{ echo "inside" } } stage("inside_two"){ steps{ echo "inside_two" } } } } stage("stage2"){ steps{ echo "outside" } } } } ``` **2.4 stage** ```bash 作用域:被stages包裹,作用在自己的stage包裹范围内 是否必须:必须 参数:需要一个string参数,表示此阶段的工作内容 备注:stage内部可以嵌套stages,内部可单独制定运行的agent ``` **2.5 steps** ```bash 作用域:被stage包裹,作用在stage内部 是否必须:必须 参数:无 ``` **2.6 post(可选)** ```bash 作用域:作用在pipeline结束或者stage结束后 条件:always、changed、failure、success、unstable、aborted ``` **2.7 parameters(可选)** - 构建时用户需要提供的参数 - 这些参数可以通过params提供给流水线的steps使用,有 **字符串** 类型和 **boolean** 类型 **string**: 字符串类型,`parameters { string(name: 'DEPLOY_ENV', defaultValue: ‘staging’, description: ‘’) }` **booleanParam**: 布尔参数,`parameters { booleanParam(name: ‘DEBUG_BUILD’, defaultValue: true, description: ‘’) }` **text**: 文本参数,包含多行`parameters { text(name: ‘DEPLOY_TEXT’, defaultValue: ‘One\nTwo\nThree\n’, description: ‘’) }` **choice**: 选择类型的参数,`parameters { choice(name: ‘CHOICES’, choices: [‘one’, ‘two’, ‘three’], description: ‘’) }` **password**: password参数,`parameters { password(name: ‘PASSWORD’, defaultValue: ‘SECRET’, description: ‘A secret password’) }` 示例 ```yaml pipeline{ agent any parameters { string(name: 'P1', defaultValue: 'it is p1', description: 'it is p1') booleanParam(name: 'P2', defaultValue: true, description: 'it is p2') } stages{ stage("stage1"){ steps{ echo "$P1" echo "$P2" } } } } ``` **2.8 triggers(可选)** 自动化触发运行pipeline的方法 示例:每两分钟触发一次job ```yaml pipeline{ agent any triggers{cron("*/2 * * * *")} stages{ stage("Build Test"){ steps{ echo "hello world" } } } } ``` **2.9 input(可选)** 指令允许 **暂时中断** pipeline执行,等待用户输入,根据用户输入进行下一步动作 ```yaml pipeline { agent any stages { stage('Example') { input { message "Should we continue?" ok "Yes, Do it." 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." } } } } ``` **2.10 when(可选)** 根据when指令的判断结果来决定是否执行后面的阶段 一个when指令至少包含一个条件,当有多个条件时,所有的子条件必须返回true,这个 stage才会运行 - **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’ } }` **单条件判断:** ```yaml pipeline{ agent any parameters{ string(name:"deploy_env",defaultValue:"test",description:"") } stages{ stage("Build Test"){ when{ environment name:"deploy_env",value:"prod" } steps{ echo "hello wrold" } } } } ``` build结果: 第一次build时,deploy_env的值是 **test**,stage “Build Test” 被 skipped 第二次build时,参数deploy_env设置为 **prod**,执行 stage “Build Test” **多条件判断:** ```yaml pipeline{ agent any parameters{ string(name:"deploy_env",defaultValue:"test",description:"") string(name:"branch",defaultValue:"test",description:"分支") } stages{ stage("Build Test"){ when{ environment name:"branch",value:"master" environment name:"deploy_env",value:"prod" } steps{ echo "Hello world" } } } } ``` 需满足 branch:master,deploy_env:prod 才会执行流水线。 # 3、Scripted Pipeline(脚本式)流水线 脚本管道和声明管道一样,是建立在底层管道子系统之上的。与Declarative不同, Scripted Pipeline实际上是一个使用Groovy构建的通用DSL。 Groovy语言提供的大多数功能都可供Scripted Pipeline的方式使用,这意味着它可以是一个非常有扩展性和灵活性的工具,可以用来编写连续交付管道。 ```groovy stage('Build&Tag&Push&Deploy'){ //把选择的项目信息转为数组 def selectedProjects = "${project_name}".split(',') for(int i=0;i<selectedProjects.size();i++){ //取出每个项目的名称 def currentProjectName = selectedProjects[i]; //定义镜像名称 def imageName = "${currentProjectName}:${tag}" //定义newTag def newTag = sh(returnStdout: true,script: 'echo `date +"%Y%m%d%H%M%S"_``git describe --tags --always`').trim() //编译,构建本地镜像 sh "sed -i 's#ACTIVEPROFILE#${springProfilesActive}#g' Dockerfile" sh "mvn clean package -Dmaven.test.skip=true dockerfile:build" container('docker') { //给镜像打标签 sh "docker tag ${imageName} ${harbor_url}/${harbor_project_name}/${currentProjectName}:${newTag}" //登录Harbor,并上传镜像 withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) { //登录 sh "docker login -u ${username} -p ${password} ${harbor_url}" //上传镜像 sh "docker push ${harbor_url}/${harbor_project_name}/${currentProjectName}:${newTag}" } //删除本地镜像 sh "docker rmi -f ${imageName}" sh "docker rmi -f ${harbor_url}/${harbor_project_name}/${currentProjectName}:${newTag}" } def deploy_image_name = "${harbor_url}/${harbor_project_name}/${currentProjectName}:${newTag}" //基于Helm的方式部署到K8S container('helm3') { withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) { sh """ helm repo add --username=${username} --password=${password} aliharborrepo http://harbor-ali-test.xxxx.com:8088/chartrepo/sparkx """ } withCredentials([file(credentialsId: 'b8fca5a2-8c91-4456-99aa-071723aae7fe', variable: 'KUBECONFIG')]) { sh """ mkdir -p /root/.kube/ && echo $KUBECONFIG >/root/.kube/config echo "Helm应用配置信息确认..." helm upgrade --install --dry-run --debug ${currentProjectName} --namespace devops aliharborrepo/javaAliTest \ --set replicaCount=${replicas} \ --set image.repository=${deploy_image_name} \ --set service.type=ClusterIP \ --set springActive=${springProfilesActive} \ --set ingress.enabled=${isIngress} echo "应用部署..." helm upgrade --install ${currentProjectName} --namespace devops aliharborrepo/javaAliTest \ --set replicaCount=${replicas} \ --set image.repository=${deploy_image_name} \ --set service.type=ClusterIP \ --set springActive=${springProfilesActive} \ --set ingress.enabled=${isIngress} """ } } } } ``` # 4、Declarative pipeline和Scripted pipeline的比较 **共同点:** 两者都是pipeline代码的持久实现,都能够使用pipeline内置的插件或者插件提供的 steps,两者都可以利用共享库扩展。 **区别:** 两者不同之处在于语法和灵活性。 - Declarative pipeline:对用户来说,语法更严格,有固定的组织结构,容易生成代码段,使其成为用户更理想的选择。 - Scripted pipeline:更加灵活,因为Groovy本身只能对结构和语法进行限制,对于更复杂的pipeline来说,用户可以根据自己的业务进行灵活的实现和扩展。 # 5、优化交付流水线性能 随着交付流水线的复杂度越来越高,需要优化交付流水线的性能成为了一个时刻需要关注的问题。 下面是一些常见的优化策略: **1、并行执行** 使用并行执行可以大大缩短交付流水线的执行时间。Pipeline可以很容易地支持并行执行 例如,我们可以将测试阶段并行执行: ```yaml stage('Test') { parallel ( "test1" : { sh 'mvn test -Dtest=Test1' }, "test2" : { sh 'mvn test -Dtest=Test2' }, "test3" : { sh 'mvn test -Dtest=Test3' } ) } ``` 在这个示例中,我们使用了 **parallel块** 来并行执行。 在parallel块内,我们定义了三个分支来执行测试。分支的名称是任意的,它们将被用作日志输出。每个分支都有自己的命令来执行测试。 **2、缓存依赖项** 使用缓存可以避免在每个阶段中重新下载依赖项。 例如,如果一个项目使用Maven,我们可以在build阶段前缓存Maven仓库: ```yaml pipeline { agent any stages { stage('Build') { steps { script { def mvnHome = tool 'Maven-3.8.2' env.M2_HOME = mvnHome sh "${mvnHome}/bin/mvn -B -Dmaven.repo.local=$HOME/.m2/repository clean package" } } } } post { success { cleanWs() } } } ``` 在这个示例中,我们使用了Maven插件的tool方法来定义Maven的版本。然后,我们将M2_HOME设置为我们定义的Maven的路径。 最后,我们在Maven命令中使用-Dmaven.repo.local选项来指定Maven仓库的位置。 **3、删除不必要的阶段** 一些阶段可能不必要并且会大大降低交付流水线的性能。 例如,我们可能只需要在提交代码时执行 build 和 test 阶段,而不是在每次构建时执行这些阶段。 示例: ```yaml pipeline { agent any stages { stage('Build') { when { changeset "src/**" } steps { sh 'mvn clean install' } } stage('Test') { when { changeset "src/**" } steps { sh 'mvn test' } } stage('Deploy') { when { changeset "src/**" } steps { sh './deploy.sh' } } } post { success { cleanWs() } } } ``` 在这个示例中,我们在build、test和deploy阶段之前添加了when块。当检测到代码库 中的更改时,这些阶段才会被执行。 # 6、总结 Scripted Pipeline 和 Declarative Pipeline 两种流水线定义的主要区别在于语法和灵活性上。 Declarative Pipeline 语法要求更严,需使用 Jenkins 预定义的DSL 结构,使用简单; Scripted Pipeline 受限很少,限制主要在 Groovy 的结构和语法; 大家可以根据个人或企业的情况选择两种方式,比如如果公司没有 Groovy 技术栈,可以考虑直接使用 Declarative Pipeline, 学习曲线低,可以快速上手; 如果需要对公司的业务场景灵活配置或者对 Groovy 熟悉,那么 Scripted Pipeline 是一个不错的选择;
阿星
2024年1月27日 18:52
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码