CI/CD — Pipeline的使用以及Blue Ocean多分支流水线的使用方法

发布于:2025-07-05 ⋅ 阅读:(14) ⋅ 点赞:(0)

Pipeline简介

CI/CD Pipeline(持续集成 / 持续部署流水线)是现代软件开发中的核心实践,通过自动化工具实现代码的快速迭代和可靠交付。以下是其核心概念、工具链和典型使用场景:

(一)CI/CD Pipeline 核心概念

1. CI(持续集成)
  • 目标:频繁将代码集成到主干分支,并通过自动化测试确保代码质量。
  • 关键步骤
    • 开发者提交代码到版本库(如 Git)。
    • CI 服务器(如 Jenkins、GitLab CI)检测到代码变更,触发自动化构建和测试。
    • 执行单元测试、集成测试、代码静态分析(如 SonarQube 检测代码质量)。
    • 生成测试报告,若所有测试通过,则将代码合并到主干。
2. CD(持续交付 / 部署)
  • 持续交付:自动将通过测试的代码部署到预生产环境,但需人工确认后才能发布到生产环境。
  • 持续部署:完全自动化,代码通过测试后直接部署到生产环境(适合对发布频率要求极高的场景,如互联网产品)。
  • 关键步骤
    • 自动打包应用(如 Docker 镜像)。
    • 部署到测试环境、预生产环境、生产环境。
    • 执行冒烟测试、性能测试等验收测试。

(二)CI/CD Pipeline 工具链

1. 代码管理
  • Git:分布式版本控制系统,配合 GitHub、GitLab 或 Bitbucket 托管代码。
2. CI 工具
  • Jenkins:开源自动化服务器,支持插件扩展,适合复杂场景。
  • GitLab CI/CD:GitLab 内置的 CI/CD 工具,与 GitLab 无缝集成,配置简单。
  • GitHub Actions:GitHub 官方 CI/CD 服务,基于 YAML 配置,适合中小型项目。
  • CircleCI:云原生 CI/CD 平台,支持并行执行任务,提升效率。
3. CD 工具
  • Docker:容器化技术,确保应用环境一致性。
  • Kubernetes:容器编排平台,自动化部署、扩展和管理容器。
  • Ansible:自动化配置管理工具,通过 SSH 执行命令,无需 Agent。
  • Terraform:基础设施即代码(IaC)工具,管理云资源(如 AWS、Azure)。
4. 测试工具
  • JUnit(Java)、Pytest(Python):单元测试框架。
  • Selenium:自动化 UI 测试工具。
  • JMeter:性能测试工具。
5. 监控与反馈
  • Prometheus + Grafana:监控系统性能指标。
  • Sentry:捕获应用异常和错误。

(三)典型使用场景

1. Web 应用开发
  • 场景:前后端分离的 Web 应用,要求快速迭代。
  • Pipeline 示例

    plaintext

    代码提交 → 触发CI → 安装依赖 → 前端构建(npm build) → 后端测试(单元测试) → 
    打包Docker镜像 → 部署到测试环境 → 自动化UI测试 → 部署到预生产环境 → 
    人工审核 → 部署到生产环境
    
2. 微服务架构
  • 场景:多个独立服务协同工作,每个服务需独立部署。
  • 挑战:服务间依赖管理、分布式测试。
  • 解决方案
    • 每个微服务有独立的 CI/CD Pipeline。
    • 使用服务发现工具(如 Consul、Nacos)管理服务注册与发现。
    • 通过容器编排平台(Kubernetes)统一部署和调度。
3. 移动应用开发
  • 场景:iOS/Android 应用的持续集成与分发。
  • Pipeline 示例

    plaintext

    代码提交 → 触发CI → 单元测试 → 代码扫描(如Android Lint、SwiftLint) → 
    打包APK/IPA → 上传到测试平台(如Firebase Test Lab) → 
    分发给测试团队(如TestFlight、Google Play内部测试)
    

(四)实战案例:GitLab CI/CD 配置示例

假设开发一个 Python Flask 应用,以下是.gitlab-ci.yml配置文件:

 

yaml

stages:
  - test
  - build
  - deploy

# 测试阶段
test:
  image: python:3.9
  stage: test
  script:
    - pip install -r requirements.txt
    - pytest tests/  # 执行单元测试
    - flake8 app/   # 代码风格检查

# 构建阶段(打包Docker镜像)
build:
  image: docker:latest
  stage: build
  services:
    - docker:dind  # Docker-in-Docker服务
  script:
    - docker build -t my-flask-app:$CI_COMMIT_SHA .
    - docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
    - docker push my-flask-app:$CI_COMMIT_SHA

# 部署阶段(示例:部署到Kubernetes)
deploy:
  image: bitnami/kubectl:latest
  stage: deploy
  script:
    - kubectl config set-cluster my-cluster --server=$K8S_SERVER --certificate-authority=$K8S_CA
    - kubectl config set-credentials my-user --token=$K8S_TOKEN
    - kubectl config set-context my-context --cluster=my-cluster --user=my-user
    - kubectl config use-context my-context
    - kubectl apply -f k8s/deployment.yaml
    - kubectl set image deployment/my-app my-app=my-flask-app:$CI_COMMIT_SHA
  only:
    - main  # 仅在main分支触发部署

(五)最佳实践

  1. 小步提交,频繁集成:避免长时间开发后一次性合并大量代码。
  2. 快速失败原则:在 Pipeline 早期(如单元测试)捕获错误,减少后续步骤的浪费。
  3. 环境一致性:使用 Docker 等容器技术确保开发、测试、生产环境一致。
  4. 监控与回滚机制:部署后监控应用性能,异常时自动回滚。
  5. 安全性检查:在 Pipeline 中集成安全扫描(如 OWASP Dependency-Check 检测依赖漏洞)。

(六)常见问题与解决方案

问题 解决方案
测试环境与生产环境不一致 使用 Docker 容器化部署
部署失败导致服务中断 采用蓝绿部署、金丝雀发布等策略
Pipeline 执行时间过长 并行执行无关任务、缓存依赖
测试覆盖率不足 强制要求测试覆盖率(如 80% 以上)
 

通过合理设计 CI/CD Pipeline,团队可显著提升开发效率、减少人为错误,并实现快速迭代和高质量交付

一、Pipeline参考文档

Jenkins使用介绍:https://www.w3cschool.cn/jenkins/jenkins-epas28oi.html

Jenkins 中文社区 - Jenkins 中文社区

二、创建Pipeline流水线

1、创建一个Pipeline流水线

2、Pipeline语法构成 

3、自动生成groove语言的步骤拉取代码步骤的语法

3.1、点击进入流水线语法

 

3.2、构建需要提前安装maven环境在Pipeline的tools方法中要引用

在脚本中的定义如下:

pipeline {
    agent any
    tools {
        maven "maven3" 
    }
    stages {
        stage('拉取代码...') {
            steps {
                echo "拉取成功!!!"
            }
        }
        stage('进行构建...') {
            steps {
                sh "mvn  --version"
                echo '构建成功'
            }
        }
    }
}

3.2、生成拉取git代码的脚本步骤 

步骤一:添加拉取代码分支的url信息

步骤二:添加拉取代码的凭证(用户名密码)

步骤三:生成流水线脚本

步骤四:生成的结果粘贴到Pipeline脚本中

pipeline {
    agent any
    tools {
        maven "maven3" 
    }
    stages {
        stage('拉取代码...') {
            steps {
                git branch: 'main', url: 'http://192.168.72.130:9080/root/java-project.git'
            }
        }
        stage('进行构建...') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

步骤五:测试

4、使用maven构建代码

        stage('进行构建...') {
            steps {
                sh """
                   cd HelloWorld           #进入到代码所在的目录
                   mvn clean package
                """
                echo '构建成功!!!'
            }
        }

注意事项如下: 

这里的要在程序的主目录下进行mvn clean的操作

5、自动生成Publish over SSH远程传送jar到测试服务器上的脚本步骤

5.1、配置Publish over SSH远程ssh的机器的信息

5.2、生成Publish over SSH 的pipeline语法


 

 6、解决Pipeline自动生成语法中有一个命令导致构建失败的方法

6.1、报错原因 

在Pipeline中多个命令执行,如果前面的命令执行失败就会报错,将不会执行后边的命令,导致发布失败,具体现象如下:

 

6.2、报错现象

在pipeline执行构建时出现如下报错:

ERROR: Exception when publishing, exception message [Exec exit status not zero. Status [125]]

6.3、解决方法:执行多条命令时要加上判断条件提高执行的成功率

解决方法:多条命令需要加判断条件,以确保每条命令都能成功运行。

如:

把
docker rm -f $(docker ps |grep helloworld|awk '{print $1}')
docker rmi -f helloworld
docker build -t helloworld .
docker run -d --name helloworld -p 8989:8989 helloworld

改成:

# 使用更健壮的容器和镜像清理逻辑
if docker ps -a | grep -q helloworld; then
    docker rm -f helloworld || true  # 忽略删除失败(如容器已停止)
fi

if docker images | grep -q helloworld; then
    docker rmi -f helloworld || true  # 忽略删除失败
fi

# 构建并运行容器,添加错误检查
docker build -t helloworld . || { echo "构建失败"; exit 1; }
docker run -d --name helloworld -p 8989:8989 helloworld || { echo "运行容器失败"; exit 1; }

7、完整的Pipeline流水线脚本样例

添加之后的pipeline脚本如下:

pipeline {
    agent any
    tools {
        maven "maven3" 
    }
    stages {
        stage('拉取代码...') {
            steps {
                git branch: 'main', url: 'http://192.168.72.130:9080/root/java-project.git'
                echo "拉取成功!!! $pwd"
            }
        }
        stage('进行构建...') {
            steps {
                //sh "mvn  --version"
                sh """
                   cd HelloWorld
                   mvn clean package
                """
                echo '构建成功!!!'
            }
        }
        stage('上传服务到测试环境...') {
            steps {
                //sh "mvn  --version"
                sshPublisher(publishers: [sshPublisherDesc(configName: '测试服务器连接', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'javafile', remoteDirectorySDF: false, removePrefix: 'HelloWorld/target', sourceFiles: '**/target/*.jar'), sshTransfer(cleanRemote: false, excludes: '', execCommand: '''if docker ps -a | grep -q helloworld; then
    docker rm -f helloworld || true  # 忽略删除失败(如容器已停止)
fi

if docker images | grep -q helloworld; then
    docker rmi -f helloworld || true  # 忽略删除失败
fi

docker build -t helloworld . || { echo "构建失败"; exit 1; }
docker run -d --name helloworld -p 8989:8989 helloworld || { echo "运行容器失败"; exit 1; }''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/', remoteDirectorySDF: false, removePrefix: ' HelloWorld/docker', sourceFiles: '**/dockerfile')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                echo '容器启动成功!!!'
            }
        }
    }
}

8、进行构建测试

8.1、进行构建测试

8.2、查看容器是否成功运行

8.3、在浏览器上进行访问 

在浏览器上进行验证: http://192.168.72.132:8989/hello

二、Jenkins BlueOcean使用

1、Jenkins BlueOcean参考文档

Jenkins中文文档_w3cschool参考文档:Jenkins中文文档_w3cschool

2、Blue Ocean概述

Blue Ocean 是 Jenkins 生态中一款专注于优化 CI/CD 流程可视化与用户体验的插件,其核心作用在于将复杂的持续集成 / 持续部署过程转化为直观、交互式的界面,帮助开发团队更高效地管理和监控流水线(Pipeline)。以下是其具体功能与价值的详细解析:

2.1、可视化流水线管理

Blue Ocean 最显著的作用是通过图形化界面展示流水线的完整生命周期,将传统的文本日志转化为可视化流程。具体包括:

  1. 流水线拓扑图
    • 以流程图形式展示流水线的各个阶段(如构建、测试、部署)及其依赖关系,直观呈现执行顺序和并行任务。
    • 示例:

      plaintext

      [检出代码] → [编译] → [单元测试] → [集成测试] → [部署预发环境] → [人工确认] → [部署生产环境]  
      
  2. 实时状态监控
    • 用颜色标识任务状态(绿色 / 成功、红色 / 失败、黄色 / 暂停),点击节点可查看详细日志和错误信息,减少排查问题的时间。
2.2、简化分支与合并请求管理

针对 Git 分支和合并请求(MR)的场景,Blue Ocean 提供专属功能:

 
  1. 分支可视化对比
    • 展示不同分支的差异点和流水线执行结果,帮助开发者快速判断分支是否可合并。
  2. MR 流水线关联
    • 自动为每个 MR 生成独立流水线,显示代码变更的测试结果和部署状态,避免因未经验证的代码合并导致问题。
  3. 冲突解决辅助
    • 可视化展示代码冲突位置,支持直接在界面中解决冲突并触发重新构建。
2.3、交互式用户体验优化

Blue Ocean 打破了 Jenkins 传统界面的复杂性,通过交互设计提升使用效率:

 
  1. 流水线导航与回溯
    • 支持通过界面直接跳转至历史构建版本,查看不同版本的变更和执行记录。
  2. 人工干预节点
    • 在流水线中设置需要人工确认的节点(如部署生产环境前的审批),通过界面按钮快速完成操作,无需命令行或额外工具。
  3. 响应式设计
    • 适配不同设备屏幕,移动端也可便捷查看流水线状态,适合远程协作场景。
2.4、集成与扩展能力

Blue Ocean 可与主流开发工具和 CI/CD 生态集成,增强整体流程效率:

 
  1. 代码仓库集成
    • 无缝对接 GitLab、GitHub、Bitbucket 等平台,自动同步分支和 MR 信息。
  2. 插件生态兼容
    • 支持与 Jenkins 现有插件(如 SonarQube、JUnit)集成,在界面中展示代码质量、测试覆盖率等指标。
  3. 自定义流水线配置
    • 通过可视化编辑器或直接编辑 Jenkinsfile 定义流水线逻辑,降低新手使用门槛。
2.5、团队协作与流程标准化

Blue Ocean 通过透明化的流程展示,促进团队协作和规范落地:

 
  1. 责任明确化
    • 每个流水线节点的执行者和状态一目了然,便于追踪问题责任方。
  2. 流程标准化
    • 提供模板化流水线配置,确保团队遵循统一的 CI/CD 规范(如代码评审、测试必过等)。
  3. 知识共享
    • 新人可通过可视化界面快速理解项目的集成流程,减少学习成本。
2.6、与传统 Jenkins 的对比
功能维度 传统 Jenkins Blue Ocean
界面交互 文本列表为主,操作繁琐 图形化流程,支持拖拽和点击操作
分支管理 需手动配置分支策略 自动关联 MR,可视化分支对比
错误排查 日志文本冗长,定位困难 节点级错误高亮,直接查看详情
团队协作 缺乏直观的协作功能 支持审批节点和任务分配
2.7、应用场景举例
  • 敏捷开发团队:快速迭代中需要频繁构建和部署,Blue Ocean 的可视化流程可加速问题定位。
  • 跨部门协作项目:非技术人员可通过界面了解部署进度,减少沟通成本。
  • 复杂微服务架构:多服务流水线并行执行,通过拓扑图清晰展示依赖关系。
2.8、总结

Blue Ocean 的核心作用是将 Jenkins 的强大 CI/CD 能力与现代化用户体验结合,通过可视化、交互性和集成性,帮助团队更高效地管理软件开发流程,降低沟通和运维成本,尤其适合追求流程透明化和效率提升的开发团队。

3、安装Blue Ocean插件

3.1、安装出现报错,提示Jenkins版本过低

 

3.2、查看现在版本的Jenkins

java -jar jenkins.war --version

4、Jenkins版本升级以适配Blue Ocean版本

4.1、在官网下载Jenkins的war包

官网下载连接:Download and deploy

4.2、替换之前的war包,开启Jenkins

#执行脚本开启Jenkins服务
#!/bin/bash
TIME=$(date +"%Y-%m-%d %H:%M:%S")
JENK_PATH=/opt/devops/jenkins
JENK_LOG=/opt/devops/jenkins/logs/jenkins.log

Main ()
{
    echo "

>>>>>>>>>>>>>>>>>Jenkins start:${TIME}<<<<<<<<<<<<<<<<<<<
" >> ${JENK_LOG}
    java -jar ${JENK_PATH}/jenkins.war >>${JENK_LOG} 2>>${JENK_LOG} &
}
Main

4.3、重新加载Jenkins页面,更新Bule Ocean插件

5、Blue Ocean使用

单独点击发布到测试环境的步骤:

三、通过Blue Ocean多分支流水线

1、创建流水线

2、填写拉取Git仓库的URL,以及对于的认证信息 

3、没有Jenkinsfile文件导致同步报错问题的解决方法

3.1、显示没有找到Jenkinsfile文件

3.2、创建Jenkinsfile

3.3、执行"立即扫描 多分支流水线"

3.3.1、流水线中没有配置拉取代码的认证信息导致报错

 

 3.3.2、填写相关的认证信息

3.3.3、再次执行"立即扫描 多分支流水线"

    3.4、取不到Jenkinsfile文件解决方法

     3.4.1、选择配置更改获取Jenkinsfile的路径

    默认和程序主目录同级所以不能拉取到自定义的路径,故需要修改。

     

    3.4.2、再次执行"立即扫描 多分支流水线"

     4、对已经同步到的两条流水线分支进行构建

    4.1、Jenkins分支url配置写错导致拉取不到代码报错

    > git rev-parse --resolve-git-dir /root/.jenkins/workspace/test_main/.git # timeout=10

    Fetching changes from the remote Git repository

    > git config remote.origin.url http://192.168.72.130:9080/gitlab-instance-d4dfee6e/test.git # timeout=10

    Fetching upstream changes from http://192.168.72.130:9080/gitlab-instance-d4dfee6e/test.git

    > git --version # timeout=10

    > git --version # 'git version 1.8.3.1'

    > git fetch --tags --progress http://192.168.72.130:9080/gitlab-instance-d4dfee6e/test.git +refs/heads/*:refs/remotes/origin/* # timeout=10

    ERROR: Error fetching remote repo 'origin'

    hudson.plugins.git.GitException: Failed to fetch from http://192.168.72.130:9080/gitlab-instance-d4dfee6e/test.git

    at PluginClassLoader for git//hudson.plugins.git.GitSCM.fetchFrom(GitSCM.java:999)

     

     

    5、对多分支进行构建测试

    (一)对main分支进行构建

    5.1.1、修改main分支Jenkinsfile脚本
    pipeline {
        agent any
        tools {
            maven "maven3" 
        }
        stages {
            stage('main拉取代码...') {
                steps {
                    git branch: 'main', url: 'http://192.168.72.130:9080/root/java-project.git'
                    echo "main代码拉取成功!!! $pwd"
                }
            }
    
            stage('main进行构建...') {
                steps {
                    //sh "mvn  --version"
                    sh """
                       cd HelloWorld
                       mvn clean package
                    """
                    echo 'main构建成功!!!'
                }
            }
            stage('main上传服务到测试环境...') {
                steps {
                    //sh "mvn  --version"
                    sshPublisher(publishers: [sshPublisherDesc(configName: '测试服务器连接', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'javafile', remoteDirectorySDF: false, removePrefix: 'HelloWorld/target', sourceFiles: '**/target/*.jar'), sshTransfer(cleanRemote: false, excludes: '', execCommand: '''if docker ps -a | grep -q helloworld; then
        docker rm -f helloworld || true  # 忽略删除失败(如容器已停止)
    fi
    
    if docker images | grep -q helloworld; then
        docker rmi -f helloworld || true  # 忽略删除失败
    fi
    
    docker build -t helloworld . || { echo "构建失败"; exit 1; }
    docker run -d --name helloworld -p 9999:8989 helloworld || { echo "运行容器失败"; exit 1; }''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/', remoteDirectorySDF: false, removePrefix: ' HelloWorld/docker', sourceFiles: '**/dockerfile')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    echo 'main容器启动成功!!!'
                }
            }
        }
    }
    

     5.1.2、修改main分支的程序输出内容方便测试

    5.1.3、执行构建发布

    5.1.4、在浏览器上进行访问验证

    输入:http://192.168.72.132:9999/

    (二)对test分支进行构建

    5.2.1、创建test分区

    5.2.2、修改test分支的Jenkinsfile
    pipeline {
        agent any
        tools {
            maven "maven3" 
        }
        stages {
            stage('test拉取代码...') {
                steps {
                    git branch: 'test', url: 'http://192.168.72.130:9080/root/java-project.git'
                    echo "test代码拉取成功!!! $pwd"
                }
            }
    
            stage('test进行构建...') {
                steps {
                    //sh "mvn  --version"
                    sh """
                       cd HelloWorld
                       mvn clean package
                    """
                    echo 'test构建成功!!!'
                }
            }
            stage('test上传服务到测试环境...') {
                steps {
                    //sh "mvn  --version"
                    sshPublisher(publishers: [sshPublisherDesc(configName: '测试服务器连接', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: 'javafile', remoteDirectorySDF: false, removePrefix: 'HelloWorld/target', sourceFiles: '**/target/*.jar'), sshTransfer(cleanRemote: false, excludes: '', execCommand: '''if docker ps -a | grep -q helloworld; then
        docker rm -f helloworld || true  # 忽略删除失败(如容器已停止)
    fi
    
    if docker images | grep -q helloworld; then
        docker rmi -f helloworld || true  # 忽略删除失败
    fi
    
    docker build -t helloworld . || { echo "构建失败"; exit 1; }
    docker run -d --name helloworld -p 7777:8989 helloworld || { echo "运行容器失败"; exit 1; }''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/', remoteDirectorySDF: false, removePrefix: ' HelloWorld/docker', sourceFiles: '**/dockerfile')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
                    echo 'test容器启动成功!!!'
                }
            }
        }
    }
    

    5.2.2.1、修改拉取代码Git的分支信息

    5.2.2.2、修改镜像映射信息

    5.2.3、修改test访问的内容方便区分与main分支的区别

    5.2.4、执行构建分布

    5.2.5、在浏览器上进行访问验证

    浏览器上访问:http://192.168.72.132:7777/

    (三)代码合并

    在实际的使用场景中:假设test分支部署到测试环境;main分支部署到生产环境;我们先提交代码到test分支,然后发布到测试环境进行测试,待测试通过后再将test分支的代码合并到main分支,再将main分支的代码发布到生产环境。

    5.3.1、合并代码

    5.3.2、解决代码冲突问题