Deployment、ReplicaSet 与 Pod 的关系
三层嵌套关系 ┌────────────────────────────────────────────────────────┐ │ Deployment nginx-deployment (replicas: 3) │ │ │ │ 管理 ──► ┌──────────────────────────────────────┐ │ │ │ ReplicaSet nginx-rs-abc123 (v1) │ │ │ │ nginx-rs-def456 (v2) │ │ │ └──────────────────────────────────────┘ │ │ 管理 ──► ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ Pod-1 │ │ Pod-2 │ │ Pod-3 │ │ │ └────────┘ └────────┘ └────────┘ │ └────────────────────────────────────────────────────────┘ 更新时:Deployment 创建新 ReplicaSet,逐步缩减旧 RS,扩充新 RS
Deployment
无状态应用的最高层抽象。管理 ReplicaSet,提供声明式更新、版本历史、滚动升级/回滚能力。是部署无状态服务的首选。
ReplicaSet
保证指定数量的 Pod 副本始终运行。通常不直接创建,由 Deployment 管理。滚动更新时,每个版本对应一个 ReplicaSet。
完整 Deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: production
annotations:
kubernetes.io/change-cause: "升级到 nginx 1.25,修复 CVE-2023-xxxx" # 用于回滚历史记录
spec:
replicas: 3
revisionHistoryLimit: 5 # 保留最近 5 个 ReplicaSet(用于回滚),默认 10
selector:
matchLabels:
app: nginx
strategy: # 更新策略
type: RollingUpdate # RollingUpdate(默认)或 Recreate
rollingUpdate:
maxSurge: 1 # 更新期间最多多出几个 Pod(可用百分比)
maxUnavailable: 0 # 更新期间最多有几个 Pod 不可用(0 = 零停机)
template:
metadata:
labels:
app: nginx
version: v1.25
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
滚动更新策略详解
RollingUpdate 过程(maxSurge:1, maxUnavailable:0, replicas:3) 初始状态 [v1] [v1] [v1] (3个运行) 第1步 [v1] [v1] [v1] [v2] (创建1个新Pod,maxSurge=1) 等待 v2 就绪... 第2步 [v1] [v1] [v2] (删除1个旧Pod,始终>=3个就绪) 第3步 [v1] [v1] [v2] [v2] (再创建1个 v2) 等待就绪... 第4步 [v1] [v2] [v2] 第5步 [v1] [v2] [v2] [v2] 等待就绪... 完成 [v2] [v2] [v2] (全部更新完毕)
# 触发滚动更新(修改镜像)
kubectl set image deployment/nginx-deployment nginx=nginx:1.26
# 实时查看更新进度
kubectl rollout status deployment/nginx-deployment
# 暂停更新(金丝雀部署场景)
kubectl rollout pause deployment/nginx-deployment
# 恢复更新
kubectl rollout resume deployment/nginx-deployment
# 查看版本历史
kubectl rollout history deployment/nginx-deployment
# 回滚到上一版本
kubectl rollout undo deployment/nginx-deployment
# 回滚到指定版本(revision 编号来自 history)
kubectl rollout undo deployment/nginx-deployment --to-revision=2
更新策略选择
RollingUpdate(默认):适合无状态服务,实现零停机更新。
Recreate:先删除所有旧 Pod,再创建新 Pod,有短暂停机。适用于不能并存两个版本(如做了不兼容 DB 迁移)的场景。
HPA 水平自动伸缩
HPA(Horizontal Pod Autoscaler)根据观测到的指标自动调整 Deployment 的 replicas 数量。
apiVersion: autoscaling/v2 # v2 版本支持自定义指标
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
scaleTargetRef: # 要控制的目标工作负载
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
minReplicas: 2 # 最小副本数
maxReplicas: 10 # 最大副本数
metrics:
- type: Resource # 基于资源指标(CPU/内存)
resource:
name: cpu
target:
type: Utilization # 目标 CPU 利用率(相对于 requests)
averageUtilization: 70 # 所有 Pod 平均 CPU 使用率目标 70%
- type: Resource
resource:
name: memory
target:
type: AverageValue # 目标内存绝对值
averageValue: 200Mi
behavior: # 伸缩行为控制(防止频繁波动)
scaleDown:
stabilizationWindowSeconds: 300 # 缩容冷却 5 分钟
policies:
- type: Pods
value: 1 # 每次最多缩减 1 个 Pod
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 0 # 扩容无冷却,立即响应
policies:
- type: Percent
value: 100 # 每次最多扩容当前数量的 100%(翻倍)
periodSeconds: 15
HPA 需要 Metrics Server
HPA 依赖 metrics-server 提供 Pod CPU/内存指标。如果集群没有安装 metrics-server,HPA 无法工作,并显示 <unknown>/70%。安装命令:kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
PodDisruptionBudget
PDB(Pod 干扰预算)保证在节点维护、集群升级等自愿中断场景中,始终有足够数量的 Pod 保持可用,防止服务不可用。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: nginx-pdb
spec:
minAvailable: 2 # 最少保留 2 个 Pod 可用
# 或者用 maxUnavailable: 1 # 最多允许 1 个 Pod 不可用
selector:
matchLabels:
app: nginx
工作负载类型对比
| 类型 | 适用场景 | 特点 |
|---|---|---|
| Deployment | 无状态 Web 服务、API 服务 | 随机 Pod 名称、Pod 可任意替换、支持滚动更新 |
| StatefulSet | 数据库、消息队列、Zookeeper | 稳定的 Pod 标识(pod-0/1/2)、有序启停、持久存储 |
| DaemonSet | 日志采集、监控 agent、网络插件 | 每个 Node 上运行且仅运行一个 Pod |
| Job | 批处理任务、数据迁移 | 运行到完成(completion),支持并行 |
| CronJob | 定时任务、定期备份 | 基于 cron 表达式定期创建 Job |
StatefulSet 示例
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql # 必须指向一个 Headless Service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates: # 每个 Pod 自动创建独立的 PVC
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
# StatefulSet 创建的 Pod 名称固定为:mysql-0, mysql-1, mysql-2
# DNS 地址:mysql-0.mysql.default.svc.cluster.local
常见错误:在 StatefulSet 中误用 emptyDir
StatefulSet 的 Pod 重启后如果使用 emptyDir 存储,数据会丢失。必须使用 volumeClaimTemplates 创建 PVC,或挂载已有的 PVC,才能在 Pod 重启/重调度后保留数据。