没有理想的人不伤心

CI CD - Jenkins

2025/10/28
5
0

1 CI/CD

CI(consistent integrate)持续集成:开发人员频繁将代码提交到共享仓库(如 Git),每次提交后自动触发构建(编译、打包)和自动化测试(单元测试、集成测试),快速发现代码集成问题。

  • 核心:“频繁集成 + 自动验证”,避免代码 “积少成多” 后难以合并的问题。

CD(consistent delivery)持续交付和部署:

  • 持续交付(Continuous Delivery):在 CI 基础上,将通过测试的代码自动部署到测试 / 预生产环境,等待手动批准后部署到生产环境。核心是 “随时可发布”,保留人工最终决策。
  • 持续部署(Continuous Deployment):在持续交付基础上,去除人工批准环节,通过所有测试的代码自动部署到生产环境。核心是 “全流程自动化”,适合迭代频率高、稳定性要求高的场景(如互联网产品)。

CI/CD 是一套 “自动化软件交付流程” 的统称,核心目标是缩短开发周期、减少人工干预、提高交付质量

CI/CD 核心:根据事先设置好的条件规则,当触发这些条件后,自动执行某些任务
image.png

为什么需要自动化发布:将项目发布到多个服务器上时,需要经常性的变更配置文件等,人工发布则会产生很多的失误,阻塞需求进度。而自动化发布,可以免去人工编译、部署时可能发生的人为失误。

2 Jenkins

image.png

Jenkins 是一款开源的自动化服务器工具,核心定位是实现持续集成(CI)和持续部署(CD)流程的自动化,被广泛用于软件开发生命周期中 “构建 - 测试 - 部署” 环节的自动化管理。它的灵活性和可扩展性使其成为行业主流的 CI/CD 工具,尤其适合需要高频迭代、多环境协作的团队。

2.1 核心功能与价值

  1. 自动化 “构建 - 测试 - 部署” 全流程

传统开发中,代码提交后需要手动编译、运行测试、打包部署,效率低且易出错。Jenkins 可以通过配置 “流水线(Pipeline)”,实现从 “代码提交” 到 “生产环境部署” 的全流程自动化:

  • 例如:开发者提交代码到 Git 仓库后,Jenkins 自动触发编译(如用 Maven/Gradle 编译 Java 代码)、运行自动化测试(如 Pytest 单元测试、接口测试)、生成测试报告,若测试通过则自动打包镜像(Docker)并部署到测试 / 生产环境。
  1. 多场景适配

支持几乎所有主流开发语言(Java、Python、Go 等)、构建工具(Maven、npm、Gradle)、版本控制工具(Git、SVN)、测试工具(Jmeter、Pytest、Selenium)和部署目标(服务器、K8s、云平台),兼容性极强。

  1. 可视化与可追溯

所有流程步骤(构建日志、测试结果、部署状态)均可视化展示,便于开发者和测试人员快速定位问题(如 “哪次提交导致测试失败”“部署到哪个环境出了错”)。

2.2 核心组件与工作原理

  1. 核心架构

    • Jenkins Master:核心服务器,负责管理任务(Job)、调度流程、展示结果,是用户操作的入口(通过 Web 界面)。

    • Jenkins Agent(节点):执行实际任务的 “工作节点”(可是物理机、虚拟机或容器),Master 会将任务分配给 Agent 执行(避免 Master 负载过高)。

      例如:可以配置 “测试节点” 专门运行 JMeter 压力测试,“部署节点” 专门执行生产环境部署,实现任务隔离。

  2. 插件生态(核心优势)

    Jenkins 本身是轻量框架,功能主要通过插件扩展,目前官方插件市场有 1000+ 插件,覆盖几乎所有开发场景:

    • 版本控制:Git Plugin(拉取代码)、GitLab Plugin(关联 GitLab 仓库触发流程);
    • 构建工具:Maven Integration Plugin、NodeJS Plugin(编译前端代码);
    • 测试集成:JUnit Plugin(展示单元测试报告)、HTML Publisher Plugin(展示 Pytest/JMeter 测试报告);
    • 部署工具:Docker Plugin(打包镜像)、Kubernetes Plugin(部署到 K8s);
    • 通知工具:Email Extension Plugin(测试失败发邮件)、DingTalk Plugin(钉钉通知)。
  3. 流水线(Pipeline):定义自动化流程的 “代码”

    流水线是 Jenkins 最核心的功能,通过代码(Groovy 语法) 定义自动化流程(即 “Pipeline as Code”),流程步骤(如拉代码、编译、测试、部署)可被版本化管理(和代码一起存在 Git 仓库),支持复杂逻辑(分支判断、循环、并行执行)。

    示例(简化的测试部署流水线):

pipeline {
  agent any  // 任意节点执行
  stages {
    stage('拉取代码') {  // 阶段1:拉取Git代码
      steps {
        git url: 'https://gitlab.com/xxx/project.git', branch: 'main'
      }
    }
    stage('运行自动化测试') {  // 阶段2:执行Pytest用例
      steps {
        sh 'pip install -r requirements.txt'  // 安装依赖
        sh 'pytest test/ --html=report.html'  // 生成测试报告
      }
    }
    stage('部署到测试环境') {  // 阶段3:测试通过后部署
      when { success() }  // 仅当前面阶段成功时执行
      steps {
        sh 'docker build -t myapp:latest .'  // 打包镜像
        sh 'docker run -d -p 8080:8080 myapp:latest'  // 启动容器
      }
    }
  }
  post {  // 流程结束后操作
    failure {  // 失败时发通知
      dingtalkSend message: '测试失败,请查看Jenkins日志'
    }
  }
}

2.3 在实际工作中的典型应用场景

  1. 开发阶段:提交代码即触发测试

    配置 “Git 提交触发”:开发者 push 代码后,Jenkins 自动拉取最新代码,运行单元测试、静态代码检查(如 SonarQube),若失败则立即通知开发者(如邮件 / 钉钉),避免问题流入后续环节。

  2. 测试阶段:自动化测试与压力测试集成

    • 将 Pytest 接口测试、Selenium UI 测试集成到流水线,每次构建后自动执行,生成测试报告;
    • 定时触发 JMeter 压力测试(如每晚执行),自动收集接口响应时间、错误率等指标,超标则报警。
  3. 部署阶段:多环境自动化部署

    区分 “测试环境”“预生产环境”“生产环境” 流水线:

    • 测试环境:每次代码合并到 develop 分支自动部署;
    • 生产环境:手动点击 “确认部署” 后,执行灰度发布(先部署部分机器,验证无误后全量),降低风险。

3 常见问题解答

3.1 为什么需要 CI/CD?它解决了传统开发流程中的哪些问题?

传统开发流程(如 “瀑布式”)存在以下痛点,CI/CD 通过自动化流程解决这些问题:

  • 集成周期长,冲突难解决:传统开发中,团队成员可能几周甚至几个月才合并一次代码,导致代码冲突堆积、集成成本极高。CI 通过 “频繁提交 + 自动集成”,将冲突分散到每次提交,降低解决难度。
  • 测试滞后,质量不可控:传统流程中,测试往往在开发完成后才进行,发现问题时已接近上线,修复成本高。CI 通过 “提交后自动测试”,提前暴露 bug(如单元测试失败、代码规范问题)。
  • 部署手动化,效率低且易出错:传统部署依赖人工执行脚本(如上传包、执行 SQL),步骤繁琐、易漏操作(如某台服务器未更新)。CD 通过自动化部署流程,确保每次部署步骤一致,减少人为错误。
  • 上线周期长,响应慢:传统流程从开发完成到上线可能需要数天(等待测试、审批、部署),而 CI/CD 可将周期缩短到小时级甚至分钟级,快速响应业务需求。

3.2 Jenkins 是什么?它在 CI/CD 流程中扮演什么角色?

Jenkins 是一个开源的自动化服务器,通过插件生态支持几乎所有主流开发工具和流程,是实现 CI/CD 的核心工具。

在 CI/CD 中的角色:

  • 流程编排者:串联代码拉取、构建、测试、部署等环节(如从 Git 拉取代码→用 Maven 编译→Junit 跑测试→Docker 打包→推送到镜像仓库→部署到 K8s)。
  • 自动化执行者:替代人工执行重复操作(如定时构建、触发式测试、自动部署),支持多环境(开发、测试、生产)的差异化流程。
  • 结果反馈者:通过邮件、钉钉、Slack 等插件推送构建 / 部署结果(成功 / 失败原因),让团队快速响应问题。

3.3 Jenkins 的核心组件有哪些?各自的作用是什么?

image.png

3.4 Jenkins 中 Pipeline 是什么?为什么推荐使用 Pipeline 而非传统 Job?

Jenkins Pipeline 是用代码定义 CI/CD 流程的工具,通过Jenkinsfile(存放于项目代码仓库)描述从构建到部署的全流程,支持两种语法:

  • 声明式(Declarative):简洁、结构化,适合标准化流程(如pipeline { ... }包裹);
  • 脚本式(Scripted):灵活,支持 Groovy 脚本逻辑(如条件判断、循环)。

推荐使用 Pipeline 的原因(相比传统自由风格 Job):

  1. 版本化管理Jenkinsfile与项目代码一同存入 Git,可追踪流程变更(如谁修改了部署步骤),便于回溯。
  2. 可复用性:通过 “共享库(Shared Library)” 封装通用逻辑(如测试报告生成、部署脚本),多个项目可复用,减少重复配置。
  3. 可视化流程:Pipeline 执行过程可在 Jenkins 界面实时展示(如哪个阶段失败),便于调试。
  4. 抗故障能力:支持 “断点续跑”(如某阶段失败,修复后从该阶段继续执行),而传统 Job 失败后需重新执行全程。
  5. 复杂流程支持:轻松实现多环境部署(开发→测试→生产)、并行任务(如同时跑前端和后端测试)、条件判断(如生产环境需手动确认)等复杂场景。

3.5 用 Jenkins Pipeline 描述一个 Java 项目的 CI/CD 流程(示例)

以 “Spring Boot 项目” 为例,流程为:拉取代码→编译打包→单元测试→构建 Docker 镜像→推送到镜像仓库→部署到测试环境。对应的Jenkinsfile(声明式)如下:

pipeline {
    agent any  // 可指定在特定Agent执行(如label 'java-agent')
    environment {  // 环境变量
        GIT_REPO = 'https://github.com/xxx/springboot-demo.git'
        IMAGE_NAME = 'demo-app:${BUILD_NUMBER}'  // BUILD_NUMBER是Jenkins内置变量(构建序号)
        REGISTRY = 'harbor.xxx.com'  // 镜像仓库地址
    }
    stages {  // 流程阶段
        stage('拉取代码') {
            steps {
                git url: "${GIT_REPO}", branch: 'dev'  // 拉取dev分支代码
            }
        }
        stage('编译打包') {
            steps {
                sh 'mvn clean package -DskipTests'  // Maven编译打包(跳过测试,测试单独阶段执行)
            }
        }
        stage('单元测试') {
            steps {
                sh 'mvn test'  // 执行单元测试
            }
            post {  // 测试后动作
                always {  // 无论成功失败都执行
                    junit 'target/surefire-reports/*.xml'  // 生成测试报告
                }
            }
        }
        stage('构建Docker镜像') {
            steps {
                sh """
                    docker build -t ${IMAGE_NAME} .  // 基于项目根目录的Dockerfile构建镜像
                    docker tag ${IMAGE_NAME} ${REGISTRY}/${IMAGE_NAME}  // 打镜像仓库标签
                """
            }
        }
        stage('推送镜像到仓库') {
            steps {
                withCredentials([usernamePassword(credentialsId: 'harbor-cred', usernameVariable: 'USER', passwordVariable: 'PWD')]) {
                    // 使用凭证登录镜像仓库(harbor-cred是在Jenkins中配置的凭证ID)
                    sh "docker login -u ${USER} -p ${PWD} ${REGISTRY}"
                    sh "docker push ${REGISTRY}/${IMAGE_NAME}"
                }
            }
        }
        stage('部署到测试环境') {
            steps {
                sshagent(credentials: ['test-server-ssh']) {  // 使用SSH凭证连接测试服务器
                    sh """
                        ssh root@test.xxx.com '
                            docker pull ${REGISTRY}/${IMAGE_NAME} && 
                            docker stop demo-app || true && 
                            docker rm demo-app || true && 
                            docker run -d --name demo-app -p 8080:8080 ${REGISTRY}/${IMAGE_NAME}
                        '
                    """
                }
            }
        }
    }
    post {  // 整个Pipeline结束后动作
        success {
            emailext to: 'dev@xxx.com', subject: '构建成功', body: 'CI/CD流程已完成,测试环境已更新'
        }
        failure {
            emailext to: 'dev@xxx.com', subject: '构建失败', body: '请查看Jenkins日志排查问题'
        }
    }
}

3.6 Jenkins 的 Master 和 Agent 有什么区别?为什么需要 Agent?

Jenkins 的节点分为 Master 和 Agent,两者分工不同:

  • Master(主节点)

    负责核心管理工作:接收任务请求、解析 Pipeline、调度任务到 Agent、展示构建结果、管理插件和凭证等。

    不建议直接执行构建任务(避免因资源消耗影响自身稳定性)。

  • Agent(从节点)

    负责实际执行构建 / 部署任务(如编译代码、跑测试、打包镜像),由 Master 分配任务。可在不同机器上部署(如 Windows、Linux、Docker 容器),支持按标签(Label)分类(如java-agentnodejs-agent),便于任务按需分配。

需要 Agent 的原因

  1. 分担 Master 负载:构建任务(如编译大型项目、跑大量测试)消耗 CPU / 内存,Agent 可避免 Master 因资源不足卡顿。
  2. 适配多环境需求:不同项目可能依赖不同环境(如 Java 8 vs Java 11、Windows vs Linux),Agent 可按需配置环境,互不干扰。
  3. 提高并行能力:多个 Agent 可同时执行不同任务(如同时构建前端和后端项目),提升 CI/CD 效率。

3.7 如何保证 Jenkins 构建过程的安全性?

Jenkins 涉及代码、凭证、服务器权限等敏感信息,需从多维度保障安全:

  1. 凭证管理

    • 所有敏感信息(如 Git 密码、服务器 SSH 密钥、API 令牌)通过 Jenkins “凭证” 功能存储(加密存储,非明文),在 Pipeline 中通过withCredentials引用,避免硬编码。
  2. 权限控制

    • 启用 “矩阵授权策略” 或 “基于角色的访问控制(RBAC)” 插件,按角色分配权限(如开发仅能查看 / 触发自己的项目,管理员可配置节点和凭证)。
    • 限制匿名用户权限(如禁止匿名访问)。
  3. 节点安全

    • Agent 与 Master 通信使用加密连接(默认启用),避免数据传输被窃听。
    • Agent 节点最小化权限(如仅授予执行构建所需的权限,不赋予服务器 root 权限)。
  4. 代码安全

    • 集成代码扫描工具(如 SonarQube 插件),在构建阶段检测代码漏洞、规范问题,阻止不安全代码进入后续流程。
  5. 插件与版本安全

    • 仅安装必要插件,定期更新插件和 Jenkins 版本(修复已知安全漏洞),避免使用来源不明的插件。

3.8 当 Jenkins 构建失败时,如何排查问题?

构建失败是 CI/CD 中的常见场景,排查步骤通常为:

  1. 查看构建日志

    进入 Jenkins 对应构建的 “控制台输出”,定位失败阶段(如编译失败、测试失败、部署超时),重点关注错误信息(如mvn compile报错 “依赖缺失”、docker run报错 “端口被占用”)。

  2. 检查环境一致性

    • 本地复现:在本地执行相同命令(如mvn package),确认是否因本地与 Agent 环境差异导致(如依赖版本、JDK 版本不同)。
    • 工作空间检查:通过 Agent 的 “工作空间” 查看拉取的代码、构建产物是否正确(如是否拉取了正确分支、打包的 JAR 是否存在)。
  3. 验证依赖与配置

    • 依赖问题:如 Maven 仓库无法访问、npm 包下载失败(检查网络、仓库地址配置)。
    • 凭证问题:如 Git 拉取失败(检查凭证是否过期)、镜像仓库登录失败(验证账号密码是否正确)。
  4. 调试 Pipeline

    • 若为 Pipeline 任务,可在失败阶段添加sh 'pwd'sh 'ls'等命令打印信息,或使用input步骤暂停流程,手动检查中间状态。
    • 简化流程:暂时注释部分步骤(如跳过部署,仅测试构建和测试阶段),逐步定位问题环节。
  5. 查看系统资源

    若构建超时或无响应,检查 Agent 节点的 CPU、内存、磁盘空间(如磁盘满导致无法写入文件,内存不足导致 JVM 崩溃)。

3.9 还有哪些主流的 CI/CD 工具

image.png