本文目录导读:

在Jenkins中实现灰度发布策略,核心思路是控制流量权重和分批次滚动更新,以下是几种常见的实现方案,从简单到复杂:
基础方案:基于构建参数的手动灰度
适用于小团队或低频发布场景,通过Jenkins参数化构建控制。
Pipeline脚本示例
pipeline {
agent any
parameters {
choice(name: 'GRAY_STRATEGY', choices: ['全量发布', '10%灰度', '50%灰度', '100%发布'], description: '选择灰度策略')
string(name: 'GRAY_TAG', defaultValue: 'latest', description: '版本标签')
}
stages {
stage('构建镜像') {
steps {
sh "docker build -t myapp:${params.GRAY_TAG} ."
sh "docker push myapp:${params.GRAY_TAG}"
}
}
stage('灰度部署') {
steps {
script {
def replicas = 10 // 总实例数
def grayReplicas = 0
switch(params.GRAY_STRATEGY) {
case '10%灰度':
grayReplicas = 1
break
case '50%灰度':
grayReplicas = 5
break
case '100%发布':
grayReplicas = replicas
break
default:
grayReplicas = 0
}
// 使用Kubernetes部署示例
sh """
kubectl set image deployment/myapp-stable myapp=myapp:${params.GRAY_TAG} --record
kubectl scale deployment/myapp-stable --replicas=${replicas - grayReplicas}
kubectl scale deployment/myapp-gray --replicas=${grayReplicas}
"""
}
}
}
stage('观察与回滚') {
steps {
input message: '灰度验证通过?', ok: '继续发布',
submitterParameter: 'APPROVER'
// 验证通过后全量发布
sh "kubectl set image deployment/myapp-stable myapp=myapp:${params.GRAY_TAG}"
sh "kubectl scale deployment/myapp-gray --replicas=0"
}
}
}
}
进阶方案:基于负载均衡的流量控制
适用于微服务架构,使用网关或Service Mesh实现精确流量控制。
Nginx/Ingress权重配置
pipeline {
agent any
environment {
REGISTRY = 'myregistry.com'
PROJECT = 'myapp'
}
parameters {
string(name: 'VERSION', defaultValue: '', description: '新版本号')
string(name: 'GRAY_PERCENT', defaultValue: '10', description: '灰度百分比')
}
stages {
stage('部署灰度版本') {
steps {
script {
// 部署灰度版本到指定组
sh """
kubectl apply -f k8s/deployment-gray.yaml
kubectl set image deployment/myapp-gray myapp=${REGISTRY}/${PROJECT}:${VERSION}
"""
}
}
}
stage('更新流量权重') {
steps {
script {
// 更新Nginx配置或ALB权重
def grayWeight = params.GRAY_PERCENT.toInteger()
def stableWeight = 100 - grayWeight
sh """
# 更新Service Mesh配置
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp
http:
- route:
- destination:
host: myapp-stable
subset: stable
weight: ${stableWeight}
- destination:
host: myapp-gray
subset: gray
weight: ${grayWeight}
EOF
"""
}
}
}
stage('灰度验证') {
steps {
timeout(time: 30, unit: 'MINUTES') {
input message: '灰度验证通过?', ok: '继续全量发布'
}
}
}
stage('全量发布') {
steps {
script {
sh """
# 将稳定版本更新为新版本
kubectl set image deployment/myapp-stable myapp=${REGISTRY}/${PROJECT}:${VERSION}
# 逐步增加权重
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp
http:
- route:
- destination:
host: myapp-stable
subset: stable
weight: 100
- destination:
host: myapp-gray
subset: gray
weight: 0
EOF
# 清理灰度版本
kubectl delete deployment myapp-gray
"""
}
}
}
}
}
高级方案:自动化灰度与金丝雀发布
使用Jenkins + Spinnaker/ArgoCD实现自动化灰度。
基于Prometheus监控的自动化灰度
pipeline {
agent any
parameters {
string(name: 'VERSION', defaultValue: '', description: '版本号')
string(name: 'MONITOR_DURATION', defaultValue: '5', description: '监控观察时间(分钟)')
string(name: 'ERROR_THRESHOLD', defaultValue: '0.1', description: '错误率阈值(%)')
}
stages {
stage('金丝雀部署') {
steps {
script {
// 1. 部署1个金丝雀实例
sh "kubectl scale deployment/myapp-canary --replicas=1"
sh "kubectl set image deployment/myapp-canary myapp=${REGISTRY}/${PROJECT}:${VERSION}"
// 2. 配置5%流量到金丝雀
sh "kubectl apply -f canary-weight-5.yaml"
}
}
}
stage('监控与评估') {
steps {
script {
// 等待并检查指标
def duration = params.MONITOR_DURATION.toInteger()
sleep time: duration, unit: 'MINUTES'
// 查询Prometheus
def errorRate = sh(script: """
curl -s "http://prometheus:9090/api/v1/query?query=sum(rate(http_requests_total{status=~'5..',app='myapp'}[5m]))/sum(rate(http_requests_total{app='myapp'}[5m]))*100" | jq -r '.data.result[0].value[1]'
""", returnStdout: true).trim()
if (errorRate.toDouble() > params.ERROR_THRESHOLD.toDouble()) {
error "错误率过高(${errorRate}%),自动回滚!"
}
}
}
}
stage('逐步扩大灰度') {
steps {
script {
// 逐步增加实例和流量
def stages = [
[replicas: 3, weight: 20],
[replicas: 5, weight: 50],
[replicas: 8, weight: 80],
]
for (stage in stages) {
sh """
kubectl scale deployment/myapp-canary --replicas=${stage.replicas}
kubectl apply -f canary-weight-${stage.weight}.yaml
"""
// 每次扩量后等待并验证
sleep 2
verifyMetrics()
}
}
}
}
}
}
def verifyMetrics() {
// 健康检查逻辑
sh "curl -sf http://myapp/health || exit 1"
}
通用灰度发布Pipeline模板
一个适用于大多数场景的模板:
pipeline {
agent any
parameters {
string(name: 'VERSION', defaultValue: '', description: '新版本号')
choice(name: 'GRAY_TYPE', choices: ['实例灰度', '流量灰度', 'AB测试'], description: '灰度类型')
string(name: 'GRAY_PERCENT', defaultValue: '10', description: '灰度比例(1-100)')
string(name: 'OBSERVE_TIME', defaultValue: '30', description: '观察时间(分钟)')
}
stages {
stage('构建') {
steps {
echo "构建版本: ${VERSION}"
}
}
stage('部署') {
steps {
script {
switch(params.GRAY_TYPE) {
case '实例灰度':
// 实例级灰度
grayByInstance()
break
case '流量灰度':
// 流量级灰度
grayByTraffic()
break
case 'AB测试':
// A/B测试
grayByABTest()
break
}
}
}
}
stage('验证与观察') {
steps {
timeout(time: params.OBSERVE_TIME.toInteger(), unit: 'MINUTES') {
input message: "灰度验证通过?\n新版本: ${VERSION}\n灰度比例: ${GRAY_PERCENT}%",
ok: '全量发布',
submitterParameter: 'APPROVER'
}
}
}
stage('全量发布') {
steps {
script {
// 全量更新
fullRelease()
}
}
}
}
post {
failure {
// 失败自动回滚
rollback()
}
}
}
def grayByInstance() {
// 实例灰度实现
sh """
kubectl set image deployment/myapp-stable myapp=${REGISTRY}/${PROJECT}:${VERSION}
kubectl scale deployment/myapp-stable --replicas=${10 - (10 * ${GRAY_PERCENT} / 100).toInteger()}
kubectl scale deployment/myapp-gray --replicas=${(10 * ${GRAY_PERCENT} / 100).toInteger()}
"""
}
def grayByTraffic() {
// 流量灰度实现
sh """
kubectl apply -f k8s/service-weight-config.yaml
kubectl patch svc myapp -p '{"spec":{"trafficPolicy":{"loadBalancer":{"weight":{\"stable\":$((100-${GRAY_PERCENT})),\"gray\":${GRAY_PERCENT}}}}}}'
"""
}
def grayByABTest() {
// AB测试实现
sh """
kubectl apply -f abtest/myapp-v2-deployment.yaml
kubectl apply -f abtest/myapp-ab-route.yaml
"""
}
def fullRelease() {
// 全量发布
sh """
kubectl set image deployment/myapp-stable myapp=${REGISTRY}/${PROJECT}:${VERSION}
kubectl scale deployment/myapp-gray --replicas=0
"""
}
def rollback() {
// 回滚逻辑
sh """
kubectl set image deployment/myapp-stable myapp=${REGISTRY}/${PROJECT}:${env.OLD_VERSION}
kubectl scale deployment/myapp-gray --replicas=0
"""
}
关键实践建议
灰度策略选择矩阵
| 场景 | 推荐方案 | 实现难度 |
|---|---|---|
| 单体应用 | 实例灰度 | 低 |
| 微服务 | 流量灰度 + Service Mesh | 中 |
| 前端应用 | 路由灰度 | 低 |
| 核心业务 | 全自动金丝雀 | 高 |
安全措施
-
自动回滚条件
def autoRollbackIf(condition) { if (condition) { currentBuild.result = 'UNSTABLE' error "触发自动回滚: ${condition}" } } -
健康检查
stage('健康检查') { steps { retry(3) { sh "curl -sf --max-time 5 http://gray-service/health || exit 1" } } } -
操作审计
post { always { sh """ echo "[$(date)] 发布记录: VERSION=${VERSION}, USER=${BUILD_USER}, RESULT=${currentBuild.result}" >> /var/log/deploy.log """ } }
Jenkins配置建议
-
安装插件
- Pipeline: Stage View
- Build Timeout
- Build Failure Analyzer
- Kubernetes CLI Plugin
- HTTP Request Plugin
-
参数化构建
properties([ parameters([ string(name: 'VERSION', defaultValue: ''), choice(name: 'ENV', choices: ['dev', 'test', 'prod']), booleanParam(name: 'DRY_RUN', defaultValue: false) ]) ])
通过以上方案,可以根据团队成熟度和业务需求选择合适的灰度发布实现,建议从简单的实例灰度开始,逐步演进到自动化的金丝雀发布。