6979 字
35 分钟
03.Kubernetes 学习笔记:Deployment 与 ReplicaSet 应用管理

五、应用的管理者 - Deployment 与 ReplicaSet#

1. 为什么需要Deployment?从痛点说起#

1.1 手动管理Pod的噩梦#

还记得我们之前创建Pod的方式吗?每次都要手动写YAML,一个个创建Pod。想象一下这样的场景:

场景1:应用升级的困境

Terminal window
# 现在的做法(痛苦版)
1. 创建新版本Pod:kubectl apply -f app-v2-pod.yaml
2. 等待新Pod就绪
3. 手动删除旧Pod:kubectl delete pod app-v1-pod
4. 如果出问题?再手动创建v1版本?
5. 有10个Pod?重复10遍!😱

场景2:Pod挂了怎么办?

Terminal window
# 某个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.yaml
3. 24小时值班?😭

场景3:扩容需求来了

Terminal window
# 老板:流量暴增,赶紧从3个Pod扩到10个!
# 你:好的!(开始复制粘贴YAML...)
cat > app-pod-4.yaml <<EOF
apiVersion: v1
kind: Pod
metadata:
name: app-pod-4 # 手动改名
labels:
app: myapp
spec:
containers:
- name: app
image: myapp:v1
EOF
# 重复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三兄弟#

它们的关系像这样:

graph TD D["Deployment<br/>版本管理、更新策略、回滚<br/>replicas: 3<br/>strategy: RollingUpdate<br/>image: myapp:v2"] R["ReplicaSet<br/>维持Pod数量<br/>期望: 3 | 当前: 3 | 就绪: 3"] P1["Pod-1<br/>Running"] P2["Pod-2<br/>Running"] P3["Pod-3<br/>Running"] D -->|管理| R R --> P1 R --> P2 R --> P3

分工明确:

角色职责比喻
Deployment版本管理、更新策略、回滚项目经理
ReplicaSet维持Pod数量、自动恢复质检员
Pod运行容器工人

1.4 工作流程:从创建到运行#

创建Deployment的完整过程:

flowchart TD A["步骤1: 创建Deployment<br/>kubectl apply -f deployment.yaml"] --> B B["Deployment Controller监听<br/>需要创建ReplicaSet"] --> C C["步骤2: 创建ReplicaSet<br/>nginx-deployment-7d64c8b9f5<br/>期望副本数: 3"] --> D D["ReplicaSet Controller监听<br/>需要创建3个Pod"] --> E E["步骤3: 创建Pods<br/>- nginx-deployment-xxx-abc12<br/>- nginx-deployment-xxx-def34<br/>- nginx-deployment-xxx-ghi56"] --> F F["步骤4: Pod调度<br/>Scheduler分配到不同节点<br/>kubelet拉取镜像并启动"] --> G G["步骤5: 持续监控<br/>ReplicaSet监控Pod状态<br/>自动恢复故障Pod"]

自动恢复演示:

flowchart LR subgraph 正常状态 P1["Pod-1<br/>Running"] P2["Pod-2<br/>Running"] P3["Pod-3<br/>Running"] end subgraph 故障发生 P1b["Pod-1<br/>Running"] P2b["Pod-2<br/>💥 Crashed"] P3b["Pod-3<br/>Running"] end subgraph 自动恢复 P1c["Pod-1<br/>Running"] P4["Pod-4<br/>Running<br/>(新建)"] P3c["Pod-3<br/>Running"] end 正常状态 -->|"Pod-2崩溃"| 故障发生 故障发生 -->|"ReplicaSet自动重建<br/>(10秒内)"| 自动恢复

1.5 Deployment vs 手动创建Pod对比#

特性手动创建Pod使用Deployment
创建复杂度每个Pod一个YAML一个YAML管理所有
副本管理手动复制粘贴N次replicas: N,一行搞定
故障恢复需要人工介入自动重建(秒级)
滚动更新手动删旧建新自动滚动(零停机)
回滚手动重建旧版本一条命令
扩缩容手动增删Pod一条命令
版本历史自动记录
适用场景学习、临时测试生产环境必备

核心价值:

手动管理Pod = 开手动挡汽车
✗ 累
✗ 容易出错
✗ 效率低
✗ 无法应对复杂场景
使用Deployment = 开自动挡汽车
✓ 省心
✓ 可靠
✓ 高效
✓ 生产级别

小结:Deployment的核心价值#

为什么需要Deployment?

  1. 自动化 - 不需要手动创建和管理每个Pod
  2. 高可用 - Pod挂了自动重建,保证服务永不中断
  3. 零停机更新 - 滚动更新,用户无感知
  4. 快速回滚 - 新版本有问题?一键回退
  5. 弹性伸缩 - 根据负载动态调整副本数
  6. 声明式管理 - 描述期望状态,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都是我的”
templatePod模板”按这个模板创建Pod”

特别注意:selector和template.labels必须匹配!

selector:
matchLabels:
app: nginx ← 必须匹配
template:
metadata:
labels:
app: nginx ← 必须匹配

如果不匹配会报错:

Error: selector does not match template labels

2.2 完整配置示例:生产级别#

apiVersion: apps/v1
kind: Deployment
metadata:
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个

参数对比:

场景maxSurgemaxUnavailable更新速度资源消耗可用性
快速更新50%50%⚡⚡⚡🔥🔥⭐⭐
生产推荐25%0⚡⚡🔥🔥⭐⭐⭐
资源受限01🔥⭐⭐⭐

3. Deployment操作实战:升级、回滚、扩缩容#

3.1 应用升级:从v1到v2#

升级方式有三种:

方法1:修改YAML文件并重新apply(推荐)

Terminal window
# 修改deployment.yaml中的镜像版本
vi nginx-deployment.yaml
# 将 image: nginx:1.20 改为 image: nginx:1.21
# 应用更改
kubectl apply -f nginx-deployment.yaml

方法2:使用kubectl set image命令

Terminal window
# 语法: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直接编辑

Terminal window
kubectl edit deployment nginx-deployment
# 在编辑器中修改image字段
# 保存退出后自动应用

推荐方式对比:

方式优点缺点适用场景
apply -f有版本记录、可审计需要改文件生产环境(推荐)
set image快速、命令行操作无文件记录临时测试
edit所见即所得容易误操作紧急修复

3.2 监控更新进度#

实时查看滚动更新过程:

Terminal window
# 查看Deployment状态
kubectl get deployment nginx-deployment
# 实时监控(watch模式)
kubectl get deployment nginx-deployment -w
# 查看详细更新过程
kubectl rollout status deployment/nginx-deployment

输出示例:

Terminal window
$ kubectl rollout status deployment/nginx-deployment
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: 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变化:

Terminal window
kubectl get replicaset
# NAME DESIRED CURRENT READY AGE
# nginx-deployment-7d64c8b9f5 3 3 3 5m ← 旧版本(保留)
# nginx-deployment-86b7dbdd8b 3 3 3 1m ← 新版本(活跃)

查看Pod变化:

Terminal window
kubectl get pods -l app=nginx --watch
# 可以看到旧Pod逐个删除,新Pod逐个创建

3.3 查看更新历史#

Kubernetes会自动记录每次Deployment的更新历史:

Terminal window
# 查看历史版本
kubectl rollout history deployment/nginx-deployment
# 输出示例:
# REVISION CHANGE-CAUSE
# 1 <none>
# 2 <none>
# 3 kubectl set image deployment/nginx-deployment nginx=nginx:1.21

如何让历史记录更有意义?

Terminal window
# 方法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版本"

查看特定版本的详细信息:

Terminal window
# 查看版本2的详细配置
kubectl rollout history deployment/nginx-deployment --revision=2

3.4 回滚操作:犯错不可怕#

场景:新版本有bug,需要紧急回退

1. 回滚到上一个版本

Terminal window
kubectl rollout undo deployment/nginx-deployment

2. 回滚到指定版本

Terminal window
# 先查看历史
kubectl rollout history deployment/nginx-deployment
# 回滚到版本2
kubectl 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 暂停和恢复更新#

场景:发现问题,立即暂停更新

Terminal window
# 暂停更新
kubectl rollout pause deployment/nginx-deployment
# 此时更新会停止,部分Pod是新版本,部分是旧版本
# 可以验证新版本是否正常
# 确认无问题后,恢复更新
kubectl rollout resume deployment/nginx-deployment
# 如果有问题,直接回滚
kubectl rollout undo deployment/nginx-deployment

金丝雀发布示例:

Terminal window
# 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-deployment

3.6 手动扩缩容:应对流量变化#

扩容:增加副本数

Terminal window
# 方法1:使用kubectl scale
kubectl scale deployment/nginx-deployment --replicas=10
# 方法2:修改YAML并apply
# 将replicas: 3 改为 replicas: 10
kubectl 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秒内完成

缩容:减少副本数

Terminal window
# 缩减到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秒内完成

查看扩缩容效果:

Terminal window
# 实时监控
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

3.7 自动扩缩容:HPA(Horizontal Pod Autoscaler)#

HPA可以根据CPU、内存等指标自动调整Pod数量

前提:必须先部署Metrics Server

步骤1:部署Metrics Server

Terminal window
# 下载部署文件
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-server
kubectl 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

Terminal window
# 方法1:命令行创建
kubectl autoscale deployment nginx-deployment \
--min=2 \
--max=10 \
--cpu-percent=50
# 方法2:使用YAML(更灵活)
cat > nginx-hpa.yaml <<EOF
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
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.yaml

HPA配置详解:

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状态:

Terminal window
# 查看HPA
kubectl 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(压力测试):

Terminal window
# 方法1:使用Apache Bench
kubectl 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 -w
kubectl get deployment nginx-deployment -w

HPA的智能特性:

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镜像)

Terminal window
# 确认镜像存在
curl -u admin:12345 http://reg.westos.org/v2/library/nginx-php/tags/list

步骤2:创建Deployment YAML

Terminal window
cd /root/k8s-yaml
cat > nginx-deployment.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
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: 3
EOF

步骤3:部署Deployment

Terminal window
# 创建Deployment
kubectl apply -f nginx-deployment.yaml
# 查看Deployment
kubectl get deployment nginx-deployment
# 查看ReplicaSet
kubectl get replicaset
# 查看Pod
kubectl get pods -l app=nginx -o wide
# 查看详细信息
kubectl describe deployment nginx-deployment

预期输出:

NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 30s
NAME DESIRED CURRENT READY AGE
nginx-deployment-7d64c8b9f5 3 3 3 30s
NAME READY STATUS IP NODE
nginx-deployment-7d64c8b9f5-abc 1/1 Running 10.244.1.10 node1
nginx-deployment-7d64c8b9f5-def 1/1 Running 10.244.2.11 node2
nginx-deployment-7d64c8b9f5-ghi 1/1 Running 10.244.1.12 node1

步骤4:创建Service访问应用

Terminal window
cat > nginx-service.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080
EOF
kubectl apply -f nginx-service.yaml
# 测试访问
curl http://192.168.100.21:30080

预期输出:

Nginx-PHP Container
Hostname: nginx-deployment-7d64c8b9f5-abc
Server IP: 10.244.1.10
Database connected successfully!
MySQL Version: 8.0.44

4.2 实验2:滚动更新升级到v2#

步骤1:确认v2镜像存在

Terminal window
# 如果还没有v2镜像,需要先构建(参考第四章)
docker images | grep nginx-php

步骤2:执行滚动更新

Terminal window
# 方法1:修改YAML文件
sed -i 's/nginx-php:v1/nginx-php:v2/' nginx-deployment.yaml
sed -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:实时监控更新过程

Terminal window
# 终端1:监控更新状态
kubectl rollout status deployment/nginx-deployment
# 终端2:监控Pod变化
kubectl get pods -l app=nginx -w
# 终端3:监控ReplicaSet
kubectl 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:验证更新结果

Terminal window
# 查看所有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-deployment

4.3 实验3:回滚到v1版本#

场景:发现v2版本有bug,需要紧急回退

步骤1:模拟v2版本故障

Terminal window
# 假设我们发现v2版本有严重bug
# 查看当前版本
kubectl rollout history deployment/nginx-deployment
# REVISION CHANGE-CAUSE
# 1 创建初始版本
# 2 升级到v2版本

步骤2:执行回滚

Terminal window
# 回滚到上一个版本(v1)
kubectl rollout undo deployment/nginx-deployment
# 或者回滚到指定版本
kubectl rollout undo deployment/nginx-deployment --to-revision=1
# 监控回滚过程
kubectl rollout status deployment/nginx-deployment

步骤3:验证回滚结果

Terminal window
# 查看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:扩容应对流量增长

Terminal window
# 当前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:缩容节省资源

Terminal window
# 流量下降,缩减到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:恢复到初始副本数

Terminal window
# 恢复到3个副本
kubectl scale deployment/nginx-deployment --replicas=3

4.5 实验5:部署Metrics Server并配置HPA#

步骤1:部署Metrics Server

Terminal window
# 下载配置文件
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:应用部署

Terminal window
kubectl apply -f metrics-server.yaml
# 等待Metrics Server就绪
kubectl get pods -n kube-system | grep metrics-server
kubectl wait --for=condition=ready pod -l k8s-app=metrics-server -n kube-system --timeout=300s
# 验证(需要等待1-2分钟收集数据)
sleep 60
kubectl top nodes
kubectl top pods

预期输出:

Terminal window
$ kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master 234m 11% 1456Mi 38%
node1 156m 7% 1123Mi 29%
node2 145m 7% 1089Mi 28%
$ kubectl top pods
NAME CPU(cores) MEMORY(bytes)
nginx-deployment-7d64c8b9f5-abc 1m 15Mi
nginx-deployment-7d64c8b9f5-def 1m 14Mi
nginx-deployment-7d64c8b9f5-ghi 1m 16Mi

步骤3:更新Deployment添加资源请求

Terminal window
# 修改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

Terminal window
cat > nginx-hpa.yaml <<EOF
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
EOF
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自动扩容

Terminal window
# 创建压力测试Pod
kubectl 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"
# 在另一个终端监控HPA
kubectl 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:清理压测环境

Terminal window
# 停止load-generator(Ctrl+C)
# 等待自动缩容(约5分钟)
kubectl get hpa nginx-hpa -w
# 查看最终状态
kubectl get deployment nginx-deployment
kubectl get hpa nginx-hpa

4.6 实验6:金丝雀发布(暂停/恢复)#

场景:谨慎发布v2版本,先更新部分Pod验证

步骤1:准备更新

Terminal window
# 假设当前是v1,要更新到v2
kubectl set image deployment/nginx-deployment \
nginx=reg.westos.org/library/nginx-php:v2

步骤2:立即暂停更新

Terminal window
# 在更新开始后立即暂停
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:测试新版本

Terminal window
# 找到新版本Pod的IP
NEW_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:决策

Terminal window
# 如果新版本正常,恢复更新
kubectl rollout resume deployment/nginx-deployment
# 如果新版本有问题,回滚
kubectl rollout undo deployment/nginx-deployment

4.7 常用管理命令总结#

Terminal window
# === 创建和删除 ===
kubectl apply -f deployment.yaml # 创建/更新
kubectl delete deployment <name> # 删除
kubectl delete -f deployment.yaml # 通过文件删除
# === 查看状态 ===
kubectl get deployment # 列出所有Deployment
kubectl get deployment <name> # 查看特定Deployment
kubectl get deployment <name> -o yaml # 查看完整YAML
kubectl 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实战总结#

核心概念回顾:

  1. Deployment = Pod模板 + 副本管理 + 更新策略
  2. ReplicaSet负责维持Pod数量,Deployment负责版本管理
  3. 滚动更新实现零停机部署
  4. 回滚机制保证快速恢复
  5. HPA实现自动弹性伸缩

生产环境最佳实践:

✓ 始终使用Deployment管理无状态应用
✓ 配置健康检查(liveness + readiness)
✓ 设置资源限制(requests + limits)
✓ 使用RollingUpdate策略
✓ 保留足够的历史版本(revisionHistoryLimit: 10)
✓ 配置HPA应对流量波动
✓ 使用YAML文件管理,纳入版本控制
✓ 添加meaningful的change-cause注解

03.Kubernetes 学习笔记:Deployment 与 ReplicaSet 应用管理
https://dev-null-sec.github.io/posts/03-k8s学习笔记-deployment与replicaset应用管理/
作者
DevNull
发布于
2024-11-10
许可协议
CC BY-NC-SA 4.0