← 返回文章列表
CI/CD 完整指南:从理论到 K8s 实战
详细讲解 CI/CD 概念、持续集成与持续交付的区别、完整流水线设计,以及基于 Kubernetes 的企业级 CI/CD 架构实战。
10 分钟阅读
字号
一、CI/CD 是什么
1.1 基本概念
CI = Continuous Integration(持续集成)
CD = Continuous Delivery(持续交付)
或 Continuous Deployment(持续部署)核心思想:软件开发的"流水线"——代码从开发到生产环境的自动化流转。
1.2 传统开发 vs CI/CD
传统开发模式(问题多):
开发者A ──▶ 代码 ──▶ ──▶ ──▶ ──▶ ──▶ ──▶ ──▶ 测试环境
▲
开发者B ──▶ 代码 ──▶ ──▶ ──▶ ──▶ ──▶ ──▶ 攒够再测
▲
开发者C ──▶ 代码 ──▶ ──▶ ──▶ ──▶ ──▶ ──▶问题:
- 多人代码合并困难(代码冲突地狱)
- 最后才集成,问题发现晚
- 测试靠人工,效率低
- 上线靠人肉,风险高
CI/CD 开发模式(自动化):
开发者A ──▶ 代码 ──▶ ──▶ Git ──▶ 自动构建 ──▶ 自动测试 ──▶
开发者B ──▶ 代码 ──▶ ──▶ Git ──▶ 自动构建 ──▶ 自动测试 ──▶
开发者C ──▶ 代码 ──▶ ──▶ Git ──▶ 自动构建 ──▶ 自动测试 ──▶优点:每次代码提交都自动构建测试,问题早发现,自动化发布,可回滚。
二、持续集成 CI 详解
2.1 CI 的流程
开发者 ──▶ git push ──▶ GitLab ──▶ Webhook ──▶ Jenkins 触发
│
▼
┌──────────────┐
│ 构建阶段 │
│ • 拉取代码 │
│ • 安装依赖 │
│ • 编译打包 │
└──────────────┘
│
▼
┌──────────────┐
│ 测试阶段 │
│ • 单元测试 │
│ • 代码扫描 │
│ • 集成测试 │
└──────────────┘
│
▼
┌──────────────┐
│ 构建结果 │
│ • 镜像推送 │
│ • 通知 │
└──────────────┘2.2 CI 做什么
1. 代码编译
| 语言 | 命令 |
|---|---|
| Java | mvn compile / gradle build |
| Go | go build |
| Python | python setup.py build |
| Node.js | npm run build |
2. 单元测试
| 语言 | 框架 |
|---|---|
| Java | JUnit + Mockito |
| Go | go test |
| Python | pytest / unittest |
| JavaScript | Jest / Mocha |
3. 代码质量扫描:使用 SonarQube 检测代码异味、安全漏洞、代码覆盖率。
4. 打包构建产物:Java jar 包、Go 二进制文件、前端镜像包。
三、持续交付 vs 持续部署
3.1 持续交付(Continuous Delivery)
代码 ──▶ 自动构建测试 ──▶ 自动打包 ──▶ 人工确认 ──▶ 发布
▲
│
人手动点击"确认上线"特点:测试环境自动,生成环境人工介入。
3.2 持续部署(Continuous Deployment)
代码 ──▶ 自动构建测试 ──▶ 自动打包 ──▶ 自动发布 ──▶ 生产特点:全自动,无需人工介入。
3.3 总结
| 阶段 | 说明 |
|---|---|
| CI(持续集成) | 保证代码质量 |
| CD(持续交付) | 自动到待发布状态,人工决定何时发布 |
| CD(持续部署) | 代码自动发布到生产环境 |
生产环境通常用"持续交付",需要人工确认。
四、完整的 CI/CD 流程图
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ 开发 │────▶│ 提交 │────▶│ 构建 │────▶│ 测试 │
│ 写代码 │ │ push │ │ compile │ │UT/IT │
└─────────┘ └─────────┘ └─────────┘ └────┬────┘
│
▼
┌─────────┐
│ 质量扫描│
│ SonarQube│
└────┬────┘
│
▼
┌─────────┐
│ 打包镜像│
│ Docker │
└────┬────┘
│
┌────────────────────────┼────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐
│ 测试环境 │ │ 预发环境 │
│ SIT/UAT │ │ Staging │
└────┬─────┘ └────┬─────┘
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ 自动化测试│ │ 自动化测试│
│ 回归测试 │ │ 回归测试 │
└────┬─────┘ └────┬─────┘
│ ┌───────────┘
│ │
│ ▼
│ ┌──────────┐
│ │ 人工验收 │
│ │ 审批 │
│ └────┬─────┘
│ │
│ ▼
│ ┌──────────┐
└──▶│ 生产环境 │
│ Product │
└──────────┘五、环境说明
| 环境 | 说明 |
|---|---|
| 开发环境(Dev) | 开发人员本地,代码编写、调试 |
| 测试环境(SIT/QA) | 系统集成测试、功能测试 |
| 预发环境(Staging/UAT) | 用户验收测试,最接近生产环境 |
| 生产环境(Production) | 真实用户访问,金丝雀发布/灰度发布 |
六、企业级 CI/CD 架构
6.1 架构图
┌──────────────────────────────────────────────────────────┐
│ 开发机 (test06) │
│ 192.168.8.116 │
│ │
│ 开发者写代码 ──▶ git push ──▶ GitLab │
└──────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ 工具集群 (test07) │
│ 192.168.8.117 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │Jenkins │ │ GitLab │ │ Harbor │ │
│ │ CI/CD │ │ 代码仓库 │ │ 镜像仓库 │ │
│ │ 调度 │ │ │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ │
└──────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌────────────────────────┐ ┌────────────────────────┐
│ 测试集群 (test04) │ │ 生产集群 (test05) │
│ 192.168.8.114 │ │ 192.168.8.115 │
│ │ │ │
│ • RD 测试 │ │ • product 命名空间 │
│ • 功能验证 │ │ • staging 命名空间 │
│ │ │ │
└────────────────────────┘ └────────────────────────┘6.2 具体流程
Step 1:开发机写代码
# 克隆代码仓库
git clone ssh://git@git.k8s.local:30022/root/greenhat.git
# 创建开发分支
git checkout -b feature/login
# 编写代码
vim main.go
# 提交并推送
git add .
git commit -m "feat: 添加登录功能"
git push origin feature/loginStep 2:GitLab 接收代码,触发 Webhook
GitLab 检测到代码 push,发送 Webhook 到 Jenkins。
Step 3:Jenkins 动态创建 Pod Agent
Jenkins Master ◀──调度──▶ K8s API
│
▼
动态创建 Pod Agent
(jnlp 镜像)
执行完自动销毁Step 4:CI 流水线执行
pipeline {
agent any
environment {
REGISTRY = 'harbor.k8s.local'
PROJECT = 'greenhat'
IMAGE = "${REGISTRY}/${PROJECT}/app"
}
stages {
stage('拉取代码') {
steps {
git 'ssh://git@git.k8s.local:30022/root/greenhat.git'
}
}
stage('构建') {
steps {
sh 'go build -o app .'
}
}
stage('单元测试') {
steps {
sh 'go test ./... -v'
}
}
stage('代码扫描') {
steps {
script {
def scannerHome = tool 'SonarQube'
withSonarQubeEnv('SonarQube') {
sh "${scannerHome}/bin/sonar-scanner"
}
}
}
}
stage('制作镜像') {
steps {
sh """
docker build -t ${IMAGE}:${BUILD_NUMBER} .
docker tag ${IMAGE}:${BUILD_NUMBER} ${IMAGE}:latest
"""
}
}
stage('推送镜像') {
steps {
sh """
docker login ${REGISTRY} -u admin -p Harbor12345
docker push ${IMAGE}:${BUILD_NUMBER}
docker push ${IMAGE}:latest
"""
}
}
stage('部署到测试环境') {
steps {
sh """
kubectl set image deployment/app \
app=${IMAGE}:${BUILD_NUMBER} \
-n test
"""
}
}
}
}Step 5:部署到测试环境
kubectl set image deployment/app \
app=harbor.k8s.local/greenhat/app:v1.0.1 \
-n testK8s 调度流程:
- kube-apiserver 收到请求
- Deployment Controller 更新 ReplicaSet
- Scheduler 选择节点
- kubelet 在选中的节点上启动新 Pod
- kubelet 从 Harbor 拉取镜像
- 启动容器
Step 6:人工审批
stage('部署到生产环境') {
when {
branch 'master'
}
steps {
input message: '确认部署到生产环境?',
ok: '确认',
submitter: 'ops-team'
sh """
kubectl set image deployment/app \
app=${IMAGE}:${BUILD_NUMBER} \
-n production
"""
}
}Step 7:部署到生产环境(金丝雀发布)
# 先更新 10% 的 Pod
kubectl patch deployment/app -n product ...
# 观察指标(5-10分钟)
# • 错误率是否上升
# • 响应时间是否正常
# • Pod 是否 Running
# 确认无问题后全量更新
kubectl scale deployment/app --replicas=10 -n product七、金丝雀发布(Canary Release)
背景:以前矿工下矿井前,会先放一只金丝雀进去测试氧气是否充足。
v1 版本(老版本)
│
│ 100% 流量 ────────────────────────────────────┐
│ │
│ 升级中...
│ 10% 流量 ─────────────┐ │
│ ▼ │
│ ┌──────────┐ │
│ │ v2 版本 │ │
│ │ (新版本) │ │
│ │ 10% 流量 │ │
│ └──────────┘ │
│ │
│ 观察错误率、响应时间
│ │
│ ✅ 没问题
│ │
│ 全量切换到 v2如果有问题? 回滚到 v1。
八、回滚机制
需要回滚的情况:
- 错误率突然上升
- 响应时间暴增
- 新版本有 Bug
- 业务指标异常
回滚命令:
# 快速回滚到上一个版本
kubectl rollout undo deployment/app -n product
# 回滚到指定版本
kubectl rollout undo deployment/app --to-revision=3 -n product
# 查看部署历史
kubectl rollout history deployment/app -n product九、总结
CI/CD 流程一句话总结:
开发机写代码 ──▶ GitLab 接收 ──▶ Jenkins 触发 ──▶
CI(持续集成):
拉代码 → 编译 → 测试 → 扫描 → 打包镜像 → 推送到 Harbor
CD(持续交付/部署):
部署测试环境 → 自动化测试 → 部署预发 → 人工审批 → 部署生产核心价值:
- 自动化:减少人工干预,降低错误率
- 快速迭代:代码提交后快速反馈
- 质量保障:每个阶段都有测试和检查
- 可回滚:出问题可以快速回退到稳定版本
分享