K8s的核心是控制器模式:声明期望状态→控制器持续调谐→实际状态趋向期望状态。Deployment是最常用的控制器,管理ReplicaSet,ReplicaSet管理Pod。
┌──────────── Deployment ────────────┐
│ metadata.name: my-app │
│ spec.replicas: 3 │
│ spec.selector: app=my-app │
│ spec.strategy: RollingUpdate │
│ ┌────── ReplicaSet (v2) ──────┐ │
│ │ replicas: 3 │ │
│ │ template: image:v2.0 │ │
│ │ ┌────┐ ┌────┐ ┌────┐ │ │
│ │ │Pod1│ │Pod2│ │Pod3│ │ │
│ │ │ v2 │ │ v2 │ │ v2 │ │ │
│ │ └────┘ └────┘ └────┘ │ │
│ └────────────────────────────┘ │
│ ┌────── ReplicaSet (v1) ──────┐ │
│ │ replicas: 0 (已缩容) │ │ ← 保留用于回滚
│ └────────────────────────────┘ │
└────────────────────────────────────┘
# deployment-complete.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: default
labels:
app: web-app
version: v1
spec:
# Pod副本数
replicas: 3
# 选择器:Deployment通过此匹配管理的Pod
selector:
matchLabels:
app: web-app
matchExpressions:
- key: version
operator: In
values: ["v1", "v2"]
# 保留的旧ReplicaSet数量(用于回滚)
revisionHistoryLimit: 10
# Pod就绪前的最小就绪时间
minReadySeconds: 5
# 进度截止时间
progressDeadlineSeconds: 600
# 更新策略
strategy:
type: RollingUpdate # RollingUpdate | Recreate
rollingUpdate:
maxSurge: 1 # 滚动更新时最多多出1个Pod(数字或百分比)
maxUnavailable: 0 # 滚动更新时最多不可用0个Pod
# Pod模板
template:
metadata:
labels:
app: web-app
version: v1
spec:
containers:
- name: web
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
# ✅ 验证通过
kubectl apply -f deployment-complete.yaml --record
kubectl get deployments
# NAME READY UP-TO-DATE AVAILABLE AGE
# web-app 3/3 3 3 30s
滚动更新过程(maxSurge=1, maxUnavailable=0, replicas=3):
初始状态:
[v1 Pod] [v1 Pod] [v1 Pod] ← 3个v1 Pod
步骤1:创建1个新Pod(maxSurge=1)
[v1 Pod] [v1 Pod] [v1 Pod] [v2 Pod:Creating]
总数=4,可用=3 ✅
步骤2:v2就绪,删除1个v1(保持可用≥3-0=3)
[v1 Pod] [v1 Pod] [v2 Pod:Ready] [v1 Pod:Terminating]
总数=4→3,可用=3 ✅
步骤3:继续滚动
[v1 Pod] [v2 Pod] [v2 Pod:Creating]
最终:
[v2 Pod] [v2 Pod] [v2 Pod] ← 3个v2 Pod
关键:maxUnavailable=0 → 零停机!
# 创建初始Deployment
kubectl create deployment roll-demo --image=nginx:1.24 --replicas=3
# ✅ 验证通过
kubectl get pods -l app=roll-demo
# NAME READY STATUS RESTARTS AGE
# roll-demo-7d8c6f5b4d-abc12 1/1 Running 0 30s
# roll-demo-7d8c6f5b4d-def34 1/1 Running 0 30s
# roll-demo-7d8c6f5b4d-ghi56 1/1 Running 0 30s
# 触发滚动更新(更新镜像版本)
kubectl set image deployment/roll-demo nginx=nginx:1.25
# 实时观察滚动更新
kubectl rollout status deployment/roll-demo
# Waiting for deployment "roll-demo" rollout to finish: 1 out of 3 new replicas...
# Waiting for deployment "roll-demo" rollout to finish: 2 out of 3 new replicas...
# deployment "roll-demo" successfully rolled out
# ✅ 验证通过
kubectl get pods -l app=roll-demo
# NAME IMAGE READY STATUS RESTARTS AGE
# roll-demo-6c8f9d7b5e-abc12 nginx:1.25 1/1 Running 0 30s
# Recreate:先删旧Pod,再建新Pod(有停机时间)
apiVersion: apps/v1
kind: Deployment
metadata:
name: recreate-demo
spec:
replicas: 3
strategy:
type: Recreate # 一次性删除所有旧Pod,再创建新Pod
selector:
matchLabels:
app: recreate-demo
template:
metadata:
labels:
app: recreate-demo
spec:
containers:
- name: app
image: nginx:1.25
# 适用场景:不支持多版本并行运行(如数据库主从切换)
# 查看部署历史
kubectl rollout history deployment/roll-demo
# REVISION CHANGE-CAUSE
# 1 kubectl create --image=nginx:1.24
# 2 kubectl set image nginx=nginx:1.25
# 查看特定版本详情
kubectl rollout history deployment/roll-demo --revision=1
# 回滚到上一版本
kubectl rollout undo deployment/roll-demo
# deployment.apps/roll-demo rolled back
# ✅ 验证通过 - 镜像已回退
kubectl get deploy roll-demo -o jsonpath='{.spec.template.spec.containers[0].image}'
# nginx:1.24
# 回滚到指定版本
kubectl rollout undo deployment/roll-demo --to-revision=1
# 暂停/恢复滚动更新(金丝雀发布)
kubectl rollout pause deployment/roll-demo
kubectl set image deployment/roll-demo nginx=nginx:1.25
kubectl set resources deployment/roll-demo -c=nginx --limits=cpu=500m,memory=256Mi
# 不会立即生效!
kubectl rollout resume deployment/roll-demo
# 恢复后一次性应用所有变更
ReplicaSet是Deployment的底层控制器,确保指定数量的Pod副本始终运行。通常不直接使用,而是通过Deployment管理。
# replicaset-standalone.yaml(了解,生产用Deployment)
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: rs-demo
spec:
replicas: 3
selector:
matchLabels:
app: rs-demo
template:
metadata:
labels:
app: rs-demo
spec:
containers:
- name: app
image: busybox:1.36
command: ['sh', '-c', 'echo "I am $(hostname)" && sleep 3600']
# ✅ 验证通过
kubectl apply -f replicaset-standalone.yaml
kubectl get rs
# NAME DESIRED CURRENT READY AGE
# rs-demo 3 3 3 30s
# 手动删除一个Pod,RS自动重建
kubectl delete pod rs-demo-xxxxx
kubectl get pods -l app=rs-demo -w
# rs-demo-yyyyy 1/1 Running 0 5s ← 自动新建
# 方式1:kubectl scale
kubectl scale deployment web-app --replicas=5
# 方式2:kubectl edit
kubectl edit deployment web-app
# 修改 spec.replicas: 5
# 方式3:修改YAML后apply
# 修改YAML文件中replicas字段
kubectl apply -f deployment-complete.yaml
# ✅ 验证通过
kubectl get pods -l app=web-app
# NAME READY STATUS RESTARTS AGE
# web-app-6c8f9d7b5e-abc12 1/1 Running 0 30s
# web-app-6c8f9d7b5e-def34 1/1 Running 0 30s
# web-app-6c8f9d7b5e-ghi56 1/1 Running 0 2m
# web-app-6c8f9d7b5e-jkl78 1/1 Running 0 2m
# web-app-6c8f9d7b5e-mno90 1/1 Running 0 2m
# 仅当当前副本数为3时才扩到5(防止并发冲突)
kubectl scale deployment web-app --replicas=5 --current-replicas=3
# 缩容到0(停止所有Pod但保留Deployment配置)
kubectl scale deployment web-app --replicas=0
PDB保护Deployment在自愿中断(节点维护/排空)时的可用性。
# pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-app-pdb
spec:
minAvailable: 2 # 或 maxUnavailable: 1
selector:
matchLabels:
app: web-app
# ✅ 验证通过
kubectl apply -f pdb.yaml
kubectl get pdb
# NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE
# web-app-pdb 2 N/A 1 10s
# 节点排空时,PDB确保至少2个Pod可用
kubectl drain k8s-worker1 --ignore-daemonsets
# 驱逐Pod时会遵守PDB,逐个驱逐而非全部
# 现象:kubectl apply后Pod没有变化
# 原因:spec.template没有变化(只有metadata变了)
# 检查Deployment的更新状态
kubectl rollout status deployment/web-app
# deployment "web-app" successfully rolled out ← 如果没变化,会直接成功
# 确认Pod模板哈希
kubectl get pods -l app=web-app --show-labels | grep pod-template-hash
# pod-template-hash=7d8c6f5b4d ← 同一个hash说明没更新
# 现象:rollout status一直不完成
kubectl rollout status deployment/web-app
# Waiting for deployment "web-app" rollout to finish: 1 out of 3 new replicas...
# 检查原因
kubectl get deploy web-app -o jsonpath='{.status.conditions}'
# type=Progressing, reason=ProgressDeadlineExceeded
# 常见原因:
# 1. 新Pod无法就绪 → 检查readinessProbe
# 2. 镜像拉取失败 → describe pod看events
# 3. 资源不足 → 新Pod Pending
# 修复后回滚
kubectl rollout undo deployment/web-app
# 查看所有ReplicaSet
kubectl get rs -l app=web-app
# NAME DESIRED CURRENT READY AGE
# web-app-7d8c6f5b4d 0 0 0 1h ← 旧版本
# web-app-6c8f9d7b5e 0 0 0 2h ← 更旧
# web-app-5b7e8a6d4c 3 3 3 3h ← 当前
# 清理:减少revisionHistoryLimit
# spec.revisionHistoryLimit: 3 ← 只保留3个旧版本
kubectl rollout status观察过程kubectl rollout undo回滚到第1个版本kubectl drain一个节点观察效果下一课预告:第04课深入Service与网络——K8s服务发现与流量路由。