Jenkins pipeline语法笔记

Jenkins pipeline

  • 简介
    • Jenkins Pipeline 优势
    • DSL 是什么
  • pipeline支持两种语法:
    • 声明式pipeline语法:
      • Pipeline
      • agent
    • Pipeline 声明式语法Declarative
      • environment
      • options
      • parameters
      • triggers
      • tools
      • input
      • when
      • Parallel
    • Pipeline Scripted语法
      • 创建一个简单的 Pipeline
      • 在 Slave 中构建任务
      • 流程控制
      • 部署 Kubernetes 应用
      • Declarative pipeline和Scripted pipeline的比较

简介

  • Jenkins pipeline (流水线)是一套运行于jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排与可视化。它把持续提交流水线(Continuous Delivery Pipeline)的任务集成到Jenkins中。
  • pipeline 是jenkins2.X 最核心的特性, 帮助jenkins 实现从CI到CD与DevOps的转变。
  • 持续提交流水线(Continuous Delivery Pipeline)会经历一个复杂的过程: 从版本控制、向用户和客户提交软件,软件的每次变更(提交代码到仓库)到软件发布(Release)。这个过程包括以一种可靠并可重复的方式构建软件,以及通过多个测试和部署阶段来开发构建好的软件(称为Build)。

总结:
1.Jenkins Pipeline是一组插件,让Jenkins可以实现持续交付管道的落地和实施。
2.持续交付管道(CD Pipeline)是将软件从版本控制阶段到交付给用户或客户的完
整过程的自动化表现。
3.软件的每一次更改(提交到源代码管理系统)都要经过一个复杂的过程才能被发布。

Jenkins Pipeline 优势

本质上,Jenkins 是一个自动化引擎,它支持许多自动模式。 Pipeline向Jenkins中添加了一组强大的工具, 支持简单的CI到全面的CD pipeline。通过对一系列的相关任务进行建模, 用户可以利用pipeline的很多特性:
1、代码:Pipeline以代码的形式实现,使团队能够编辑,审查和迭代其CD流程。
2、可持续性:Jenkins重启或者中断后都不会影响Pipeline Job。
3、停顿:Pipeline可以选择停止并等待人工输入或批准,然后再继续Pipeline运行。
4、多功能:Pipeline支持现实复杂的CD要求,包括循环和并行执行工作的能力。
5、可扩展:Pipeline插件支持其DSL的自定义扩展以及与其他插件集成的多个选项。

DSL 是什么

DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言(下简称 DSL);
而与 DSL相对的就是GPL,这里的GPL并不是我们知道的开源许可证,而是 General Purpose Language的简称,即通用编程语言,也就是我们非常熟悉的 Objective-C、Java、Python 以及 C 语言等等。

pipeline脚本是由groovy 语言实现的
但无需专门学习 groovy

pipeline支持两种语法:

  • Declarative:声明式
  • Scripted pipeline :脚本式

声明式pipeline语法:

官网:
https://www.jenkins.io/doc/book/pipeline/syntax/

声明式语法包括以下核心流程:
1.pipeline : 声明其内容为一个声明式的pipeline脚本
2.agent: 执行节点(job运行的slave或者master节点)
3.stages: 阶段集合,包裹所有的阶段(例如:打包,部署等各个阶段)
4.stage: 阶段,被stages包裹,一个stages可以有多个stage
5.steps: 步骤,为每个阶段的最小执行单元,被stage包裹
6.post: 执行构建后的操作,根据构建结果来执行对应的操作

根据上面流程创建一个简单的pipeline

pipeline{
    agent any
    stages{
        stage("This is first stage"){
            steps("This is first step"){
                echo "I am test"
            }
        }
    }
    post{
        always{
            echo "The process is ending"
        }
    }
}

Pipeline

Pipeline: 作用域:应用于全局最外层,表明该脚本为声明式pipeline   必写

agent

agent:作用域:可用在全局与stage内, agent表明此pipeline在哪个节点上执行 必写
agent参数:any,none, label, node,docker,dockerfile。

  • agent any 运行在任意的可用节点上
  • agent none 全局不指定运行节点,由各自stage来决定
  • agent { label ‘master’ } 运行在指定标签的机器上,具体标签名称由agent配置决定
  • node{ label ‘master’} 和agent { label ‘master’ }一样,但是node可以扩展节点信息,允许额外的选项 (比如 customWorkspace )。
agent { 
     node {
         label  'my-defined-label'
         customWorkspace 'xxxxxxx'
    } 
}

agent { docker ‘python’ } 使用指定的容器运行流水线
定义此参数时,执行Pipeline或stage时会动态的在具有label 'my-defined-label’标签的node提供docker节点去执行Pipelines。 docker还可以接受一个args,直接传递给docker run调用。

agent {
    docker {
        image 'maven:3-alpine'
        label 'my-defined-label'
        args  '-v /tmp:/tmp'
    }
}
agent {
    // Equivalent to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
    dockerfile {
        filename 'Dockerfile.build'
        dir 'build'
        label 'my-defined-label'
        additionalBuildArgs  '--build-arg version=1.0.2'
    }
}

Pipeline 声明式语法Declarative

environment

  • environment指令指定一系列键值对,这些键值对将被定义为所有step或stage-specific step的环境变量,具体取决于environment指令在Pipeline中的位置。
  • 该指令支持一种特殊的方法credentials(),可以通过其在Jenkins环境中的标识符来访问预定义的凭据。
  • 对于类型为“Secret Text”的凭据,该 credentials()方法将确保指定的环境变量包含Secret Text内容;
  • 对于“标准用户名和密码”类型的凭证,指定的环境变量将被设置为username:password并且将自动定义两个附加的环境变量:MYVARNAME_USR和MYVARNAME_PSW。

在这里插入图片描述

pipeline {
    agent any
    environment {  
        CC = 'clang' 
    }
    stages {
        stage('Example') {
            steps {
                sh 'printenv'
            }
        }
    }
}

options

options指令允许在Pipeline本身内配置Pipeline专用选项。Pipeline本身提供了许多选项,例如buildDiscarder,但它们也可能由插件提供,例如 timestamps。
在这里插入图片描述
可用选项

  • buildDiscarder: pipeline保持构建的最大个数。用于保存Pipeline最近几次运行的数据,例如:options { buildDiscarder(logRotator(numToKeepStr: ‘1’)) }
  • disableConcurrentBuilds: 不允许并行执行Pipeline,可用于防止同时访问共享资源等。例如:options { disableConcurrentBuilds() }
  • skipDefaultCheckout:跳过默认设置的代码check out。例如:options { skipDefaultCheckout() }
  • skipStagesAfterUnstable: 一旦构建状态进入了“Unstable”状态,就跳过此stage。例如:options { skipStagesAfterUnstable() }
  • timeout: 设置Pipeline运行的超时时间,超过超时时间,job会自动被终止,例如:options { timeout(time: 1, unit: ‘HOURS’) }
  • retry: 失败后,重试整个Pipeline的次数。例如:options { retry(3) }
  • timestamps: 预定义由Pipeline生成的所有控制台输出时间。例如:options { timestamps() }
pipeline {
    agent any
    options {
        timeout(time: 1, unit: 'HOURS') 
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
} 

parameters

parameters指令提供用户在触发Pipeline时的参数列表。这些参数值通过该params对象可用于Pipeline stage中,具体用法如下:
在这里插入图片描述

作用域:被最外层pipeline所包裹,并且只能出现一次,参数可被全局使用
好处:使用parameters的好处是能够使参数也变成code,达到pipeline as code,pipeline中设置的参数会自动在job构建的时候生成,形成参数化构建

可用参数

  • string :A parameter of a string type, for example: parameters { string(name: ‘DEPLOY_ENV’, defaultValue: ‘staging’, description: ‘’) }
  • booleanParam :A boolean parameter, for example: parameters { booleanParam(name: ‘DEBUG_BUILD’, defaultValue: true, description: ‘’) }
  • 目前只支持[booleanParam, choice, credentials, file, text, password, run, string]这几种参数类型,其他高级参数化类型还需等待社区支持。
pipeline{
    agent any
    parameters {
        string(name: 'xianchao', defaultValue: 'my name is xianchao', description: 'My name is xiancaho')
        booleanParam(name: 'luckylucky421302', defaultValue: true, description: 'This is my wechat')
    }
    stages{
        stage("stage1"){
            steps{
                echo "$xianchao"
                echo "$luckylucky421302"
            }
        }
    }
}

在这里插入图片描述

在这里插入图片描述

triggers

triggers指令定义了Pipeline自动化触发的方式。目前有三个可用的触发器:cron和pollSCM和upstream。
在这里插入图片描述
用域:被pipeline包裹,在符合条件下自动触发pipeline

  • cron:接受一个cron风格的字符串来定义Pipeline触发的时间间隔,例如: triggers { cron(‘H 4/* 0 0 1-5’) }
  • pollSCM:接受一个cron风格的字符串来定义Jenkins检查SCM源更改的常规间隔。如果存在新的更改,则Pipeline将被重新触发。例如:triggers { pollSCM(‘H 4/* 0 0 1-5’) }
pipeline {
    agent any
    triggers {
        cron('H 4/* 0 0 1-5')
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

tools

通过tools可自动安装工具,并放置环境变量到PATH。如果agent none,这将被忽略。
在这里插入图片描述
Supported Tools(Global Tool Configuration)

  • maven
  • jdk
  • gradle
pipeline {
    agent any
    tools {
       #工具名称必须在Jenkins 管理Jenkins → 全局工具配置中预配置。
        maven 'apache-maven-3.0.1'
    }
    stages {
        stage('Example') {
            steps {
                sh 'mvn --version'
            }
        }
    }
}

工具名称必须在Jenkins中的Manage Jenkins→Global tool Configuration下预先配置

input

stage 的 input 指令允许你使用 input step提示输入。 在应用了 options 后,进入 stage 的 agent 或评估 when 条件前,stage 将暂停。 如果 input 被批准, stage 将会继续。 作为 input 提交的一部分的任何参数都将在环境中用于其他 stage

配置项:

  • 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 "xianchao,lucky"
                parameters {
                    string(name: 'PERSON', defaultValue: 'xianchao', description: 'Who should I say hello to?')
                }
            }
            steps {
                echo "Hello, ${PERSON}, nice to meet you."
            }
        }
    }
}

在这里插入图片描述
在这里插入图片描述

when

when指令允许Pipeline根据给定的条件确定是否执行该阶段。该when指令必须至少包含一个条件。如果when指令包含多个条件,则所有子条件必须为stage执行返回true。这与子条件嵌套在一个allOf条件中相同(见下面的例子)。
更复杂的条件结构可使用嵌套条件建:not,allOf或anyOf。嵌套条件可以嵌套到任意深度。
在这里插入图片描述
内置条件

  • branch:当正在构建的分支与给出的分支模式匹配时执行,例如:when { branch ‘master’ }。请注意,这仅适用于多分支Pipeline。
  • environment:当指定的环境变量设置为给定值时执行,例如: when { environment name: ‘DEPLOY_TO’, value: ‘production’ }
  • expression: 当指定的Groovy表达式求值为true时执行,例如: when { expression { return params.DEBUG_BUILD } }
  • not:当嵌套条件为false时执行。必须包含一个条件。例如: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 {
                allOf {
                    branch 'production'
                    environment name: 'DEPLOY_TO', value: 'production'
                }
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}

Parallel

Declarative Pipeline近期新增了对并行嵌套stage的支持,对耗时长,相互不存在依赖的stage可以使用此方式提升运行效率。除了parallel stage,单个parallel里的多个step也可以使用并行的方式运行。

pipeline {
    agent any
    stages {
        stage('Non-Parallel Stage') {
            steps {
                echo 'This stage will be executed first.'
            }
        }
        stage('Parallel Stage') {
            when {
                branch 'master'
            }
            parallel {
                stage('Branch A') {
                    agent {
                        label "for-branch-a"
                    }
                    steps {
                        echo "On Branch A"
                    }
                }
                stage('Branch B') {
                    agent {
                        label "for-branch-b"
                    }
                    steps {
                        echo "On Branch B"
                    }
                }
            }
        }
    }
}

Pipeline Scripted语法

Groovy脚本不一定适合所有使用者,因此jenkins创建了Declarative pipeline,为编写Jenkins管道提供了一种更简单、更有主见的语法。
但是由于脚本化的pipeline是基于groovy的一种DSL语言,所以与Declarative pipeline相比为jenkins用户提供了更巨大的灵活性和可扩展性。

  • Node:节点,一个 Node 就是一个 Jenkins 节点,Master 或者 Agent,是执行 Step 的具体运行环境,比如我们之前动态运行的 Jenkins Slave 就是一个 Node 节点
  • Stage:阶段,一个 Pipeline 可以划分为若干个 Stage,每个 Stage 代表一组操作,比如:Build、Test、Deploy,Stage 是一个逻辑分组的概念,可以跨多个 Node
  • Step:步骤,Step 是最基本的操作单元,可以是打印一句话,也可以是构建一个 Docker 镜像,由各类 Jenkins 插件提供,比如命令:sh ‘make’,就相当于我们平时 shell 终端中执行 make 命令一样。

Pipeline 也有两种创建方法:
可以直接在 Jenkins 的 Web UI 界面中输入脚本;
也可以通过创建一个 Jenkinsfile 脚本文件放入项目源码库中
一般我们都推荐在 Jenkins 中直接从源代码控制(SCMD)中直接载入 Jenkinsfile Pipeline 这种方法

创建一个简单的 Pipeline

node {
  stage('Clone') {
    echo "1.Clone Stage"
  }
  stage('Test') {
    echo "2.Test Stage"
  }
  stage('Build') {
    echo "3.Build Stage"
  }
  stage('Deploy') {
    echo "4. Deploy Stage"
  }
}

在 Slave 中构建任务

上面创建了一个简单的 Pipeline 任务,但是可以看到这个任务并没有在 Jenkins 的 Slave 中运行,那么如何让任务跑在 Slave 中呢?
之前在添加 Slave Pod 的时候,需要用到这个 label,我们重新编辑上面创建的 Pipeline 脚本,给 node 添加一个 label 属性,如下:

node('k8stest1') {
    stage('Clone') {
      echo "1.Clone Stage"
    }
    stage('Test') {
      echo "2.Test Stage"
    }
    stage('Build') {
      echo "3.Build Stage"
    }
    stage('Deploy') {
      echo "4. Deploy Stage"
    }
}

流程控制

pipeline脚本同其它脚本语言一样,从上至下顺序执行,它的流程控制取决于Groovy表达式,如if/else条件语句,举例如下:

node {
    stage('Example') {
        if (env.BRANCH_NAME == 'master') {
            echo 'I only execute on the master branch'
        } else {
            echo 'I execute elsewhere'
        }
    }
}

部署 Kubernetes 应用

如何来部署一个原生的 Kubernetes 应用呢? 要部署 Kubernetes 应用,就得对之前部署应用的流程要非常熟悉才行,之前的流程是怎样的:

  • 编写代码
  • 测试
  • 编写 Dockerfile
  • 构建打包 Docker 镜像
  • 推送 Docker 镜像到仓库
  • 编写 Kubernetes YAML 文件
  • 更改 YAML 文件中 Docker 镜像 TAG
  • 利用 kubectl 工具部署应用

之前在 Kubernetes 环境中部署一个原生应用的流程应该基本上是上面这些流程吧?现在需要把上面这些流程放入 Jenkins 中来自动帮我们完成(当然编码除外),从测试到更新 YAML 文件属于 CI 流程,后面部署属于 CD 的流程。如果按照上面的示例,现在要来编写一个 Pipeline 的脚本。

node('k8stest1') {
    stage('Clone') {
      echo "1.Clone Stage"
    }
    stage('Test') {
      echo "2.Test Stage"
    }
    stage('Build') {
      echo "3.Build Docker Image Stage"
    }
    stage('Push') {
      echo "4.Push Docker Image Stage"
    }
    stage('YAML') {
      echo "5. Change YAML File Stage"
    }
    stage('Deploy') {
      echo "6. Deploy Stage"
    }
}

这里将一个简单 golang 程序部署到 kubernetes 环境中,代码链接:https://github.com/cnych/jenkins-demo。如果按照之前的示例,我们是不是应该像这样来编写 Pipeline 脚本:

  • 第一步,clone 代码,这个没得说吧
stage('Clone') {
    echo "1.Clone Stage"
    git url: "https://github.com/cnych/jenkins-demo.git"
}
  • 第二步,进行测试,如果测试通过了才继续下面的任务(本步骤简单忽略)
  • 第三步,由于 Dockerfile 基本上都是放入源码中进行管理的,所以我们这里就是直接构建 Docker 镜像了
stage('Build') {
    echo "3.Build Docker Image Stage"
    sh "docker build -t qienda/jenkins-demo:${build_tag} ."
}

采用和git commit的记录为镜像的 tag,这里有一个好处就是镜像的 tag 可以和 git 提交记录对应起来,也方便日后对应查看。但是由于这个 tag 不只是我们这一个 stage 需要使用,下一个推送镜像是不是也需要,所以这里把这个 tag 编写成一个公共的参数,把它放在 Clone 这个 stage 中,这样一来前两个 stage 就变成了下面这个样子:

stage('Clone') {
    echo "1.Clone Stage"
    git url: "https://github.com/cnych/jenkins-demo.git"
    script {
        build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
    }
}
stage('Build') {
    echo "3.Build Docker Image Stage"
    sh "docker build -t qienda/jenkins-demo:${build_tag} ."
}
  • 第四步,镜像打包完成,就应该推送到镜像仓库中吧

镜像构建完成了,现在就需要将此处构建的镜像推送到镜像仓库中去,直接使用 docker hub 即可。
正常来说我们在本地推送 docker 镜像的时候,需要使用docker login命令,然后输入用户名和密码,认证通过后,就可以使用docker push命令来推送本地的镜像到 docker hub 上面去了
这里的 Pipeline 是不是就该这样写了

stage('Push') {
    echo "4.Push Docker Image Stage"
    sh "docker login -u cnych -p xxxxx"
    sh "docker push cnych/jenkins-demo:${build_tag}"
}

如果只是在 Jenkins 的 Web UI 界面中来完成这个任务的话,这里的 Pipeline 是可以这样写的,但是是不是推荐使用 Jenkinsfile 的形式放入源码中进行版本管理,这样的话直接把 docker 仓库的用户名和密码暴露给别人这样很显然是非常非常不安全的,更何况这里使用的是 github 的公共代码仓库,所有人都可以直接看到源码,所以应该用一种方式来隐藏用户名和密码这种私密信息

在首页点击 Credentials -> Stores scoped to Jenkins 下面的 Jenkins -> Global credentials (unrestricted) -> 左侧的 Add Credentials:添加一个 Username with password 类型的认证信息,如下:
在这里插入图片描述
输入 docker hub 的用户名和密码,ID 部分我们输入dockerHub,注意,这个值非常重要,在后面 Pipeline 的脚本中我们需要使用到这个 ID 值。

有了上面的 docker hub 的用户名和密码的认证信息,现在我们可以在 Pipeline 中使用这里的用户名和密码了:

stage('Push') {
    echo "4.Push Docker Image Stage"
    withCredentials([usernamePassword(credentialsId: 'dockerHub', passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
        sh "docker login -u ${dockerHubUser} -p ${dockerHubPassword}"
        sh "docker push qienda/jenkins-demo:${build_tag}"
    }
}

注意这里在 stage 中使用了一个新的函数withCredentials,其中有一个 credentialsId 值就是我们刚刚创建的 ID 值,而对应的用户名变量就是 ID 值加上 User,密码变量就是 ID 值加上 Password,然后我们就可以在脚本中直接使用这里两个变量值来直接替换掉之前的登录 docker hub 的用户名和密码,现在是不是就很安全了,我只是传递进去了两个变量而已,别人并不知道我的真正用户名和密码,只有自己的 Jenkins 平台上添加的才知道。

  • 第五步,镜像推送完成,是不是需要更改 YAML 文件中的镜像 TAG 为这次镜像的 TAG

上面已经完成了镜像的打包、推送的工作,接下来更新 Kubernetes 系统中应用的镜像版本了,当然为了方便维护,用 YAML 文件的形式来编写应用部署规则,比如这里的 YAML 文件:(k8s.yaml)

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins-demo
spec:
  template:
    metadata:
      labels:
        app: jenkins-demo
    spec:
      containers:
      - image: qienda/jenkins-demo:<BUILD_TAG>
        imagePullPolicy: IfNotPresent
        name: jenkins-demo
        env:
        - name: branch
          value: <BRANCH_NAME>

该 Pod 使用的就是上面推送的镜像,唯一不同的地方是 Docker 镜像的 tag 不是平常见的具体的 tag,而是一个的标识,实际上如果将这个标识替换成上面的 Docker 镜像的 tag,是不是就是最终本次构建需要使用到的镜像?怎么替换呢?其实也很简单,使用一个sed命令就可以实现了:

stage('YAML') {
    echo "5. Change YAML File Stage"
    sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s.yaml"
    sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s.yaml"
}

上面的 sed 命令就是将 k8s.yaml 文件中的 标识给替换成变量 build_tag 的值。

  • 第六步,万事俱备,只差最后一步,使用 kubectl 命令行工具进行部署了

Kubernetes 应用的 YAML 文件已经更改完成了,之前手动部署的环境下,接使用 kubectl apply 命令就可以直接更新应用了,当然这里只是写入到了 Pipeline 里面,思路都是一样的:

stage('Deploy') {
    echo "6. Deploy Stage"
    sh "kubectl apply -f k8s.yaml"
}

这样到这里整个流程就算完成了。

  • 人工确认

理论上来说上面的6个步骤其实已经完成了,但是一般在我们的实际项目实践过程中,可能还需要一些人工干预的步骤,比如开发提交了一次代码,测试也通过了,镜像也打包上传了,但是这个版本并不一定就是要立刻上线到生产环境的,可能需要将该版本先发布到测试环境、QA 环境、或者预览环境之类的,总之直接就发布到线上环境去还是挺少见的,所以需要增加人工确认的环节,一般都是在 CD 的环节才需要人工干预,比如这里的最后两步,就可以在前面加上确认:

stage('YAML') {
    echo "5. Change YAML File Stage"
    def userInput = input(
        id: 'userInput',
        message: 'Choose a deploy environment',
        parameters: [
            [
                $class: 'ChoiceParameterDefinition',
                choices: "Dev\nQA\nProd",
                name: 'Env'
            ]
        ]
    )
    echo "This is a deploy step to ${userInput.Env}"
    sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s.yaml"
    sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s.yaml"
}

这里使用了 input 关键字,里面使用一个 Choice 的列表来让用户进行选择,然后在选择了部署环境后,当然也可以针对不同的环境再做一些操作,比如可以给不同环境的 YAML 文件部署到不同的 namespace 下面去,增加不同的标签等操作:

stage('Deploy') {
    echo "6. Deploy Stage"
    if (userInput.Env == "Dev") {
      // deploy dev stuff
    } else if (userInput.Env == "QA"){
      // deploy qa stuff
    } else {
      // deploy prod stuff
    }
    sh "kubectl apply -f k8s.yaml"
}

由于这一步也属于部署的范畴,所以可以将最后两步都合并成一步,最终的 Pipeline 脚本如下:

node('hwzx-cmp') {
    stage('Clone') {
        echo "1.Clone Stage"
        git url: "https://github.com/cnych/jenkins-demo.git"
        script {
            build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
        }
    }
    stage('Test') {
      echo "2.Test Stage"
    }
    stage('Build') {
        echo "3.Build Docker Image Stage"
        sh "docker build -t qienda/jenkins-demo:${build_tag} ."
    }
    stage('Push') {
        echo "4.Push Docker Image Stage"
        withCredentials([usernamePassword(credentialsId: 'dockerHub', passwordVariable: 'dockerHubPassword', usernameVariable: 'dockerHubUser')]) {
            sh "docker login -u ${dockerHubUser} -p ${dockerHubPassword}"
            sh "docker push qienda/jenkins-demo:${build_tag}"
        }
    }
    stage('Deploy') {
        echo "5. Deploy Stage"
        def userInput = input(
            id: 'userInput',
            message: 'Choose a deploy environment',
            parameters: [
                [
                    $class: 'ChoiceParameterDefinition',
                    choices: "Dev\nQA\nProd",
                    name: 'Env'
                ]
            ]
        )
        echo "This is a deploy step to ${userInput}"
        sh "sed -i 's/<BUILD_TAG>/${build_tag}/' k8s.yaml"
        sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' k8s.yaml"
        if (userInput == "Dev") {
            // deploy dev stuff
        } else if (userInput == "QA"){
            // deploy qa stuff
        } else {
            // deploy prod stuff
        }
        sh "kubectl apply -f k8s.yaml"
    }
}

现在 Jenkins Web UI 中重新配置 jenkins-demo 这个任务,将上面的脚本粘贴到 Script 区域,重新保存,然后点击左侧的 Build Now,触发构建,然后过一会儿就可以看到 Stage View 界面出现了暂停的情况:
在这里插入图片描述

这就是上面 Deploy 阶段加入了人工确认的步骤,所以这个时候构建暂停了,需要人为的确认下,比如这里选择 QA,然后点击 Proceed,就可以继续往下走了,然后构建就成功了,在 Stage View 的 Deploy 这个阶段可以看到如下的一些日志信息:

在这里插入图片描述

打印出来了 QA,和刚刚的选择是一致的,现在去 Kubernetes 集群中观察下部署的应用:

$ kubectl get deployment -n kube-ops
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
jenkins        1         1         1            1           7d
jenkins-demo   1         1         1            0           1m
$ kubectl get pods -n kube-ops
NAME                           READY     STATUS      RESTARTS   AGE
jenkins-7c85b6f4bd-rfqgv       1/1       Running     4          7d
jenkins-demo-f6f4f646b-2zdrq   0/1       Completed   4          1m
$ kubectl logs jenkins-demo-f6f4f646b-2zdrq -n kube-ops
Hello, Kubernetes!I'm from Jenkins CI!

可以看到应用已经正确的部署到了 Kubernetes 的集群环境中了。
到这里整个 CI/CD 的流程是不是就都完成了。

Declarative pipeline和Scripted pipeline的比较

  • 共同点:两者都是pipeline代码的持久实现,都能够使用pipeline内置的插件或者插件提供的stage,两者都可以利用共享库扩展。
  • 区别:两者不同之处在于语法和灵活性。Declarative pipeline对用户来说,语法更严格,有固定的组织结构,更容易生成代码段,使其成为用户更理想的选择。但是Scripted pipeline更加灵活,因为Groovy本身只能对结构和语法进行限制,对于更复杂的pipeline来说,用户可以根据自己的业务进行灵活的实现和扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/892839.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(38)MATLAB分析带噪信号的频谱

文章目录 前言一、MATLAB仿真代码二、仿真结果画图总结 前言 本文给出带噪信号的时域和频域分析&#xff0c;指出频域分析在处理带噪信号时的优势。 首先使用MATLAB生成一段信号&#xff0c;并在信号上叠加高斯白噪声得到带噪信号&#xff0c;然后对带噪信号对其进行FFT变换&…

数据结构:跳表

数据结构&#xff1a;跳表 跳表实现类架构构造函数析构函数查找插入删除 总代码 跳表 在传统的链表中&#xff0c;不论单链表还是双链表&#xff0c;查询时都要O(N)的时间复杂度&#xff0c;就算是一个有序链表&#xff0c;由于无法像数组一样定址&#xff0c;无法进行二分查找…

学习最新vue20.17.0-事件处理

vue中文官网事件处理 | Vue.js (vuejs.org) 我在官网基础上,添加些代码,方便初学者学习,能够快速理解官网内容,掌握自己所需要的知识,以便节省宝贵的时间。 事件处理 监听事件 我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript…

Anaconda3与PyCharm安装配置

参考文章 Anaconda3与PyCharm安装配置保姆教程 参照上面文章&#xff0c;安装好Anaconda3和PyCharm环境 下面重点记录下环境配置 1&#xff0c;在window系统菜单中选择Anaconda Prompt&#xff0c;而不是Anaconda Powershell Prompt 2, 打开Anaconda Prompt&#xff0c;输…

[网络基础]——什么是IP路由,路由优先级,度量值详解

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;网络通信基础TCP/IP专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年10月14日15点23分 路由器扮演着至关重要的角色&#xff0c;它不仅负责将数据包从源地址转发到目的地址&#xff0c;还…

wsl1升级到wsl2步骤

1、进入到windows功能界面&#xff08;winr&#xff1a;输入cmd&#xff0c;到界面里面输出control&#xff09; 这几个选项勾选上&#xff0c;然后自动重启电脑 2、下载WSL2内核安装包 前往此链接&#xff0c;然后点击下图的下载链接&#xff0c;下载这个更新包后用管理员权…

美畅物联丨剖析 GB/T 28181 与 GB 35114:视频汇聚领域的关键协议

我们在使用畅联云平台进行视频汇聚时&#xff0c;经常会用的GB/T 28181协议&#xff0c;前面我们写了关于GB/T 28181的相关介绍&#xff0c;​ 详见《畅联云平台&#xff5c;关于GB28181你了解多少&#xff1f;》。 ​最近也有朋友向我们咨询GB 35114协议与GB/T 28181有什么不同…

详细分析Redisson分布式锁中的renewExpiration()方法

目录 一、Redisson分布式锁的续期 整体分析 具体步骤和逻辑分析 为什么需要递归调用&#xff1f; 定时任务的生命周期&#xff1f; 一、Redisson分布式锁的续期 Redisson是一个基于Redis的Java分布式锁实现。它允许多个进程或线程之间安全地共享资源。为了实现这一点&…

闯关leetcode——118. Pascal‘s Triangle

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/pascals-triangle/description/ 内容 Given an integer numRows, return the first numRows of Pascal’s triangle. In Pascal’s triangle, each number is the sum of the two numbers direct…

2.Java--入门程序

一、开发Java程序 步骤&#xff1a; 1.编写代码 其中第一行的HelloWorld叫类名&#xff0c;下面的框架叫main()方法&#xff0c; 类名要和文件名一致&#xff0c; 2.编译代码 用Javac进行编译&#xff0c;将编写的代码保存之后&#xff0c;打开WindowsR输入cmd 用cd文件夹…

SPP与SPPF的区别?Anchor based和Anchor free的区别?

SPP与SPPF的区别&#xff1f; spp是何凯明提出来的&#xff0c;名为空间金子塔&#xff0c;有效避免了对图像区域的裁剪、缩放操作导致的图像失真等问题。 解决了卷积神经网络对图相关重复特征提取的问题&#xff0c;大大提高了产生候选框的速度&#xff0c;且节省了计算成本。…

razor TagHelper 汇总、HtmlHelper 汇总

Tag Helper Tag Helpers 的范围由 addTagHelper 和 removeTagHelper 进行控制&#xff0c;并且 “!” 为退出字符。 addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers // 手动高亮 asp-for 》》 Label <label asp-for"userName"></label>》》生…

九大排序之选择排序和归并排序

1.前言 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 本章重点&#xff1a; 堆排序和选择排序和归并排序 2.选择排序 基本思路 left和right记录区间的左端和右…

Opencv库的安装与vs项目配置(vs成功配置opencv库)

目录 一、下载安装opencv 1、下载 2、减压安装 3、环境变量配置 二、vs项目配置opencv 1、创建vs项目 2、配置opencv库 3、测试 其中&#xff1a;二、2、配置opencv库是最复杂的&#xff0c;有空需要搞清楚vs中配置不同地方的区别。 以下所有测试是opencv官方4.6.0 w…

差分的数学定义——由泰勒展开式推导

差分是数值分析中的概念&#xff0c;用于近似连续函数的导数。差分可以通过多种方式定义&#xff0c;一阶差分常见的有前向差分、后向差分和中心差分&#xff0c;二阶差分常用的是中心差分法。 一阶差分 1. 前向差分 (Forward Difference) 对于一个函数 f ( x ) f(x) f(x)&…

机器学习数据标准化与归一化:提升模型精度的关键

&#x1f4d8;数据标准化与归一化&#xff1a;提升模型精度的关键 机器学习中的数据处理环节至关重要&#xff0c;其中&#xff0c;数据标准化与归一化是提高模型性能的关键步骤之一。数据的特征尺度往往不一致&#xff0c;直接影响模型的训练效果&#xff0c;因此对数据进行处…

大数据开发基础实训室设备

大数据实验实训一体机 大数据实验教学一体机是一种专为大数据教育设计的软硬件融合产品&#xff0c;其基于华为机架服务器进行了调优设计&#xff0c;从而提供了卓越的性能和稳定性。这一产品将企业级虚拟化管理系统与实验实训教学信息化平台内置于一体&#xff0c;通过软硬件…

【超详细】TCP协议

TCP(Transmission Control Protocol 传输控制协议) 传输层协议有连接可靠传输面向字节流 为什么TCP是传输控制协议呢&#xff1f; 我们以前所看到的write接口&#xff0c;都是把用户级缓冲区的数据拷贝到发送缓冲区中&#xff0c;然后数据就由TCP自主决定了&#xff0c;所以…

番茄工作法计时器:高效时间管理利器

《番茄工作法计时器&#xff1a;高效时间管理利器》 在快节奏的现代生活中&#xff0c;高效管理时间成为每个人的迫切需求。今天&#xff0c;我们为你推荐一款强大的番茄工作法计时器。 这款计时器设计简洁&#xff0c;操作便捷&#xff0c;仅有两个按钮 —— 工作 25 分钟和休…

【未公开0day】RaidenMAILD CVE-2024-32399 路径穿越漏洞【附poc下载】

免责声明&#xff1a;本文仅用于技术学习和讨论。请勿使用本文所提供的内容及相关技术从事非法活动&#xff0c;若利用本文提供的内容或工具造成任何直接或间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果均与文章作者及本账号无关。 fofa语…