🚀 一、CI/CD 基础理论
1. 持续集成(CI,Continuous Integration)
目标:频繁(每天多次)地集成代码,发现问题尽早修复
- 每次提交代码自动触发构建流程
- 自动执行单元测试、构建镜像等
- 发现问题及时反馈给开发者
2. 持续交付(CD,Continuous Delivery)
目标:构建完成后自动部署到类生产环境,确保可发布
- 镜像推送至 Harbor
- 自动部署到 Kubernetes 测试环境
- 手动审核部署到生产
3. 持续部署(Continuous Deployment)
目标:构建完成后自动部署到生产环境
- 与持续交付相比,多了“自动化发布”这一步
- 风险较大,需保障测试和回滚机制完善

🧱 二、平台组件角色与协作关系
| 组件 | 角色描述 |
|---|---|
| GitLab | 代码管理、Webhook 触发 CI 流水线 |
| Jenkins | 流水线核心引擎,构建、测试、打包、部署的控制中心 |
| Docker | 用于构建应用容器镜像 |
| Harbor | 私有镜像仓库,用于保存构建好的镜像 |
| Kubernetes | 应用运行环境,完成容器调度、伸缩、滚动更新等部署工作 |
🔄 三、典型工作流程(理论视角)
1. 开发者提交代码(Push)
- GitLab 接收到 Push 请求
- 触发 Webhook,通知 Jenkins 进行 CI 构建
2. Jenkins CI 流水线执行
- 拉取代码
- 单元测试(可选)
- 生成 Docker 镜像
- 推送镜像到 Harbor
- 更新 K8s 部署(例如修改 Deployment 的镜像版本)
3. Kubernetes 执行部署
- 拉取 Harbor 中的镜像
- 滚动更新 Deployment
- 实现无缝部署
🚀 CI/CD 流程描述
客户机开发者使用本地 IDE 进行持续编码,仅需手动执行一次代码提交(git push),之后的所有操作均自动完成,流程如下:
代码提交
- 开发者将代码通过本地 IDE
push到 GitLab 仓库。
- 开发者将代码通过本地 IDE
触发构建
- GitLab 通过 WebHook 通知 Jenkins,自动触发对应的构建任务。
拉取源码
- Jenkins 使用 Shell 脚本从 GitLab 仓库拉取最新的应用源代码和
Dockerfile文件。
- Jenkins 使用 Shell 脚本从 GitLab 仓库拉取最新的应用源代码和
构建镜像
- Jenkins 基于拉取的源码和
Dockerfile构建 Docker 镜像。
- Jenkins 基于拉取的源码和
推送镜像
- 构建完成的镜像被推送至 Harbor 私有镜像仓库中。
部署到集群
- Jenkins 通过
kubectl命令行工具(或 kubelet 客户端)通知 Kubernetes 集群拉取 Harbor 中的镜像,并更新对应 Deployment。 - 默认使用 滚动更新(Rolling Update)策略,无缝替换旧版本容器。
- Jenkins 通过
整个流程中,除了开发者手动提交代码,其余步骤均实现自动化,确保持续集成与持续部署高效闭环。
四、架构规划
| Node IP | 部署服务 | 备注 |
|---|---|---|
| 100.100.157.10(master01) | Ingress-nginx | k8s-统一入口 |
| 100.100.157.11(work01) | SpringBoot、harbor | 后端项目 |
| 100.100.157.12(work02) | vue | 前端项目 |
| 100.100.157.13(cicd) | jenkins、gitlab、maven、jdk、nodejs、docker | 数据库/镜像仓库 |
这里基础组件部署就不过多赘述了,请参考其他文章。
五、gitlab项目demo准备
1.gitlab创建前后端项目,并创建master/devops分支(用于模拟正式环境/开发环境发布流程)

2.推送代码至gitlab(master/devops分支)
gitlab git url:
后端项目如下:

前端项目如下:

六、jenkins环境配置
1.jenkins基础全局配置
Dashdoard——manage-jenkins——System
- Jenkins Location:Jenkins URL
Dashdoard——manage-jenkins——Tools
- git、maven、node.js(可选,也可以在流水线中配置)
Dashdoard——manage-jenkins——credentials
- 配置凭证

七、cicd java项目
1、准备
将dockerfile上传至gitlab项目中,用于构建镜像

2.新建ltem
- 输入任务名称(自定义)
- 选择pipeline
- 流水线-定义-pipeline script
流水线配置
properties([
parameters([
string(name: 'BRANCH', defaultValue: 'master', description: '请输入要构建的 Git 分支')
])
])
node {
def harborUser = 'hxy'
def harborPasswd = 'Hxy1224...'
def harborAddress = '100.100.157.10:5000'
def harborRepo = 'k8s'
def JAVA_HOME = '/usr/java/jdk1.8.0_131'
def dingTalkWebhook = 'https://oapi.dingtalk.com/robot/send?access_token=25508193433dbe82f8761fb5e63396a0c43188d398040a7d4a484184eeeb7ceb'
def imageTag = ""
def buildSuccess = false
catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
stage('拉取Git代码') {
checkout scmGit(
branches: [[name: "*/${params.BRANCH}"]],
extensions: [],
userRemoteConfigs: [[
credentialsId: 'gitlab',
url: 'http://100.100.157.13:9090/cicd-xhy/back-end-demo.git'
]]
)
}
stage('构建代码') {
env.JAVA_HOME = JAVA_HOME
env.PATH = "${JAVA_HOME}/bin:${env.PATH}"
sh '''
export JAVA_HOME=/usr/java/jdk1.8.0_131
export PATH=$JAVA_HOME/bin:$PATH
/root/hxy/packages/jenkins/mvm/apache-maven-3.9.9/bin/mvn clean package -DskipTests
'''
}
stage('制作镜像并推送 Harbor') {
def timestamp = new Date().format("yyyy-MM-dd-HH-mm", TimeZone.getTimeZone("Asia/Shanghai"))
imageTag = timestamp
def imageFullPath = "${harborAddress}/${harborRepo}/${env.JOB_NAME}:${imageTag}"
env.IMAGE_TAG = imageTag
sh """
mv target/*jar docker/
docker build -t ${imageFullPath} docker/
docker image prune -f
docker login -u ${harborUser} -p ${harborPasswd} ${harborAddress}
docker push ${imageFullPath}
"""
}
stage('更新K8s YAML并部署') {
def newImage = "${harborAddress}/${harborRepo}/${env.JOB_NAME}:${imageTag}"
sh """
ssh root@100.100.157.10 "sudo sed -i 's|image: .*|image: ${newImage}|' /root/hxy/packages/k8s-demo/java/backend.yaml"
ssh root@100.100.157.10 kubectl delete -f /root/hxy/packages/k8s-demo/java/backend.yaml || true
ssh root@100.100.157.10 kubectl apply -f /root/hxy/packages/k8s-demo/java/backend.yaml
"""
}
buildSuccess = true
}
// ✅ 无论构建成功或失败都执行
def emoji = buildSuccess ? "✅" : "❌"
def msg = buildSuccess ? "构建成功" : "构建失败"
sendDingTalkText(emoji, msg, imageTag, dingTalkWebhook, harborAddress, harborRepo)
}
// 发送钉钉通知函数
def sendDingTalkText(String statusEmoji, String resultDesc, String imageTag, String webhook, String harborAddress, String harborRepo) {
def jobName = env.JOB_NAME
def buildNumber = env.BUILD_NUMBER
def tag = imageTag ?: "N/A"
def buildTime = new Date().format("yyyy-MM-dd HH:mm", TimeZone.getTimeZone("Asia/Shanghai"))
def imageFullPath = "${harborAddress}/${harborRepo}/${jobName}:${tag}"
def buildUrl = env.BUILD_URL ?: "http://your-jenkins-url/job/${jobName}/${buildNumber}/"
def rawText = """cicd-发版通知
构建状态:${statusEmoji} ${resultDesc}
应用名称:${jobName}
应用版本:${tag}
构建时间:${buildTime}
构建镜像:${imageFullPath}
构建链接:${buildUrl}
备注:请各研发运维同学观察版本上线验证 ✅"""
def payload = """{
"msgtype": "text",
"text": {
"content": "${rawText}"
}
}"""
sh """
curl '${webhook}' \
-H 'Content-Type: application/json' \
-d '${payload}'
"""
}
this project is parameterized(配置动态分支选择)

运行流水线
