• Jenkins自动构建 CI/CD流水线学习笔记(从入门到入土,理论+示例)


    1、什么是Jenkins的流水线?

    Jenkins 流水线是一套插件,它支持实现和集成持续交付流水线到 Jenkins。流水线提供了一组可扩展的工具,用于通过流水线 DSL 将简单到复杂的交付流水线建模为“代码”。

    对Jenkins 流水线的定义被写在一个文本文件中 (成为 Jenkinsfile),该文件可以被提交到项目的源代码的控制仓库。这是"流水线即代码"的基础; 将CD 流水线作为应用程序的一部分,像其他代码一样进行版本化和审查。 创建 Jenkinsfile并提交它到源代码控制中提供了一些即时的好处:

    • 自动地为所有分支创建流水线构建过程并拉取请求。

    • 在流水线上代码复查/迭代 (以及剩余的源代码)。

    • 对流水线进行审计跟踪。

    • 该流水线的真正的源代码 [3], 可以被项目的多个成员查看和编辑。

    2、流水线语法

    Jenkinsfile 能使用两种语法进行编写 - 声明式和脚本化。

    声明式和脚本式流水线都是 DSL 语言,[1]用来描述软件交付流水线的一部分。 脚本式流水线是用一种限制形式的 Groovy 语法编写的。

    声明式和脚本化的流水线从根本上是不同的。 声明式流水线的是 Jenkins 流水线更近的特性:

    • 相比脚本化的流水线语法,它提供更丰富的语法特性,

    • 是为了使编写和读取流水线代码更容易而设计的。

    然而,写到Jenkinsfile中的许多单独的语法组件(或者 “步骤”), 通常都是声明式和脚本化相结合的流水线。

    2.1、声明式流水线

    在声明式流水线语法中, pipeline 块定义了整个流水线中完成的所有的工作。

    pipeline {
        agent any 
        stages {
            stage('Build') { 
                steps {
                    // 
                }
            }
            stage('Test') { 
                steps {
                    // 
                }
            }
            stage('Deploy') { 
                steps {
                    // 
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述
    说明:

    1. 在任何可用的代理上,执行流水线或它的任何阶段。
    2. 定义 “Build” 阶段。
    3. 执行与 “Build” 阶段相关的步骤。
    4. 定义"Test" 阶段。
    5. 执行与"Test" 阶段相关的步骤。
    6. 定义 “Deploy” 阶段。
    7. 执行与 “Deploy” 阶段相关的步骤

    2.2、脚本化流水线

    在脚本化流水线语法中, 一个或多个 node 块在整个流水线中执行核心工作。 虽然这不是脚本化流水线语法的强制性要求, 但它限制了你的流水线的在node块内的工作做两件事:

    1. 通过在Jenkins队列中添加一个项来调度块中包含的步骤。 节点上的执行器一空闲, 该步骤就会运行。

    2. 创建一个工作区(特定为特定流水间建立的目录),其中工作可以在从源代码控制检出的文件上完成。
      Caution: 根据你的 Jenkins 配置,在一系列的空闲后,一些工作区可能不会自动清理 。

    node {  
        stage('Build') { 
            // 
        }
        stage('Test') { 
            // 
        }
        stage('Deploy') { 
            // 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述
    说明:

    1. 在任何可用的代理上,执行流水线或它的任何阶段。
    2. 定义 “Build” 阶段。 stage 块 在脚本化流水线语法中是可选的。 然而, 在脚本化流水线中实现 stage 块 ,可以清楚的显示Jenkins UI中的每个 stage 的任务子集。
    3. 执行与 “Build” 阶段相关的步骤。
    4. 定义 “Test” 阶段。
    5. 执行与 “Test” 阶段相关的步骤。
    6. 定义 “Deploy” 阶段。
    7. 执行与 “Deploy” 阶段相关的步骤

    3、流水线示例

    3.1、使用声明式流水线的语法编写的 Jenkinsfile 文件

    pipeline { 
        agent any 
        stages {
            stage('Build') { 
                steps { 
                    sh 'make' 
                }
            }
            stage('Test'){
                steps {
                    sh 'make check'
                    junit 'reports/**/*.xml' 
                }
            }
            stage('Deploy') {
                steps {
                    sh 'make publish'
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述
    说明:

    1. pipeline 是声明式流水线的一种特定语法,他定义了包含执行整个流水线的所有内容和指令的 “block” 。
    2. agent是声明式流水线的一种特定语法,它指示 Jenkins 为整个流水线分配一个执行器 (在节点上)和工作区。
    3. stage 是一个描述 stage of this Pipeline的语法块。在 Pipeline syntax 页面阅读更多有关声明式流水线语法的stage块的信息。如 above所述, 在脚本化流水线语法中,stage 块是可选的。
    4. steps 是声明式流水线的一种特定语法,它描述了在这个 stage 中要运行的步骤。
    5. sh 是一个执行给定的shell命令的流水线 step (由 Pipeline: Nodes and Processes plugin提供) 。
    6. junit 是另一个聚合测试报告的流水线 step (由 JUnit plugin提供)。
    7. node 是脚本化流水线的一种特定语法,它指示 Jenkins 在任何可用的代理/节点上执行流水线 (和包含在其中的任何阶段)这实际上等效于 声明式流水线特定语法的agent

    3.2、Pipeline 各种语言示例

    3.2.1 Java:
    pipeline {
        agent { docker 'maven:3.3.3' }
        stages {
            stage('build') {
                steps {
                    sh 'mvn --version'
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    3.2.2 Node.js / JavaScript
    pipeline {
        agent { docker 'node:6.3' }
        stages {
            stage('build') {
                steps {
                    sh 'npm --version'
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    3.2.3 Python
    pipeline {
        agent { docker 'python:3.5.1' }
        stages {
            stage('build') {
                steps {
                    sh 'python --version'
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4、一套完整的Devops Jenkinsfile流水线

    本示例流水线包括以下八个阶段。
    在这里插入图片描述
    说明:

    • 阶段 1:Checkout SCM:从 GitHub 仓库检出源代码。
    • 阶段 2:单元测试:待该测试通过后才会进行下一阶段。
    • 阶段 3:SonarQube 分析:SonarQube 代码质量分析。
    • 阶段 4:构建并推送快照镜像:根据策略设置中选定的分支来构建镜像,并将 SNAPSHOT- B R A N C H N A M E − BRANCH_NAME- BRANCHNAMEBUILD_NUMBER 标签推送至 Docker Hub,其中 $BUILD_NUMBER 为流水线活动列表中的运行序号。
    • 阶段 5:推送最新镜像:将 SonarQube 分支标记为 latest,并推送至 Docker Hub。
    • 阶段 6:部署至开发环境:将 SonarQube 分支部署到开发环境,此阶段需要审核。
    • 阶段 7:带标签推送:生成标签并发布到 GitHub,该标签会推送到 Docker Hub。
    • 阶段 8:部署至生产环境:将已发布的标签部署到生产环境。
    pipeline {
      agent {
        node {
          label 'maven'
        }
    
      }
      stages {
        stage('clone code') {
          steps {
            container('maven') {
              checkout([$class: 'GitSCM', branches: [[name: '*/$BRANCH_NAME']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[url: 'https://github.com/kubesphere/devops-python-sample.git']]])
            }
    
          }
        }
    
        stage('unit test') {
          steps {
            container('maven') {
              sh 'mvn clean -o -gs `pwd`/configuration/settings.xml test'
            }
    
          }
        }
    
        stage('build & push') {
          steps {
            container('maven') {
              sh 'mvn -o -Dmaven.test.skip=true -gs `pwd`/configuration/settings.xml clean package'
              sh 'docker build -f Dockerfile-online -t $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER .'
              withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$DOCKER_CREDENTIAL_ID" ,)]) {
                sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
                sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER'
              }
    
            }
    
          }
        }
    
        stage('push latest') {
          when {
            branch 'master'
          }
          steps {
            container('maven') {
              sh 'docker tag  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest '
              sh 'docker push  $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest '
            }
    
          }
        }
    
        stage('deploy to dev') {
          steps {
            container('maven') {
              input(id: 'deploy-to-dev', message: 'deploy to dev?')
              withCredentials([kubeconfigContent(credentialsId : 'KUBECONFIG_CREDENTIAL_ID' ,variable : 'KUBECONFIG_CONFIG' ,)]) {
                sh 'mkdir -p ~/.kube/'
                sh 'echo "$KUBECONFIG_CONFIG" > ~/.kube/config'
                sh 'envsubst < deploy/dev-ol/deploy.yaml | kubectl apply -f -'
              }
    
            }
    
          }
        }
    
        stage('deploy to production') {
          steps {
            container('maven') {
              input(id: 'deploy-to-production', message: 'deploy to production?')
              withCredentials([kubeconfigContent(credentialsId : 'KUBECONFIG_CREDENTIAL_ID' ,variable : 'KUBECONFIG_CONFIG' ,)]) {
                sh 'mkdir -p ~/.kube/'
                sh 'echo "$KUBECONFIG_CONFIG" > ~/.kube/config'
                sh 'envsubst < deploy/prod-ol/deploy.yaml | kubectl apply -f -'
              }
    
            }
    
          }
        }
    
      }
      environment {
        DOCKER_CREDENTIAL_ID = 'dockerhub-id'
        GITHUB_CREDENTIAL_ID = 'github-id'
        KUBECONFIG_CREDENTIAL_ID = 'demo-kubeconfig'
        REGISTRY = 'docker.io'
        DOCKERHUB_NAMESPACE = 'docker_username'
        GITHUB_ACCOUNT = 'kubesphere'
        APP_NAME = 'devops-java-sample'
      }
      parameters {
        string(name: 'TAG_NAME', defaultValue: '', description: '')
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    在这里插入图片描述


    磨你的心智,是为了以后不管你遇见任何人和事,都能稳如泰山。


  • 相关阅读:
    Caputo 分数阶一维问题基于 L1 逼近的快速差分方法(附Matlab代码)
    如何进行JMeter分布式压测?一个案例教你详细解读!
    前端新宠 Svelte,呜呜,卷不动了
    药品研发---崩解时限检查法检验原始记录模板
    开启生态新姿势 | 使用 WrodPress 远程附件存储到 COS
    c++基础知识点总结
    C/C++ 实现:自然排序:针对两个需要排序的字符串,不仅逐个比较每个字符的顺序,对于连在一起的数字字符会作为一个完整数字进行比较 某知名企业的笔试题
    使用格式化工具处理U盘等,出现the disk is write-protected 或者 设备繁忙 的解决方法
    极智开发 | 腾讯云ECS本地开发环境搭建
    labelme做标注
  • 原文地址:https://blog.csdn.net/weixin_43025151/article/details/136624268