本章目录(点击跳转):
- 4.1 工作负载是什么
- 4.2 Deployment(重中之重)
- 4.2.1 完整 YAML 模板
- 4.2.2 Deployment 背后还有一个 ReplicaSet
- 4.2.3 扩缩容
- 4.2.4 滚动升级(发版)
- 4.2.5 回滚(发版翻车救星)
- 4.2.6 暂停与恢复批量更新
- 4.3 StatefulSet(有状态应用)
- 4.3.1 完整示例:一个 3 副本的 etcd 演示
- 4.4 DaemonSet(每台节点一个)
- 4.5 Job 与 CronJob(任务型)
- 4.5.1 Job:跑一次就结束
- 4.5.2 CronJob:定时任务
- 4.6 四种工作负载对比总结
- 4.7 本章小结
本章目标:掌握 Kubernetes 四种核心工作负载——Deployment、StatefulSet、DaemonSet、Job/CronJob,能根据应用特点选对工具,并会做滚动升级和回滚。
4.1 工作负载是什么
前面直接创建 Pod,删除后 K8s 不会帮你补。工作负载(Workload)就是在 Pod 之上的一层"管理者":
你声明"我要什么",工作负载控制器负责永远让现实符合声明:副本数、滚动更新、自愈、重启策略。
选型口诀:
| 应用特点 | 用什么 | 例子 |
|---|---|---|
| 无状态(任意副本可互换) | Deployment(最常用) | Web 服务、API |
| 有状态(需要固定名字、固定存储) | StatefulSet | 数据库、Kafka |
| 每台节点都要跑一个 | DaemonSet | 日志采集、监控 agent |
| 跑一次就结束 | Job | 数据迁移、报表 |
| 定时跑一次 | CronJob | 每天备份 |
4.2 Deployment(重中之重)
4.2.1 完整 YAML 模板
# web-deploy.yaml —— 以后复制这个模板改就行
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: default
labels:
app: web
spec:
replicas: 3 # 副本数
selector: # 管理哪些 Pod(必须匹配 template 标签)
matchLabels:
app: web
strategy: # 更新策略
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新时最多多出 1 个
maxUnavailable: 0 # 更新时最多 0 个不可用(不中断服务)
template: # Pod 模板
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
readinessProbe:
httpGet:
path: /
port: 80
periodSeconds: 5
kubectl apply -f web-deploy.yaml
kubectl get deploy web
kubectl get pods -l app=web -w
输出:
NAME READY UP-TO-DATE AVAILABLE AGE
web 3/3 3 3 10s
小白注意
selector.matchLabels和template.metadata.labels必须一致,否则 apply 会报错。Deployment 创建后 selector 不可修改。
4.2.2 Deployment 背后还有一个 ReplicaSet
Deployment 通过管理 ReplicaSet 来管理 Pod(一层间接,为了升级时新旧两组 Pod 并存)。你一般不用直接创建 ReplicaSet,但要知道它存在:
kubectl get rs -l app=web
# 会看到 web-xxxxx(Deployment 自动生成的)
4.2.3 扩缩容
kubectl scale deployment web --replicas=5
kubectl get pods -l app=web -w # 看新 Pod 逐个起来
kubectl scale deployment web --replicas=2
自动扩缩容 HPA(提前预告,生产常用):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # CPU 超过 70% 就扩容
minikube 默认没装 metrics-server,HPA 需要它。
minikube addons enable metrics-server可开启。
4.2.4 滚动升级(发版)
把镜像从 1.27 升到 1.28,全程不停机:
# 方式一:命令行
kubectl set image deployment/web web=nginx:1.28
# 方式二:改 YAML 后 apply(推荐,有版本记录)
# 把 web-deploy.yaml 里 image 改成 nginx:1.28
kubectl apply -f web-deploy.yaml
观察升级过程:
kubectl rollout status deployment/web
kubectl get pods -l app=web -w
# 新 Pod 先起、就绪后,旧 Pod 才删 —— 这就是滚动更新
kubectl rollout history deployment/web
# REVISION 号每次更新 +1
4.2.5 回滚(发版翻车救星)
# 回滚到上一版
kubectl rollout undo deployment/web
# 回滚到指定版本
kubectl rollout undo deployment/web --to-revision=2
# 查看历史
kubectl rollout history deployment/web
# 演练一下:
kubectl set image deployment/web web=nginx:1.28
kubectl rollout undo deployment/web # 退回 1.27
kubectl get pods -l app=web
4.2.6 暂停与恢复批量更新
一批改动不想每步都触发滚动更新:
kubectl rollout pause deployment/web
kubectl set image deployment/web web=nginx:1.28 # 只记录,不执行
kubectl set env deployment/web APP_VERSION=v2
kubectl rollout resume deployment/web # 一次性滚动
4.3 StatefulSet(有状态应用)
数据库这类应用有三个特殊需求:
- 固定的网络标识:
mysql-0、mysql-1、mysql-2,重启后名字不变; - 稳定的存储:每个副本绑定自己专属的 PVC,Pod 重建后数据还在;
- 有序的启停:按 0、1、2 顺序启动,按 2、1、0 顺序停止。
StatefulSet 就是为这三点设计的。
4.3.1 完整示例:一个 3 副本的 etcd 演示
# stateful-demo.yaml
apiVersion: v1
kind: Service
metadata:
name: etcd-headless
spec:
clusterIP: None # Headless Service:不给虚拟IP
selector:
app: etcd
ports:
- port: 2380
name: peer
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: etcd
spec:
serviceName: etcd-headless # 必须指向一个 Headless Service
replicas: 3
selector:
matchLabels:
app: etcd
template:
metadata:
labels:
app: etcd
spec:
containers:
- name: etcd
image: bitnami/etcd:3.5
env:
- name: ETCD_INITIAL_CLUSTER
value: etcd-0=http://etcd-0:2380,etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380
ports:
- containerPort: 2379
volumeClaimTemplates: # 每个副本自动创建一个 PVC
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
kubectl apply -f stateful-demo.yaml
kubectl get pods -l app=etcd -o wide
# 名字是 etcd-0, etcd-1, etcd-2
kubectl get pvc
# 自动生成 data-etcd-0, data-etcd-1, data-etcd-2
# 每个 Pod 有独立 DNS 名(靠 headless service):
kubectl exec -it etcd-0 -- ping -c1 etcd-1
注意:删除 StatefulSet 时,PVC 默认不会删(数据安全优先),需要手动清理:
kubectl delete pvc -l app=etcd
kubectl delete -f stateful-demo.yaml
4.4 DaemonSet(每台节点一个)
场景:日志采集 agent(Fluentd)、监控 agent(node-exporter)、网络插件(CNI)。
# daemonset-demo.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-logger
spec:
selector:
matchLabels:
app: node-logger
template:
metadata:
labels:
app: node-logger
spec:
containers:
- name: logger
image: busybox:1.36
command: ["sh", "-c", "while true; do echo \"$(hostname) $(date)\"; sleep 5; done"]
kubectl apply -f daemonset-demo.yaml
kubectl get ds node-logger
# minikube 只有 1 个节点,所以只有 1 个 Pod;
# 多节点集群里,每加一个节点,就自动多一个 Pod
kubectl get pods -o wide -l app=node-logger
kubectl delete -f daemonset-demo.yaml
4.5 Job 与 CronJob(任务型)
4.5.1 Job:跑一次就结束
# job-demo.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: backup-job
spec:
completions: 1 # 需要成功完成的次数
backoffLimit: 3 # 失败重试 3 次
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: busybox:1.36
command: ["sh", "-c", "for i in 1 2 3 4 5; do echo 备份进度 $i; sleep 2; done; echo 完成"]
kubectl apply -f job-demo.yaml
kubectl get job backup-job
kubectl get pods -l job-name=backup-job
kubectl logs job/backup-job
# 状态 Succeeded 后 Job 完成;再想跑就删除重建
kubectl delete job backup-job
并行 Job(completions=4, concurrencyPolicy=Allow, 可加 parallelism=4):4 个子任务同时跑,全部成功才算成功。
4.5.2 CronJob:定时任务
# cronjob-demo.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hourly-report
spec:
schedule: "0 * * * *" # crontab 格式:每小时整点
concurrencyPolicy: Forbid # 上一次没跑完就不启动新的
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: report
image: busybox:1.36
command: ["sh", "-c", "echo 生成 $(date) 的报表"]
kubectl apply -f cronjob-demo.yaml
kubectl get cronjob hourly-report
# 想立即跑一次(不用等整点):
kubectl create job run-from-cron --from=cronjob/hourly-report
kubectl get jobs
kubectl delete -f cronjob-demo.yaml
crontab 格式速记:分 时 日 月 星期,*/10 * * * * 表示每 10 分钟。
4.6 四种工作负载对比总结
| Deployment | StatefulSet | DaemonSet | Job/CronJob | |
|---|---|---|---|---|
| Pod 命名 | web-随机哈希 | 固定序号 0,1,2 | 随机 | 随机+序号 |
| 副本位置 | 任意节点 | 任意节点(有序启停) | 每节点一个 | 跑完即止 |
| 存储 | 共享/无 | 每副本独立 PVC | 无 | 无 |
| 更新 | 滚动 | 有序逐个 | 逐节点 | 无 |
| 典型场景 | Web/API | DB/MQ | 节点级 agent | 批处理/定时 |
4.7 本章小结
- 无状态应用 → Deployment,会 4 件套:
apply、scale、rollout status、rollout undo。 - 有状态 → StatefulSet + Headless Service + volumeClaimTemplates。
- 每节点一个 → DaemonSet;跑一次 → Job;定时 → CronJob。
maxUnavailable: 0+ 就绪探针 = 升级零停机。
下一章:让应用能被访问——Service 与网络。
原文链接:第4章 工作负载(Workloads),转载请注明来源!
