五、应用的管理者 - Deployment 与 ReplicaSet
1. 为什么需要Deployment?从痛点说起
1.1 手动管理Pod的噩梦
还记得我们之前创建Pod的方式吗?每次都要手动写YAML,一个个创建Pod。想象一下这样的场景:
场景1:应用升级的困境
# 现在的做法(痛苦版)1. 创建新版本Pod:kubectl apply -f app-v2-pod.yaml2. 等待新Pod就绪3. 手动删除旧Pod:kubectl delete pod app-v1-pod4. 如果出问题?再手动创建v1版本?5. 有10个Pod?重复10遍!😱场景2:Pod挂了怎么办?
# 某个Pod突然崩溃了kubectl get pods# app-pod-1 1/1 Running 0 5m# app-pod-2 0/1 Error 0 2m ← 挂了!# app-pod-3 1/1 Running 0 5m
# 你需要:1. 发现它挂了(盯着监控?)2. 手动重建:kubectl apply -f app-pod-2.yaml3. 24小时值班?😭场景3:扩容需求来了
# 老板:流量暴增,赶紧从3个Pod扩到10个!# 你:好的!(开始复制粘贴YAML...)
cat > app-pod-4.yaml <<EOFapiVersion: v1kind: Podmetadata: name: app-pod-4 # 手动改名 labels: app: myappspec: containers: - name: app image: myapp:v1EOF
# 重复7次...手指抽筋 😵这就是为什么需要Deployment!
1.2 Deployment:应用管理的”自动驾驶”
把Deployment想象成一个智能管家,你只需要告诉它:
- 我要运行什么应用
- 我要几个副本
- 用什么镜像版本
剩下的事情,它全包了!
Deployment能做什么?
1. 自动创建和管理Pod └─ 你说要3个副本,它就创建3个Pod
2. 自动故障恢复 └─ Pod挂了?自动重建! └─ 节点挂了?自动在其他节点重建!
3. 滚动更新(零停机升级) └─ 旧版本逐步替换为新版本 └─ 用户无感知,服务不中断
4. 一键回滚 └─ 新版本有问题?一条命令回退到旧版本
5. 弹性伸缩 └─ 一条命令从3个副本扩到10个 └─ 或者缩减到1个
6. 版本历史管理 └─ 记录每次更新,想回到哪个版本都行1.3 架构解析:Deployment、ReplicaSet、Pod三兄弟
它们的关系像这样:
分工明确:
| 角色 | 职责 | 比喻 |
|---|---|---|
| Deployment | 版本管理、更新策略、回滚 | 项目经理 |
| ReplicaSet | 维持Pod数量、自动恢复 | 质检员 |
| Pod | 运行容器 | 工人 |
1.4 工作流程:从创建到运行
创建Deployment的完整过程:
自动恢复演示:
1.5 Deployment vs 手动创建Pod对比
| 特性 | 手动创建Pod | 使用Deployment |
|---|---|---|
| 创建复杂度 | 每个Pod一个YAML | 一个YAML管理所有 |
| 副本管理 | 手动复制粘贴N次 | replicas: N,一行搞定 |
| 故障恢复 | 需要人工介入 | 自动重建(秒级) |
| 滚动更新 | 手动删旧建新 | 自动滚动(零停机) |
| 回滚 | 手动重建旧版本 | 一条命令 |
| 扩缩容 | 手动增删Pod | 一条命令 |
| 版本历史 | 无 | 自动记录 |
| 适用场景 | 学习、临时测试 | 生产环境必备 |
核心价值:
手动管理Pod = 开手动挡汽车 ✗ 累 ✗ 容易出错 ✗ 效率低 ✗ 无法应对复杂场景
使用Deployment = 开自动挡汽车 ✓ 省心 ✓ 可靠 ✓ 高效 ✓ 生产级别小结:Deployment的核心价值
为什么需要Deployment?
- 自动化 - 不需要手动创建和管理每个Pod
- 高可用 - Pod挂了自动重建,保证服务永不中断
- 零停机更新 - 滚动更新,用户无感知
- 快速回滚 - 新版本有问题?一键回退
- 弹性伸缩 - 根据负载动态调整副本数
- 声明式管理 - 描述期望状态,K8s自动实现
一句话总结:
Deployment让你能够像管理1个Pod一样管理1000个Pod,这就是它的魔力!
2. Deployment配置详解:YAML资源清单剖析
2.1 最简单的Deployment示例
先看一个最基础的例子,理解核心配置:
apiVersion: apps/v1 # API版本kind: Deployment # 资源类型metadata: name: nginx-deployment # Deployment名称 labels: app: nginx # Deployment自身的标签spec: replicas: 3 # 期望的Pod副本数 selector: # Pod选择器(重要!) matchLabels: app: nginx # 匹配哪些Pod template: # Pod模板(下面是Pod的定义) metadata: labels: app: nginx # Pod的标签(必须与selector匹配) spec: containers: - name: nginx image: nginx:1.20 ports: - containerPort: 80关键字段解析:
| 字段 | 作用 | 类比 |
|---|---|---|
replicas | 期望的Pod副本数 | ”我要3个工人” |
selector | 选择管理哪些Pod | ”标记为app=nginx的Pod都是我的” |
template | Pod模板 | ”按这个模板创建Pod” |
特别注意:selector和template.labels必须匹配!
selector: matchLabels: app: nginx ← 必须匹配
template: metadata: labels: app: nginx ← 必须匹配如果不匹配会报错:
Error: selector does not match template labels2.2 完整配置示例:生产级别
apiVersion: apps/v1kind: Deploymentmetadata: name: web-app namespace: default labels: app: web version: v1 environment: production annotations: description: "Web应用前端服务"spec: # === 副本管理 === replicas: 5
# === 选择器 === selector: matchLabels: app: web
# === 更新策略 === strategy: type: RollingUpdate # 滚动更新 rollingUpdate: maxSurge: 1 # 更新时最多多几个Pod(可以是数字或百分比) maxUnavailable: 0 # 更新时最多不可用几个Pod
# === 版本历史保留 === revisionHistoryLimit: 10 # 保留10个历史版本
# === Pod模板 === template: metadata: labels: app: web version: v1 spec: # === 容器配置 === containers: - name: web image: reg.westos.org/library/nginx-php:v2 ports: - containerPort: 80 name: http protocol: TCP
# === 资源限制 === resources: requests: # 最低需求 cpu: "100m" # 0.1核 memory: "128Mi" limits: # 上限 cpu: "500m" # 0.5核 memory: "512Mi"
# === 健康检查 === livenessProbe: # 存活探针 httpGet: path: / port: 80 initialDelaySeconds: 10 periodSeconds: 5
readinessProbe: # 就绪探针 httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 3
# === 环境变量 === env: - name: APP_VERSION value: "v2.0" - name: DB_HOST value: "mysql-service"
# === 重启策略 === restartPolicy: Always配置详解:
第1层:Deployment基本信息├─ metadata: 名称、命名空间、标签└─ spec: Deployment规格
第2层:副本和更新策略├─ replicas: 副本数├─ selector: Pod选择器├─ strategy: 更新策略└─ revisionHistoryLimit: 历史版本数
第3层:Pod模板└─ template ├─ metadata: Pod标签 └─ spec: Pod规格 ├─ containers: 容器列表 ├─ resources: 资源配置 ├─ livenessProbe: 存活探针 ├─ readinessProbe: 就绪探针 └─ env: 环境变量2.3 更新策略详解:RollingUpdate vs Recreate
Kubernetes支持两种更新策略:
1. RollingUpdate(滚动更新)- 默认推荐
strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # 更新过程中,最多比replicas多几个Pod maxUnavailable: 0 # 更新过程中,最多有几个Pod不可用参数详解:
maxSurge(冲刺数量) └─ 控制更新时能创建多少额外的Pod └─ 值越大,更新越快,但资源消耗越多
示例:replicas=3, maxSurge=1 ┌────────────────────────────────┐ │ 更新过程中最多4个Pod同时存在 │ │ 3个旧版本 + 1个新版本 = 4个 │ └────────────────────────────────┘
maxUnavailable(最大不可用数) └─ 控制更新时允许多少Pod不可用 └─ 值越小,服务稳定性越高
示例:replicas=3, maxUnavailable=1 ┌────────────────────────────────┐ │ 更新过程中至少2个Pod可用 │ │ 3 - 1 = 2个Pod必须健康 │ └────────────────────────────────┘滚动更新流程演示:
初始状态(3个Pod,v1版本):┌──────┐ ┌──────┐ ┌──────┐│ v1-1 │ │ v1-2 │ │ v1-3 ││ Ready│ │ Ready│ │ Ready│└──────┘ └──────┘ └──────┘
配置:replicas=3, maxSurge=1, maxUnavailable=0
步骤1:创建1个新Pod(v2)┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ v1-1 │ │ v1-2 │ │ v1-3 │ │ v2-1 ││ Ready│ │ Ready│ │ Ready│ │ 启动中│└──────┘ └──────┘ └──────┘ └──────┘总数:4(3旧+1新)maxSurge允许
步骤2:v2-1就绪后,删除1个旧Pod┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ v1-1 │ │ v1-2 │ │ ✗ │ │ v2-1 ││ Ready│ │ Ready│ │ 删除 │ │ Ready│└──────┘ └──────┘ └──────┘ └──────┘可用:3(2旧+1新)maxUnavailable=0保证
步骤3:创建第2个新Pod┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ v1-1 │ │ v1-2 │ │ v2-1 │ │ v2-2 ││ Ready│ │ Ready│ │ Ready│ │ 启动中│└──────┘ └──────┘ └──────┘ └──────┘
步骤4:v2-2就绪后,删除1个旧Pod┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ v1-1 │ │ ✗ │ │ v2-1 │ │ v2-2 ││ Ready│ │ 删除 │ │ Ready│ │ Ready│└──────┘ └──────┘ └──────┘ └──────┘
步骤5:创建第3个新Pod┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ v1-1 │ │ v2-1 │ │ v2-2 │ │ v2-3 ││ Ready│ │ Ready│ │ Ready│ │ 启动中│└──────┘ └──────┘ └──────┘ └──────┘
步骤6:v2-3就绪后,删除最后的旧Pod┌──────┐ ┌──────┐ ┌──────┐│ v2-1 │ │ v2-2 │ │ v2-3 ││ Ready│ │ Ready│ │ Ready│└──────┘ └──────┘ └──────┘更新完成!全部v2版本特点:
- ✅ 零停机(始终有Pod可用)
- ✅ 渐进式(逐个替换)
- ✅ 可控制(通过参数调节速度)
- ✅ 可回滚(发现问题立即停止)
2. Recreate(重建策略)
strategy: type: Recreate流程:先删所有旧Pod,再创建所有新Pod
初始状态(3个Pod,v1版本):┌──────┐ ┌──────┐ ┌──────┐│ v1-1 │ │ v1-2 │ │ v1-3 ││ Ready│ │ Ready│ │ Ready│└──────┘ └──────┘ └──────┘
步骤1:删除所有旧Pod┌──────┐ ┌──────┐ ┌──────┐│ ✗ │ │ ✗ │ │ ✗ ││ 删除 │ │ 删除 │ │ 删除 │└──────┘ └──────┘ └──────┘⚠️ 服务完全不可用!
步骤2:创建所有新Pod┌──────┐ ┌──────┐ ┌──────┐│ v2-1 │ │ v2-2 │ │ v2-3 ││ 启动中│ │ 启动中│ │ 启动中│└──────┘ └──────┘ └──────┘
完成:所有Pod就绪┌──────┐ ┌──────┐ ┌──────┐│ v2-1 │ │ v2-2 │ │ v2-3 ││ Ready│ │ Ready│ │ Ready│└──────┘ └──────┘ └──────┘特点:
- ✗ 有停机时间
- ✓ 简单粗暴
- ✓ 不会出现新旧版本共存
使用场景:
适合Recreate: ✓ 不能容忍新旧版本共存(如数据库schema变更) ✓ 测试环境 ✓ 单副本应用
推荐RollingUpdate: ✓ Web应用 ✓ 微服务 ✓ 生产环境2.4 滚动更新参数最佳实践
场景1:快速更新,可以接受短暂不可用
strategy: rollingUpdate: maxSurge: 50% # 允许多50%的Pod maxUnavailable: 50% # 允许50%不可用场景2:稳定优先,零停机更新(推荐生产环境)
strategy: rollingUpdate: maxSurge: 25% # 逐步增加25% maxUnavailable: 0 # 不允许不可用场景3:资源受限,不能多Pod
strategy: rollingUpdate: maxSurge: 0 # 不允许超过replicas maxUnavailable: 1 # 每次只替换1个参数对比:
| 场景 | maxSurge | maxUnavailable | 更新速度 | 资源消耗 | 可用性 |
|---|---|---|---|---|---|
| 快速更新 | 50% | 50% | ⚡⚡⚡ | 🔥🔥 | ⭐⭐ |
| 生产推荐 | 25% | 0 | ⚡⚡ | 🔥🔥 | ⭐⭐⭐ |
| 资源受限 | 0 | 1 | ⚡ | 🔥 | ⭐⭐⭐ |
3. Deployment操作实战:升级、回滚、扩缩容
3.1 应用升级:从v1到v2
升级方式有三种:
方法1:修改YAML文件并重新apply(推荐)
# 修改deployment.yaml中的镜像版本vi nginx-deployment.yaml# 将 image: nginx:1.20 改为 image: nginx:1.21
# 应用更改kubectl apply -f nginx-deployment.yaml方法2:使用kubectl set image命令
# 语法:kubectl set image deployment/<名称> <容器名>=<新镜像>kubectl set image deployment/nginx-deployment nginx=nginx:1.21
# 如果有多个容器kubectl set image deployment/nginx-deployment \ nginx=nginx:1.21 \ sidecar=busybox:1.30.1方法3:使用kubectl edit直接编辑
kubectl edit deployment nginx-deployment# 在编辑器中修改image字段# 保存退出后自动应用推荐方式对比:
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| apply -f | 有版本记录、可审计 | 需要改文件 | 生产环境(推荐) |
| set image | 快速、命令行操作 | 无文件记录 | 临时测试 |
| edit | 所见即所得 | 容易误操作 | 紧急修复 |
3.2 监控更新进度
实时查看滚动更新过程:
# 查看Deployment状态kubectl get deployment nginx-deployment
# 实时监控(watch模式)kubectl get deployment nginx-deployment -w
# 查看详细更新过程kubectl rollout status deployment/nginx-deployment输出示例:
$ kubectl rollout status deployment/nginx-deploymentWaiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...deployment "nginx-deployment" successfully rolled out查看ReplicaSet变化:
kubectl get replicaset# NAME DESIRED CURRENT READY AGE# nginx-deployment-7d64c8b9f5 3 3 3 5m ← 旧版本(保留)# nginx-deployment-86b7dbdd8b 3 3 3 1m ← 新版本(活跃)查看Pod变化:
kubectl get pods -l app=nginx --watch# 可以看到旧Pod逐个删除,新Pod逐个创建3.3 查看更新历史
Kubernetes会自动记录每次Deployment的更新历史:
# 查看历史版本kubectl rollout history deployment/nginx-deployment
# 输出示例:# REVISION CHANGE-CAUSE# 1 <none># 2 <none># 3 kubectl set image deployment/nginx-deployment nginx=nginx:1.21如何让历史记录更有意义?
# 方法1:在apply时添加--record参数(已废弃,但仍可用)kubectl apply -f nginx-deployment.yaml --record
# 方法2:使用kubernetes.io/change-cause注解(推荐)kubectl annotate deployment/nginx-deployment \ kubernetes.io/change-cause="升级到nginx 1.21版本"查看特定版本的详细信息:
# 查看版本2的详细配置kubectl rollout history deployment/nginx-deployment --revision=23.4 回滚操作:犯错不可怕
场景:新版本有bug,需要紧急回退
1. 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment2. 回滚到指定版本
# 先查看历史kubectl rollout history deployment/nginx-deployment
# 回滚到版本2kubectl rollout undo deployment/nginx-deployment --to-revision=2回滚过程:
当前状态(v3有bug):┌──────┐ ┌──────┐ ┌──────┐│ v3-1 │ │ v3-2 │ │ v3-3 ││ Error│ │ Error│ │ Error│└──────┘ └──────┘ └──────┘
执行回滚:kubectl rollout undo deployment/nginx-deployment
开始回滚到v2:┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ v3-1 │ │ v3-2 │ │ v3-3 │ │ v2-1 ││ Error│ │ Error│ │ Error│ │ 启动中│└──────┘ └──────┘ └──────┘ └──────┘
逐步替换(就像滚动更新一样):┌──────┐ ┌──────┐ ┌──────┐│ v2-1 │ │ v2-2 │ │ v2-3 ││ Ready│ │ Ready│ │ Ready│└──────┘ └──────┘ └──────┘回滚完成!服务恢复正常回滚也遵循滚动更新策略:
- ✅ 零停机
- ✅ 渐进式
- ✅ 可以随时暂停
3.5 暂停和恢复更新
场景:发现问题,立即暂停更新
# 暂停更新kubectl rollout pause deployment/nginx-deployment
# 此时更新会停止,部分Pod是新版本,部分是旧版本# 可以验证新版本是否正常
# 确认无问题后,恢复更新kubectl rollout resume deployment/nginx-deployment
# 如果有问题,直接回滚kubectl rollout undo deployment/nginx-deployment金丝雀发布示例:
# 1. 准备更新kubectl set image deployment/nginx-deployment nginx=nginx:1.21
# 2. 立即暂停(只更新少量Pod)kubectl rollout pause deployment/nginx-deployment
# 3. 验证新版本(可能只有1-2个Pod是新版本)curl http://new-pod-ip # 测试新版本
# 4. 如果正常,恢复更新kubectl rollout resume deployment/nginx-deployment
# 5. 如果异常,回滚kubectl rollout undo deployment/nginx-deployment3.6 手动扩缩容:应对流量变化
扩容:增加副本数
# 方法1:使用kubectl scalekubectl scale deployment/nginx-deployment --replicas=10
# 方法2:修改YAML并apply# 将replicas: 3 改为 replicas: 10kubectl apply -f nginx-deployment.yaml扩容过程:
当前状态(3个Pod):┌──────┐ ┌──────┐ ┌──────┐│ Pod-1│ │ Pod-2│ │ Pod-3│└──────┘ └──────┘ └──────┘
扩容到10个:kubectl scale deployment/nginx-deployment --replicas=10
K8s立即创建7个新Pod:┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ Pod-1│ │ Pod-2│ │ Pod-3│ │ Pod-4│ │ Pod-5│└──────┘ └──────┘ └──────┘ └──────┘ └──────┘┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐│ Pod-6│ │ Pod-7│ │ Pod-8│ │ Pod-9│ │Pod-10│└──────┘ └──────┘ └──────┘ └──────┘ └──────┘
通常10-30秒内完成缩容:减少副本数
# 缩减到1个副本kubectl scale deployment/nginx-deployment --replicas=1缩容过程:
当前状态(10个Pod):10个Pod全部运行中
缩容到1个:kubectl scale deployment/nginx-deployment --replicas=1
K8s选择9个Pod删除(通常是最新创建的):┌──────┐│ Pod-1│ ← 保留1个└──────┘其他9个Pod被终止
5-10秒内完成查看扩缩容效果:
# 实时监控kubectl get pods -l app=nginx -w
# 查看Deployment状态kubectl get deployment nginx-deployment# NAME READY UP-TO-DATE AVAILABLE AGE# nginx-deployment 10/10 10 10 5m3.7 自动扩缩容:HPA(Horizontal Pod Autoscaler)
HPA可以根据CPU、内存等指标自动调整Pod数量。
前提:必须先部署Metrics Server
步骤1:部署Metrics Server
# 下载部署文件wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 修改配置(重要!)vi components.yaml
# 在Deployment的容器args中添加:# - --kubelet-insecure-tls# - --kubelet-preferred-address-types=InternalIP
# 应用部署kubectl apply -f components.yaml
# 验证是否正常kubectl get pods -n kube-system | grep metrics-serverkubectl top nodes # 查看节点资源使用情况kubectl top pods # 查看Pod资源使用情况步骤2:为Deployment配置资源请求
# HPA需要知道Pod的资源需求才能计算spec: template: spec: containers: - name: nginx image: nginx:1.20 resources: requests: cpu: 100m # 必须配置! memory: 128Mi limits: cpu: 500m memory: 512Mi步骤3:创建HPA
# 方法1:命令行创建kubectl autoscale deployment nginx-deployment \ --min=2 \ --max=10 \ --cpu-percent=50
# 方法2:使用YAML(更灵活)cat > nginx-hpa.yaml <<EOFapiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: nginx-hpaspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-deployment minReplicas: 2 # 最少2个Pod maxReplicas: 10 # 最多10个Pod metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 # CPU平均使用率50% - type: Resource resource: name: memory target: type: Utilization averageUtilization: 70 # 内存平均使用率70%EOF
kubectl apply -f nginx-hpa.yamlHPA配置详解:
minReplicas: 2 # 最小副本数(即使负载为0也保持)maxReplicas: 10 # 最大副本数(保护集群资源)
metrics: # 监控指标- type: Resource # 资源类型 resource: name: cpu # CPU使用率 target: averageUtilization: 50 # 目标:50%工作原理:
监控周期:默认15秒检查一次
场景1:CPU使用率 > 50%(需要扩容)┌─────────────────────────────────┐│ 当前:3个Pod,CPU使用率70% ││ HPA计算:70% > 50%,需要扩容 ││ 新副本数 = 3 × (70/50) = 4.2 ││ 向上取整 = 5个Pod │└─────────────────────────────────┘HPA执行:kubectl scale deployment --replicas=5
场景2:CPU使用率 < 50%(需要缩容)┌─────────────────────────────────┐│ 当前:5个Pod,CPU使用率30% ││ HPA计算:30% < 50%,需要缩容 ││ 新副本数 = 5 × (30/50) = 3 │└─────────────────────────────────┘HPA执行:kubectl scale deployment --replicas=3
注意:缩容有保护机制,默认5分钟才缩一次查看HPA状态:
# 查看HPAkubectl get hpa
# 输出示例:# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE# nginx-hpa Deployment/nginx-deployment 45%/50% 2 10 3 5m
# TARGETS显示:当前值/目标值
# 查看HPA详细信息kubectl describe hpa nginx-hpa测试HPA(压力测试):
# 方法1:使用Apache Benchkubectl run -it --rm load-generator --image=busybox -- /bin/sh# 在容器内执行:while true; do wget -q -O- http://nginx-service; done
# 方法2:使用专业压测工具kubectl run load-generator --image=k8s.gcr.io/hpa-example \ --requests=cpu=200m -- /bin/sh -c "while true; do echo 'test'; done"
# 观察HPA自动扩容kubectl get hpa -wkubectl get deployment nginx-deployment -wHPA的智能特性:
1. 防抖动机制 └─ 扩容:立即执行 └─ 缩容:等待5分钟(避免频繁缩放)
2. 渐进式扩缩 └─ 不会一次性从3个扩到100个 └─ 每次最多翻倍(3→6→12...)
3. 优雅终止 └─ 缩容时会等待Pod处理完请求
4. 多指标支持 └─ 可以同时基于CPU、内存、自定义指标3.8 扩缩容最佳实践
手动 vs 自动扩缩容选择:
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 流量可预测(如定时任务) | 手动 + 定时任务 | 精确控制,节省资源 |
| 流量不可预测(如Web服务) | HPA | 自动适应,省心 |
| 突发流量(如秒杀) | 预扩容 + HPA | 快速响应 |
| 资源受限 | 手动 | 精确控制成本 |
HPA配置建议:
# 生产环境推荐配置minReplicas: 3 # 至少3个保证高可用maxReplicas: 20 # 限制上限保护集群metrics:- type: Resource resource: name: cpu target: averageUtilization: 70 # 70%比较合理(不要设太低)为什么CPU目标不要设太低?
CPU目标=30%: ✗ 资源利用率低(浪费) ✗ Pod数量过多(管理复杂) ✗ 成本高
CPU目标=70%: ✓ 资源利用合理 ✓ 留有缓冲空间 ✓ 成本可控
CPU目标=90%: ✗ 扩容响应慢 ✗ 没有缓冲 ✗ 容易过载4. 实战演练:完整的Deployment生命周期
4.1 实验1:创建第一个Deployment
步骤1:准备镜像(使用之前的nginx-php镜像)
# 确认镜像存在curl -u admin:12345 http://reg.westos.org/v2/library/nginx-php/tags/list步骤2:创建Deployment YAML
cd /root/k8s-yaml
cat > nginx-deployment.yaml <<EOFapiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deployment labels: app: nginxspec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: reg.westos.org/library/nginx-php:v1 ports: - containerPort: 80 env: - name: APP_VERSION value: "v1.0" resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 10 periodSeconds: 5 readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 3EOF步骤3:部署Deployment
# 创建Deploymentkubectl apply -f nginx-deployment.yaml
# 查看Deploymentkubectl get deployment nginx-deployment
# 查看ReplicaSetkubectl get replicaset
# 查看Podkubectl get pods -l app=nginx -o wide
# 查看详细信息kubectl describe deployment nginx-deployment预期输出:
NAME READY UP-TO-DATE AVAILABLE AGEnginx-deployment 3/3 3 3 30s
NAME DESIRED CURRENT READY AGEnginx-deployment-7d64c8b9f5 3 3 3 30s
NAME READY STATUS IP NODEnginx-deployment-7d64c8b9f5-abc 1/1 Running 10.244.1.10 node1nginx-deployment-7d64c8b9f5-def 1/1 Running 10.244.2.11 node2nginx-deployment-7d64c8b9f5-ghi 1/1 Running 10.244.1.12 node1步骤4:创建Service访问应用
cat > nginx-service.yaml <<EOFapiVersion: v1kind: Servicemetadata: name: nginx-servicespec: type: NodePort selector: app: nginx ports: - port: 80 targetPort: 80 nodePort: 30080EOF
kubectl apply -f nginx-service.yaml
# 测试访问curl http://192.168.100.21:30080预期输出:
Nginx-PHP ContainerHostname: nginx-deployment-7d64c8b9f5-abcServer IP: 10.244.1.10
Database connected successfully!MySQL Version: 8.0.444.2 实验2:滚动更新升级到v2
步骤1:确认v2镜像存在
# 如果还没有v2镜像,需要先构建(参考第四章)docker images | grep nginx-php步骤2:执行滚动更新
# 方法1:修改YAML文件sed -i 's/nginx-php:v1/nginx-php:v2/' nginx-deployment.yamlsed -i 's/v1.0/v2.0/' nginx-deployment.yaml
# 添加更新记录kubectl annotate deployment/nginx-deployment \ kubernetes.io/change-cause="升级到v2版本"
# 应用更新kubectl apply -f nginx-deployment.yaml
# 方法2:直接使用命令(更快)kubectl set image deployment/nginx-deployment \ nginx=reg.westos.org/library/nginx-php:v2
kubectl annotate deployment/nginx-deployment \ kubernetes.io/change-cause="升级到v2版本"步骤3:实时监控更新过程
# 终端1:监控更新状态kubectl rollout status deployment/nginx-deployment
# 终端2:监控Pod变化kubectl get pods -l app=nginx -w
# 终端3:监控ReplicaSetkubectl get replicaset -w观察到的现象:
1. 创建1个新Pod(v2) nginx-deployment-86b7dbdd8b-new1 0/1 ContainerCreating
2. 新Pod就绪后,删除1个旧Pod(v1) nginx-deployment-7d64c8b9f5-abc 1/1 Terminating nginx-deployment-86b7dbdd8b-new1 1/1 Running
3. 重复此过程,直到所有Pod都是v2
总耗时:约1-2分钟(取决于镜像大小)步骤4:验证更新结果
# 查看所有Pod的镜像版本kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
# 访问应用验证curl http://192.168.100.21:30080 | grep Version# 输出:Nginx-PHP - Version: v2.0
# 查看历史版本kubectl rollout history deployment/nginx-deployment4.3 实验3:回滚到v1版本
场景:发现v2版本有bug,需要紧急回退
步骤1:模拟v2版本故障
# 假设我们发现v2版本有严重bug# 查看当前版本kubectl rollout history deployment/nginx-deployment# REVISION CHANGE-CAUSE# 1 创建初始版本# 2 升级到v2版本步骤2:执行回滚
# 回滚到上一个版本(v1)kubectl rollout undo deployment/nginx-deployment
# 或者回滚到指定版本kubectl rollout undo deployment/nginx-deployment --to-revision=1
# 监控回滚过程kubectl rollout status deployment/nginx-deployment步骤3:验证回滚结果
# 查看Pod镜像kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'# 应该显示:reg.westos.org/library/nginx-php:v1
# 访问应用验证curl http://192.168.100.21:30080 | grep Version# 输出:Nginx-PHP Container(v1版本)
# 查看历史(注意版本号变化)kubectl rollout history deployment/nginx-deployment# REVISION CHANGE-CAUSE# 2 升级到v2版本# 3 回滚到v1版本4.4 实验4:手动扩缩容
场景1:扩容应对流量增长
# 当前3个副本,扩容到10个kubectl scale deployment/nginx-deployment --replicas=10
# 观察扩容过程kubectl get pods -l app=nginx -w
# 查看Deployment状态kubectl get deployment nginx-deployment# NAME READY UP-TO-DATE AVAILABLE AGE# nginx-deployment 10/10 10 10 5m
# 查看Pod分布kubectl get pods -l app=nginx -o wide | awk '{print $7}' | sort | uniq -c# 5 node1# 5 node2场景2:缩容节省资源
# 流量下降,缩减到2个副本kubectl scale deployment/nginx-deployment --replicas=2
# 观察缩容过程kubectl get pods -l app=nginx -w
# 验证服务仍可访问for i in {1..10}; do curl -s http://192.168.100.21:30080 | grep Hostname; done# 虽然只有2个Pod,但Service会轮询负载均衡场景3:恢复到初始副本数
# 恢复到3个副本kubectl scale deployment/nginx-deployment --replicas=34.5 实验5:部署Metrics Server并配置HPA
步骤1:部署Metrics Server
# 下载配置文件wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server.yaml
# 修改配置(添加参数)vi metrics-server.yaml
# 找到Deployment的containers.args部分,添加:# - --kubelet-insecure-tls# - --kubelet-preferred-address-types=InternalIP
# 完整示例:spec: containers: - args: - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls # 添加这行 image: registry.k8s.io/metrics-server/metrics-server:v0.6.4 name: metrics-server步骤2:应用部署
kubectl apply -f metrics-server.yaml
# 等待Metrics Server就绪kubectl get pods -n kube-system | grep metrics-serverkubectl wait --for=condition=ready pod -l k8s-app=metrics-server -n kube-system --timeout=300s
# 验证(需要等待1-2分钟收集数据)sleep 60kubectl top nodeskubectl top pods预期输出:
$ kubectl top nodesNAME CPU(cores) CPU% MEMORY(bytes) MEMORY%master 234m 11% 1456Mi 38%node1 156m 7% 1123Mi 29%node2 145m 7% 1089Mi 28%
$ kubectl top podsNAME CPU(cores) MEMORY(bytes)nginx-deployment-7d64c8b9f5-abc 1m 15Minginx-deployment-7d64c8b9f5-def 1m 14Minginx-deployment-7d64c8b9f5-ghi 1m 16Mi步骤3:更新Deployment添加资源请求
# 修改deployment.yaml,确保有resources配置vi nginx-deployment.yaml
# 确认包含resources: resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi
# 重新应用kubectl apply -f nginx-deployment.yaml步骤4:创建HPA
cat > nginx-hpa.yaml <<EOFapiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: nginx-hpaspec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginx-deployment minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50EOF
kubectl apply -f nginx-hpa.yaml
# 查看HPA状态kubectl get hpa# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE# nginx-hpa Deployment/nginx-deployment 2%/50% 2 10 2 10s步骤5:测试HPA自动扩容
# 创建压力测试Podkubectl run load-generator \ --image=reg.westos.org/library/busybox:1.30.1 \ --restart=Never \ --rm -it -- sh -c \ "while true; do wget -q -O- http://nginx-service; done"
# 在另一个终端监控HPAkubectl get hpa nginx-hpa -w
# 在第三个终端监控Pod数量kubectl get pods -l app=nginx -w观察到的现象:
1. CPU使用率逐渐上升 TARGETS: 2%/50% → 45%/50% → 75%/50%
2. HPA触发扩容(约15-30秒后) REPLICAS: 2 → 4 → 6
3. 新Pod创建并就绪 nginx-deployment-xxx-new4 ContainerCreating → Running nginx-deployment-xxx-new5 ContainerCreating → Running
4. CPU使用率下降 TARGETS: 75%/50% → 40%/50%
5. 停止压测后,等待5分钟,HPA自动缩容 REPLICAS: 6 → 4 → 2步骤6:清理压测环境
# 停止load-generator(Ctrl+C)
# 等待自动缩容(约5分钟)kubectl get hpa nginx-hpa -w
# 查看最终状态kubectl get deployment nginx-deploymentkubectl get hpa nginx-hpa4.6 实验6:金丝雀发布(暂停/恢复)
场景:谨慎发布v2版本,先更新部分Pod验证
步骤1:准备更新
# 假设当前是v1,要更新到v2kubectl set image deployment/nginx-deployment \ nginx=reg.westos.org/library/nginx-php:v2步骤2:立即暂停更新
# 在更新开始后立即暂停kubectl rollout pause deployment/nginx-deployment
# 查看当前状态(可能有1-2个Pod已更新)kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'步骤3:测试新版本
# 找到新版本Pod的IPNEW_POD_IP=$(kubectl get pods -l app=nginx -o jsonpath='{.items[0].status.podIP}')
# 多次访问测试for i in {1..20}; do curl -s http://$NEW_POD_IP | grep Version; done
# 通过Service访问(会看到新旧版本混合)for i in {1..20}; do curl -s http://192.168.100.21:30080 | grep Version; done步骤4:决策
# 如果新版本正常,恢复更新kubectl rollout resume deployment/nginx-deployment
# 如果新版本有问题,回滚kubectl rollout undo deployment/nginx-deployment4.7 常用管理命令总结
# === 创建和删除 ===kubectl apply -f deployment.yaml # 创建/更新kubectl delete deployment <name> # 删除kubectl delete -f deployment.yaml # 通过文件删除
# === 查看状态 ===kubectl get deployment # 列出所有Deploymentkubectl get deployment <name> # 查看特定Deploymentkubectl get deployment <name> -o yaml # 查看完整YAMLkubectl describe deployment <name> # 查看详细信息
# === 更新操作 ===kubectl set image deployment/<name> <container>=<image> # 更新镜像kubectl edit deployment <name> # 编辑配置kubectl patch deployment <name> -p '{json}' # 部分更新
# === 回滚操作 ===kubectl rollout status deployment/<name> # 查看更新状态kubectl rollout history deployment/<name> # 查看历史kubectl rollout undo deployment/<name> # 回滚到上一版本kubectl rollout undo deployment/<name> --to-revision=2 # 回滚到指定版本kubectl rollout pause deployment/<name> # 暂停更新kubectl rollout resume deployment/<name> # 恢复更新
# === 扩缩容 ===kubectl scale deployment/<name> --replicas=5 # 手动扩缩容kubectl autoscale deployment/<name> --min=2 --max=10 --cpu-percent=50 # 自动扩缩容
# === 调试 ===kubectl logs deployment/<name> # 查看日志kubectl logs -f deployment/<name> # 实时日志kubectl exec -it deployment/<name> -- bash # 进入容器小结:Deployment实战总结
核心概念回顾:
- Deployment = Pod模板 + 副本管理 + 更新策略
- ReplicaSet负责维持Pod数量,Deployment负责版本管理
- 滚动更新实现零停机部署
- 回滚机制保证快速恢复
- HPA实现自动弹性伸缩
生产环境最佳实践:
✓ 始终使用Deployment管理无状态应用✓ 配置健康检查(liveness + readiness)✓ 设置资源限制(requests + limits)✓ 使用RollingUpdate策略✓ 保留足够的历史版本(revisionHistoryLimit: 10)✓ 配置HPA应对流量波动✓ 使用YAML文件管理,纳入版本控制✓ 添加meaningful的change-cause注解