Kubernetes Deployment 完全指南:从原理到实战

技术标签: Kubernetes | Deployment | 滚动更新 | 回滚 | 云原生 | 应用部署
难度级别: 进阶
阅读时间: 30分钟
适用人群: DevOps工程师、云原生架构师、Kubernetes用户


📖 文章导读

Deployment 是 Kubernetes 中最常用的工作负载控制器,它封装了 ReplicaSet 并提供声明式更新回滚扩缩容等高级功能。本文将从底层原理到生产实践,全面解析 Deployment 的核心机制。

你将学到什么?

  • ✅ Deployment 的架构设计与工作原理
  • ✅ 滚动更新策略详解(RollingUpdate vs Recreate)
  • ✅ 版本管理与回滚机制
  • ✅ 生产环境最佳实践
  • ✅ 常见问题排查指南

一、Deployment 的定位与演进

1.1 为什么需要 Deployment?

在 Kubernetes 早期,用户直接使用 ReplicaSet 管理 Pod,但面临以下痛点:

痛点1:更新需要手动操作
  旧版本:kubectl delete rs old && kubectl create rs new

痛点2:无法保证更新过程的安全性
  如果新版本有问题,旧版本已经被删除

痛点3:缺少版本历史和回滚能力
  更新后发现问题,不知道之前是什么配置

Deployment 的解决方案

# 声明式:只需更新期望状态
kubectl set image deployment/myapp nginx=nginx:1.22

# Kubernetes 自动完成:
# 1. 创建新 ReplicaSet
# 2. 逐步扩容新 RS,缩容旧 RS
# 3. 记录版本历史
# 4. 支持一键回滚

1.2 Deployment 与 ReplicaSet 的关系

管理

管理

管理

当前激活

控制

控制

旧版本

新版本

控制

控制

Deployment

ReplicaSet-v1

ReplicaSet-v2

ReplicaSet-v3

Pod-1

Pod-2

Pod-3

Pod-4

核心关系

  • Deployment:声明式管理层,负责更新策略、版本管理
  • ReplicaSet:执行层,负责维持指定数量的 Pod 副本
  • Pod:实际运行的容器实例

二、Deployment 核心架构深度解析

2.1 Deployment Controller 工作流程

// 简化的 DeploymentController Reconcile 逻辑
func (dc *DeploymentController) Reconcile(key string) error {
    // 1. 获取 Deployment 对象
    deployment := getDeployment(key)
    
    // 2. 查找所有关联的 ReplicaSet
    rsList := getReplicaSets(deployment)
    
    // 3. 获取最新的 ReplicaSet
    newRS := getNewReplicaSet(deployment, rsList)
    
    // 4. 执行滚动更新
    if isRollingUpdate(deployment) {
        dc.rollingUpdate(deployment, newRS, rsList)
    }
    
    // 5. 清理过旧的 ReplicaSet(保留历史版本)
    dc.cleanupDeployment(deployment, rsList)
    
    // 6. 更新 Deployment 状态
    updateDeploymentStatus(deployment)
    
    return nil
}

2.2 滚动更新算法详解

算法核心:渐进式替换
初始状态:
  RS-v1 (3 replicas): [Pod-1, Pod-2, Pod-3]
  
第1轮迭代:
  RS-v1 (2 replicas): [Pod-1, Pod-2]
  RS-v2 (1 replica):  [Pod-4]
  
第2轮迭代:
  RS-v1 (1 replica):  [Pod-1]
  RS-v2 (2 replicas): [Pod-4, Pod-5]
  
第3轮迭代:
  RS-v1 (0 replicas): []
  RS-v2 (3 replicas): [Pod-4, Pod-5, Pod-6]
关键参数控制
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1       # 最多超出期望副本数1个
      maxUnavailable: 0 # 最多允许0个不可用(保证零宕机)

参数计算示例

期望副本数:3
maxSurge: 1
maxUnavailable: 0

第1轮:
  允许最大Pod数 = 3 + 1 = 4
  允许最小可用Pod数 = 3 - 0 = 3
  所以:缩容1个旧Pod → 扩容1个新Pod
  
第2轮:
  当前:旧2个,新1个(总共3个)
  允许最大Pod数 = 4
  允许最小可用Pod数 = 3
  所以:再缩容1个旧Pod → 扩容1个新Pod

2.3 状态机设计

Deployment 通过 Conditions 维护状态:

type DeploymentCondition struct {
    Type               DeploymentConditionType `json:"type"`
    Status             ConditionStatus         `json:"status"`
    LastUpdateTime     metav1.Time             `json:"lastUpdateTime"`
    LastTransitionTime metav1.Time             `json:"lastTransitionTime"`
    Reason             string                  `json:"reason"`
    Message            string                  `json:"message"`
}

type DeploymentConditionType string

const (
    DeploymentAvailable    DeploymentConditionType = "Available"
    DeploymentProgressing  DeploymentConditionType = "Progressing"
    DeploymentReplicaFailure DeploymentConditionType = "ReplicaFailure"
)

典型状态流转

Progressing=True, Available=False  → 正在部署
Progressing=True, Available=True   → 部署成功
Progressing=False, Available=True  → 部署完成
Progressing=False, Available=False → 部署失败

三、滚动更新策略深度对比

3.1 RollingUpdate(滚动更新)

策略详解
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2        # 20% 超出
      maxUnavailable: 1  # 10% 不可用
  template:
    spec:
      containers:
      - name: app
        image: myapp:v2.0
        readinessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 10
更新过程可视化
时间线:
T0: [v1,v1,v1,v1,v1,v1,v1,v1,v1,v1]  ← 初始状态(10个v1)
T1: [v1,v1,v1,v1,v1,v1,v1,v1,v1,v2]  ← 添加1个v2(maxUnavailable=1)
T2: [v1,v1,v1,v1,v1,v1,v1,v1,v2,v2]  ← 再添加1个v2
T3: [v1,v1,v1,v1,v1,v1,v1,v2,v2,v2]  ← 同时移除1个v1(maxSurge=2)
T4: [v1,v1,v1,v1,v1,v1,v2,v2,v2,v2]  
T5: [v1,v1,v1,v1,v1,v2,v2,v2,v2,v2]  
T6: [v1,v1,v1,v1,v2,v2,v2,v2,v2,v2]  
T7: [v1,v1,v1,v2,v2,v2,v2,v2,v2,v2]  
T8: [v1,v1,v2,v2,v2,v2,v2,v2,v2,v2]  
T9: [v1,v2,v2,v2,v2,v2,v2,v2,v2,v2]  
T10:[v2,v2,v2,v2,v2,v2,v2,v2,v2,v2]  ← 更新完成

关键依赖:ReadinessProbe 确保新 Pod 就绪后才继续更新

适用场景

适合

  • Web 服务(需要持续可用)
  • API 服务(零宕机要求)
  • 微服务(支持灰度发布)

不适合

  • 需要同时切换所有实例的场景
  • 新版本与旧版本不兼容的情况

3.2 Recreate(重建更新)

策略详解
apiVersion: apps/v1
kind: Deployment
metadata:
  name: batch-processor
spec:
  replicas: 3
  strategy:
    type: Recreate  # 先删除所有旧Pod,再创建新Pod
  template:
    spec:
      containers:
      - name: processor
        image: myapp:v2.0
更新过程
T0: [v1,v1,v1]
T1: []           ← 全部删除(服务中断!)
T2: [v2,v2,v2]   ← 全部创建
适用场景

适合

  • 数据库迁移(需要所有实例同时更新)
  • 批处理任务(可以接受短暂中断)
  • 版本不兼容的更新

不适合

  • 需要高可用的服务
  • 用户面向的 Web 应用

3.3 策略对比矩阵

特性 RollingUpdate Recreate
服务可用性 ✅ 持续可用 ❌ 更新期间中断
资源占用 ️ 短暂超出(maxSurge) ✅ 不会超出
更新速度 ⚠️ 较慢(逐步替换) ✅ 较快
兼容性要求 ✅ 新旧版本需兼容 ❌ 可以不兼容
典型场景 Web服务、微服务 数据库、批处理

四、版本管理与回滚机制

4.1 Revision History

Deployment 通过 revisionHistoryLimit 保留历史版本:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  revisionHistoryLimit: 10  # 保留最近10个版本(默认10)
  template:
    spec:
      containers:
      - name: app
        image: myapp:v1.0

版本存储机制

Deployment/myapp
├── ReplicaSet/myapp-7d9b8c6f5 (revision=1, image=v1.0)
├── ReplicaSet/myapp-8e0c9d7g6 (revision=2, image=v1.1)
├── ReplicaSet/myapp-9f1d0e8h7 (revision=3, image=v1.2) ← 当前版本
└── ReplicaSet/myapp-0g2e1f9i8 (revision=4, image=v1.3) ← 最新版本
    ↑
    如果 revisionHistoryLimit=3,则 revision=1 的 RS 会被清理

4.2 回滚操作详解

查看历史版本
# 查看更新历史
$ kubectl rollout history deployment/myapp
deployment.apps/myapp 
REVISION  CHANGE-CAUSE
1         kubectl apply --filename=deployment-v1.yaml
2         kubectl set image deployment/myapp myapp=myapp:v1.1
3         kubectl set image deployment/myapp myapp=myapp:v1.2

# 查看特定版本详情
$ kubectl rollout history deployment/myapp --revision=2
deployment.apps/myapp with revision #2
Pod Template:
  Labels:  app=myapp
           pod-template-hash=8e0c9d7g6
  Containers:
   myapp:
    Image:      myapp:v1.1
    Port:       80/TCP
执行回滚
# 回滚到上一个版本
$ kubectl rollout undo deployment/myapp
deployment.apps/myapp rolled back

# 回滚到指定版本
$ kubectl rollout undo deployment/myapp --to-revision=1
deployment.apps/myapp rolled back

# 暂停回滚(用于调试)
$ kubectl rollout pause deployment/myapp

# 恢复回滚
$ kubectl rollout resume deployment/myapp

回滚原理

回滚到 revision=1:
1. 创建新的 ReplicaSet(revision=4),内容与 revision=1 相同
2. 将新 RS 的 replicas 设置为期望值
3. 逐步缩容当前 RS(revision=3)
4. 逐步扩容新 RS(revision=4)
5. 更新 Deployment 状态

注意:回滚本身也是一次"更新",会生成新的 revision!

4.3 自动回滚机制

配置进度超时
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  progressDeadlineSeconds: 600  # 10分钟内必须完成更新
  minReadySeconds: 30           # Pod 就绪后等待30秒才认为更新成功
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

超时检测逻辑

if (当前时间 - 更新开始时间) > progressDeadlineSeconds {
    if (新RS的Ready副本数 < 期望副本数) {
        // 标记更新失败
        setCondition(DeploymentProgressing, False, "ProgressDeadlineExceeded")
        
        // 自动回滚(如果配置了)
        rollback()
    }
}
监控与告警
# 查看更新状态
$ kubectl rollout status deployment/myapp
Waiting for deployment "myapp" rollout to finish: 2 out of 3 new replicas have been updated...

# 在 CI/CD 中使用
kubectl rollout status deployment/myapp --timeout=600s
if [ $? -ne 0 ]; then
    echo "Deployment failed, rolling back..."
    kubectl rollout undo deployment/myapp
    exit 1
fi

五、生产环境最佳实践

5.1 零宕机发布配置

apiVersion: apps/v1
kind: Deployment
metadata:
  name: production-web
spec:
  replicas: 5
  minReadySeconds: 10  # 就绪后等待10秒,确保稳定
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 每次只增加1个Pod
      maxUnavailable: 0  # 不允许任何Pod不可用(零宕机)
  template:
    metadata:
      labels:
        app: web
        version: v2.0
    spec:
      # 优雅关闭配置
      terminationGracePeriodSeconds: 30
      containers:
      - name: web
        image: myapp:v2.0
        ports:
        - containerPort: 8080
        
        # 就绪探针(决定是否可以接收流量)
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 3
          successThreshold: 1
          
        # 存活探针(决定是否需要重启)
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10
          failureThreshold: 3
          
        # 优雅退出处理
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 5"]  # 给5秒时间处理现有请求
              
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi

5.2 蓝绿部署模式

虽然 Deployment 本身不支持蓝绿部署,但可以通过 Service 实现:

# 蓝色版本(当前生产)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
      version: blue
  template:
    metadata:
      labels:
        app: web
        version: blue
    spec:
      containers:
      - name: web
        image: myapp:v1.0

# 绿色版本(新版本)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
      version: green
  template:
    metadata:
      labels:
        app: web
        version: green
    spec:
      containers:
      - name: web
        image: myapp:v2.0

# Service 指向蓝色版本
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  selector:
    app: web
    version: blue  # 切换到 green 即完成蓝绿切换
  ports:
  - port: 80
    targetPort: 8080

切换命令

# 验证绿色版本健康
kubectl get pods -l app=web,version=green

# 切换流量到绿色版本
kubectl patch service web-service -p '{"spec":{"selector":{"version":"green"}}}'

# 验证切换
kubectl get svc web-service -o jsonpath='{.spec.selector}'

5.3 金丝雀发布(Canary)

# 主版本(90%流量)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-canary
spec:
  replicas: 9
  selector:
    matchLabels:
      app: web
  template:
    spec:
      containers:
      - name: web
        image: myapp:v1.0

# 金丝雀版本(10%流量)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-canary
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
      canary: "true"
  template:
    spec:
      containers:
      - name: web
        image: myapp:v2.0

流量切分:通过 Service 的 label selector 权重分配(需要 Istio 或 Nginx Ingress 支持)


六、常见问题排查指南

6.1 更新卡住不动

现象
$ kubectl rollout status deployment/myapp
Waiting for deployment "myapp" rollout to finish: 1 old replicas are pending termination...
排查步骤
# 1. 检查 Pod 状态
kubectl get pods -l app=myapp
kubectl describe pod <pod-name>

# 2. 检查是否有 Pod 卡在 Terminating
kubectl get pods | grep Terminating

# 3. 查看 Pod 事件
kubectl describe pod <pod-name> | grep -A 10 Events

# 4. 检查 Finalizer
kubectl get pod <pod-name> -o jsonpath='{.metadata.finalizers}'

# 5. 强制删除(慎用)
kubectl delete pod <pod-name> --grace-period=0 --force

常见原因

  • 容器进程未响应 SIGTERM 信号
  • Volume 卸载失败(如 NFS 网络问题)
  • Finalizer 阻塞删除

6.2 回滚失败

现象
$ kubectl rollout undo deployment/myapp --to-revision=1
error: unable to rollout deployment "myapp": revision 1 not found
解决方案
# 1. 查看可用版本
kubectl rollout history deployment/myapp

# 2. 如果 revisionHistoryLimit 太小导致历史版本被清理
# 修改 Deployment 增加保留数量
kubectl patch deployment myapp -p '{"spec":{"revisionHistoryLimit":20}}'

# 3. 手动回滚(重新应用旧配置)
kubectl apply -f deployment-v1.yaml

6.3 Pod 无法就绪导致更新阻塞

问题根因
新 Pod 创建 → ReadinessProbe 检查 → 失败 → 无法接收流量
→ Deployment 等待 Pod Ready → 超时 → 更新卡住
排查命令
# 检查 ReadinessProbe 配置
kubectl get deployment myapp -o jsonpath='{.spec.template.spec.containers[0].readinessProbe}'

# 查看 Pod 就绪状态
kubectl get pods -l app=myapp -o wide

# 检查 Pod 日志
kubectl logs <pod-name>

# 进入 Pod 调试
kubectl exec -it <pod-name> -- /bin/sh

修复示例

# 增加 initialDelaySeconds,给应用更多启动时间
readinessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 30  # 从5秒增加到30秒
  periodSeconds: 5
  failureThreshold: 5      # 允许更多失败次数

6.4 资源不足导致更新失败

现象
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  1m    default-scheduler  0/3 nodes are available: 3 Insufficient cpu.
解决方案
# 1. 检查节点资源
kubectl top nodes

# 2. 临时降低 replicas 完成更新
kubectl scale deployment myapp --replicas=2

# 3. 更新完成后恢复
kubectl scale deployment myapp --replicas=5

# 4. 或者调整资源请求
kubectl set resources deployment myapp -c myapp --requests=cpu=50m,memory=64Mi

七、高级技巧与扩展

7.1 使用 kubectl 快速操作

# 设置镜像
kubectl set image deployment/myapp nginx=nginx:1.22

# 设置环境变量
kubectl set env deployment/myapp APP_ENV=production

# 设置资源限制
kubectl set resources deployment/myapp -c app --limits=cpu=500m,memory=256Mi

# 暴露端口
kubectl expose deployment/myapp --port=80 --target-port=8080 --type=LoadBalancer

# 自动扩缩容
kubectl autoscale deployment/myapp --min=3 --max=10 --cpu-percent=80

7.2 与 ConfigMap/Secret 集成

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
      - name: app
        image: myapp:v2.0
        envFrom:
        - configMapRef:
            name: app-config
        - secretRef:
            name: app-secret
        volumeMounts:
        - name: config-volume
          mountPath: /etc/config
      volumes:
      - name: config-volume
        configMap:
          name: app-config

配置更新自动重启

# 添加 annotation 触发重启
spec:
  template:
    metadata:
      annotations:
        checksum/config: "sha256sum-of-configmap"  # 配置变化时更新此值

7.3 与 HPA(水平自动扩缩容)集成

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

八、总结

8.1 核心要点回顾

概念 要点
滚动更新 通过 maxSurge 和 maxUnavailable 控制更新节奏
版本管理 通过 ReplicaSet 保留历史,revisionHistoryLimit 控制数量
回滚机制 支持手动和自动回滚,回滚本身也生成新版本
探针配置 ReadinessProbe 决定流量,LivenessProbe 决定重启
零宕机 maxUnavailable=0 + ReadinessProbe 保证

8.2 设计原则

DO

  • 始终配置 ReadinessProbe 和 LivenessProbe
  • 设置合理的 progressDeadlineSeconds
  • 保留足够的 revisionHistoryLimit
  • 使用 RollingUpdate 策略实现零宕机
  • 配置 terminationGracePeriodSeconds 优雅关闭

DON’T

  • 不要在生产环境使用 Recreate 策略(除非必要)
  • 不要将 maxUnavailable 设置为大于0(如需零宕机)
  • 不要忘记配置 resource limits
  • 不要忽略 Pod 的优雅退出处理

8.3 下一步学习

  1. 深入理解

  2. 实战演练

    • 配置 GitOps 流水线(ArgoCD/Flux)
    • 实现蓝绿/金丝雀发布
    • 集成监控系统(Prometheus + Grafana)
  3. 高级主题

    • 自定义 Deployment Controller
    • 多集群部署策略
    • Service Mesh 流量管理

参考资料

  1. 官方文档

  2. 源码

  3. 最佳实践


版权声明:本文为原创技术文档,转载请保留原文链接。
联系方式:如有疑问或建议,欢迎在评论区交流讨论。


⭐ 如果觉得本文有帮助,请点赞支持!

系列文章:Kubernetes Controller 深度解析系列

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐