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分支触发部署
(五)最佳实践
- 小步提交,频繁集成:避免长时间开发后一次性合并大量代码。
- 快速失败原则:在 Pipeline 早期(如单元测试)捕获错误,减少后续步骤的浪费。
- 环境一致性:使用 Docker 等容器技术确保开发、测试、生产环境一致。
- 监控与回滚机制:部署后监控应用性能,异常时自动回滚。
- 安全性检查:在 Pipeline 中集成安全扫描(如 OWASP Dependency-Check 检测依赖漏洞)。
(六)常见问题与解决方案
问题 解决方案 测试环境与生产环境不一致 使用 Docker 容器化部署 部署失败导致服务中断 采用蓝绿部署、金丝雀发布等策略 Pipeline 执行时间过长 并行执行无关任务、缓存依赖 测试覆盖率不足 强制要求测试覆盖率(如 80% 以上) 通过合理设计 CI/CD Pipeline,团队可显著提升开发效率、减少人为错误,并实现快速迭代和高质量交付
一、Pipeline参考文档
Jenkins使用介绍:https://www.w3cschool.cn/jenkins/jenkins-epas28oi.html
二、创建Pipeline流水线
1、创建一个Pipeline流水线


2、Pipeline语法构成

3、自动生成groove语言的步骤拉取代码步骤的语法
3.1、点击进入流水线语法

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



在脚本中的定义如下:
Groovy
pipeline {
agent any
tools {
maven "maven3"
}
stages {
stage('拉取代码...') {
steps {
echo "拉取成功!!!"
}
}
stage('进行构建...') {
steps {
sh "mvn --version"
echo '构建成功'
}
}
}
}
3.2、生成拉取git代码的脚本步骤

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

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

步骤三:生成流水线脚本

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

Groovy
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构建代码
Groovy
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、解决方法:执行多条命令时要加上判断条件提高执行的成功率
解决方法:多条命令需要加判断条件,以确保每条命令都能成功运行。
如:
bash
把
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脚本如下:
Groovy
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 最显著的作用是通过图形化界面展示流水线的完整生命周期,将传统的文本日志转化为可视化流程。具体包括:
流水线拓扑图
以流程图形式展示流水线的各个阶段(如构建、测试、部署)及其依赖关系,直观呈现执行顺序和并行任务。
示例: plaintext
[检出代码] → [编译] → [单元测试] → [集成测试] → [部署预发环境] → [人工确认] → [部署生产环境]
实时状态监控
- 用颜色标识任务状态(绿色 / 成功、红色 / 失败、黄色 / 暂停),点击节点可查看详细日志和错误信息,减少排查问题的时间。
2.2、简化分支与合并请求管理
针对 Git 分支和合并请求(MR)的场景,Blue Ocean 提供专属功能:
- 分支可视化对比
- 展示不同分支的差异点和流水线执行结果,帮助开发者快速判断分支是否可合并。
- MR 流水线关联
- 自动为每个 MR 生成独立流水线,显示代码变更的测试结果和部署状态,避免因未经验证的代码合并导致问题。
- 冲突解决辅助
- 可视化展示代码冲突位置,支持直接在界面中解决冲突并触发重新构建。
2.3、交互式用户体验优化
Blue Ocean 打破了 Jenkins 传统界面的复杂性,通过交互设计提升使用效率:
- 流水线导航与回溯
- 支持通过界面直接跳转至历史构建版本,查看不同版本的变更和执行记录。
- 人工干预节点
- 在流水线中设置需要人工确认的节点(如部署生产环境前的审批),通过界面按钮快速完成操作,无需命令行或额外工具。
- 响应式设计
- 适配不同设备屏幕,移动端也可便捷查看流水线状态,适合远程协作场景。
2.4、集成与扩展能力
Blue Ocean 可与主流开发工具和 CI/CD 生态集成,增强整体流程效率:
- 代码仓库集成
- 无缝对接 GitLab、GitHub、Bitbucket 等平台,自动同步分支和 MR 信息。
- 插件生态兼容
- 支持与 Jenkins 现有插件(如 SonarQube、JUnit)集成,在界面中展示代码质量、测试覆盖率等指标。
- 自定义流水线配置
- 通过可视化编辑器或直接编辑 Jenkinsfile 定义流水线逻辑,降低新手使用门槛。
2.5、团队协作与流程标准化
Blue Ocean 通过透明化的流程展示,促进团队协作和规范落地:
- 责任明确化
- 每个流水线节点的执行者和状态一目了然,便于追踪问题责任方。
- 流程标准化
- 提供模板化流水线配置,确保团队遵循统一的 CI/CD 规范(如代码评审、测试必过等)。
- 知识共享
- 新人可通过可视化界面快速理解项目的集成流程,减少学习成本。
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
bash
java -jar jenkins.war --version

4、Jenkins版本升级以适配Blue Ocean版本
4.1、在官网下载Jenkins的war包
官网下载连接:Download and deploy

4.2、替换之前的war包,开启Jenkins
bash
#执行脚本开启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脚本
Groovy
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
Groovy
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、解决代码冲突问题
