Jenkins Pipeline 详解

梗概(20%核心概念)

PipelineJenkins 中用于定义整个构建、测试、部署流程的工具,通过代码化(Jenkinsfile)管理流程,相比传统方式更灵活且易于版本控制。

核心概念

  • Jenkinsfile:存放 Pipeline 脚本的文件,通常放在项目根目录,与代码一起纳入版本控制
  • 步骤(Step):最小执行单元,如 sh(执行 shell 命令)、git(拉取代码)、build(触发其他任务)等
  • 阶段(Stage):将流程划分为不同阶段(如”拉取代码""编译""测试""部署”),直观展示流程进度
  • 节点(Node):执行步骤的计算资源(Jenkins 主节点或代理节点)

Jenkins 基础概念

  • 流水线(Pipeline):将软件发布流程(如拉取代码、编译、测试、部署)定义为一个可执行的脚本,是Jenkins的核心功能
  • 插件(Plugins):Jenkins的功能通过插件扩展,比如Git插件用于拉取代码,Maven插件用于编译Java项目等
  • 节点(Node):执行任务的服务器,包括Jenkins自身所在的”主节点”和其他”从节点”
  • 任务(Job):Jenkins中具体的工作单元,比如一个构建任务、测试任务等,详见运维Job

详细语法与实践(80%深入内容)

Pipeline类型对比

声明式 vs 脚本式

特性声明式Pipeline脚本式Pipeline
语法结构预定义的结构化语法完全的Groovy脚本
学习难度相对简单需要Groovy知识
灵活性有限但够用完全灵活
错误处理内置错误处理需要手动处理
推荐使用大多数场景复杂逻辑场景

脚本式Pipeline核心语法

脚本式Pipeline使用更灵活的Groovy语法,适合复杂的条件逻辑和动态配置:

// 脚本式Pipeline基本结构
node('worker') {  // 指定执行节点
    try {
        // 定义变量
        def buildNumber = env.BUILD_NUMBER
        def gitCommit = ''
        
        stage('拉取代码') {
            // Git操作
            checkout scm
            gitCommit = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
            echo "Git commit: ${gitCommit}"
        }
        
        stage('构建测试') {
            parallel(  // 并行执行
                '单元测试': {
                    sh '''
                        echo "运行单元测试..."
                        mvn test
                    '''
                    
                    // 条件判断
                    def testResult = sh(returnStatus: true, script: 'mvn test')
                    if (testResult != 0) {
                        error "单元测试失败"
                    }
                },
                '代码扫描': {
                    sh '''
                        echo "执行代码质量扫描..."
                        sonar-scanner
                    '''
                }
            )
        }
        
        stage('构建部署') {
            // 动态条件判断
            if (env.BRANCH_NAME == 'main') {
                echo "主分支,执行生产部署"
                sh 'mvn package -DskipTests'
                
                // 部署到生产环境
                sh '''
                    docker build -t myapp:${BUILD_NUMBER} .
                    docker push registry.company.com/myapp:${BUILD_NUMBER}
                '''
            } else if (env.BRANCH_NAME.startsWith('feature/')) {
                echo "特性分支,部署到测试环境"
                sh 'mvn package -Ptest'
            } else {
                echo "其他分支,跳过部署"
            }
        }
        
    } catch (Exception e) {
        currentBuild.result = 'FAILURE'
        echo "构建失败: ${e.getMessage()}"
        throw e
    } finally {
        // 清理工作
        sh 'docker system prune -f'
        
        // 发送通知
        if (currentBuild.result == 'FAILURE') {
            emailext (
                subject: "构建失败: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
                body: "构建失败,请检查日志。",
                to: "${env.CHANGE_AUTHOR_EMAIL}"
            )
        }
    }
}

脚本式Pipeline的核心要素

  • node 块:必选,指定任务运行的节点(通过标签筛选),内部包含具体步骤
  • 步骤(Steps):Jenkins 提供的内置命令,如 git(拉代码)、sh(执行Shell)、bat(Windows命令)、echo(输出日志)等
  • 变量与返回值:用 def 定义变量,sh returnStatus: true 可获取命令执行结果(0为成功,非0为失败)
  • 条件判断:支持 if-else,可根据执行结果控制流程(如测试失败则终止)

基础语法(Declarative 声明式)

pipeline {
    agent any  // 在任意可用节点执行
    stages {
        stage('拉取代码') {
            steps {
                git url: 'https://github.com/xxx/xxx.git', branch: 'main'
            }
        }
        stage('编译') {
            steps {
                sh 'mvn clean compile'  // 假设是 Maven 项目
            }
        }
        stage('测试') {
            steps {
                sh 'mvn test'
            }
        }
        stage('部署') {
            steps {
                sh './deploy.sh'  // 执行部署脚本
            }
        }
    }
    post {
        success {
            echo '构建成功!'
        }
        failure {
            echo '构建失败!'
        }
    }
}

多环境部署最佳实践

1. 环境变量配置

把服务器地址、路径等配置集中管理,避免硬编码:

pipeline {
    environment {
        PROD_SERVER = 'prod.example.com'
        TEST_SERVER = 'test.example.com'
        DEPLOY_PATH = '/var/www/app'
    }
    // ...
}

2. 人工确认(input 步骤)

在生产环境前加人工确认,防止误操作:

stage('生产环境部署确认') {
    steps {
        input message: '确认部署到生产环境?', ok: '确认部署',
              parameters: [choice(choices: ['y', 'n'], description: '选择是否继续', name: 'DEPLOY_CHOICE')]
    }
}

3. 安全凭证管理(withCredentials)

Jenkins凭据功能在自动化流程中用于安全存储密码、密钥、令牌等敏感信息(如Git仓库密码、服务器SSH密钥、API令牌),避免在脚本中硬编码。

常用凭据类型

  • usernamePassword:用户名密码对
  • sshUserPrivateKey:SSH私钥
  • string:单个密钥字符串

使用示例

stage('部署到生产环境') {
    steps {
        withCredentials([sshUserPrivateKey(credentialsId: 'prod-ssh-key', keyFileVariable: 'KEY_FILE')]) {
            sh """
                scp -i \$KEY_FILE app.jar user@\$PROD_SERVER:\$DEPLOY_PATH/
                ssh -i \$KEY_FILE user@\$PROD_SERVER 'systemctl restart app'
            """
        }
    }
}

多种凭据组合使用

withCredentials([
    usernamePassword(credentialsId: 'docker-registry-creds', 
                    usernameVariable: 'DOCKER_USER', 
                    passwordVariable: 'DOCKER_PASS'),
    string(credentialsId: 'api-token', variable: 'API_TOKEN')
]) {
    sh "docker login -u \$DOCKER_USER -p \$DOCKER_PASS"
    sh "curl -H 'Authorization: Bearer \$API_TOKEN' https://api.example.com/deploy"
}

代理节点(Agent)配置

当主节点负载过高时,可配置代理节点分担任务:

  1. 主节点操作:进入”系统管理”→“节点管理”→“新建节点”,输入节点名称,选择”固定节点”
  2. 配置节点信息:填写远程工作目录(如 /opt/jenkins_agent)、标签(用于指定任务在该节点执行)、启动方式(如”通过 SSH 启动代理”,需填写代理节点的 IP、用户名、密码)
  3. 在 Pipeline 中指定节点
pipeline {
    agent { label 'test-node' }  // 仅在标签为 test-node 的节点执行
    // ...
}

实际应用场景

Java 项目自动部署到 Kubernetes

前提条件:安装 Kubernetes Plugin、Docker Plugin

核心 Pipeline 步骤

stage('构建镜像') {
    steps {
        sh 'mvn package -DskipTests'  // 打包 Jar
        sh 'docker build -t myapp:${BUILD_NUMBER} .'
        sh 'docker push registry.example.com/myapp:${BUILD_NUMBER}'  // 推送到私有仓库
    }
}
stage('部署到 K8s') {
    steps {
        sh 'kubectl set image deployment/myapp myapp=registry.example.com/myapp:${BUILD_NUMBER}'
        sh 'kubectl rollout status deployment/myapp'  // 检查部署状态
    }
}

相关概念链接