Deployment、StatefulSet 与 DaemonSet
High Contrast
Dark Mode
Light Mode
Sepia
Forest
2 min read342 words

Deployment、StatefulSet 与 DaemonSet

核心问题:直接创建 Pod 没有高可用——Kubernetes 怎样管理 Pod 的副本数、滚动更新和故障恢复?什么时候用哪种工作负载类型?


四种工作负载类型

graph TB subgraph "无状态应用" DEP[Deployment
Web 服务、API、Worker] end subgraph "有状态应用" STS[StatefulSet
数据库、消息队列、ZK] end subgraph "节点级守护进程" DS[DaemonSet
日志 Agent、监控 Agent] end subgraph "批处理任务" JOB[Job / CronJob
数据迁移、定时任务] end
类型 Pod 命名 存储 启动顺序 典型用途
Deployment 随机后缀 共享或无 并行 Web 服务、API
StatefulSet 有序 pod-0pod-1 独立 PVC 有序 MySQL、Redis、Kafka
DaemonSet 每节点一个 可挂载 hostPath 与节点同生命周期 Fluentd、Prometheus Node Exporter
Job 随机后缀 可选 并行/串行可配 数据库迁移、批量计算

Deployment

完整 Deployment 示例

apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
namespace: production
labels:
app: api-server
version: v1.2.3
spec:
replicas: 3                          # 副本数
selector:
matchLabels:
app: api-server                  # 与 Pod template 的 labels 匹配
# 更新策略
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1               # 更新时最多 1 个不可用
maxSurge: 1                     # 更新时最多额外创建 1 个
template:
metadata:
labels:
app: api-server
version: v1.2.3
spec:
containers:
- name: api
image: myorg/api:v1.2.3
ports:
- containerPort: 3000
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
readinessProbe:
httpGet:
path: /healthz
port: 3000
initialDelaySeconds: 10
periodSeconds: 5
# 反亲和:多副本分散到不同节点
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: [api-server]
topologyKey: kubernetes.io/hostname

Deployment 操作

# 创建/更新
kubectl apply -f deployment.yaml
# 查看滚动更新进度
kubectl rollout status deployment/api-server -n production
# 查看更新历史
kubectl rollout history deployment/api-server -n production
# 回滚到上一版本
kubectl rollout undo deployment/api-server -n production
# 回滚到指定版本
kubectl rollout undo deployment/api-server --to-revision=2 -n production
# 暂停更新(金丝雀期间使用)
kubectl rollout pause deployment/api-server -n production
kubectl rollout resume deployment/api-server -n production
# 强制重新部署(不改镜像版本但触发重建)
kubectl rollout restart deployment/api-server -n production

更新策略对比

策略 maxUnavailable maxSurge 特点
保守滚动(默认) 25% 25% 平衡速度与可用性
快速更新 0 100% 先加倍副本再缩减,零宕机但需双倍资源
就地替换 100% 0 先全停再全启,有短暂宕机,节省资源
金丝雀 0 1 逐步替换,手动控制节奏

StatefulSet

有状态应用需要稳定的网络标识pod-0.svc)和独立存储(每个副本自己的 PVC)。

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: production
spec:
serviceName: postgres-headless    # 必须对应一个 Headless Service
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
# 每个 Pod 独立创建 PVC(StatefulSet 专属)
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: gp3
resources:
requests:
storage: 20Gi
# Headless Service(StatefulSet 必须)
apiVersion: v1
kind: Service
metadata:
name: postgres-headless
spec:
clusterIP: None    # Headless:不分配 ClusterIP,直接解析到 Pod IP
selector:
app: postgres
ports:
- port: 5432

DNS 解析结果: - postgres-0.postgres-headless.production.svc.cluster.local - postgres-1.postgres-headless.production.svc.cluster.local


DaemonSet

DaemonSet 保证集群中每个(符合条件的)节点都运行一个 Pod 副本。

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: monitoring
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
tolerations:
# 允许在 Master 节点上运行(可选)
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1.16
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch.monitoring"
resources:
requests:
cpu: "100m"
memory: "200Mi"
limits:
cpu: "200m"
memory: "400Mi"
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers

Job 与 CronJob

# Job:运行一次性任务(如数据库迁移)
apiVersion: batch/v1
kind: Job
metadata:
name: db-migrate
spec:
completions: 1              # 需要成功运行 1 次
parallelism: 1              # 并发运行 1 个 Pod
backoffLimit: 3             # 失败后最多重试 3 次
ttlSecondsAfterFinished: 3600  # 完成后 1 小时自动清理
template:
spec:
restartPolicy: OnFailure  # Job 中 Pod 失败时重启
containers:
- name: migrate
image: myapp:v1.2.3
command: ["node", "scripts/migrate.js"]
# CronJob:定时任务
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup-old-records
spec:
schedule: "0 2 * * *"      # 每天凌晨 2 点(UTC)
concurrencyPolicy: Forbid  # 上次还没结束则跳过本次
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: cleanup
image: myapp:v1.2.3
command: ["node", "scripts/cleanup.js"]

工作负载选型总结

flowchart TD Q1{应用是否无状态?} Q1 -->|是| DEP[Deployment ✅] Q1 -->|否| Q2{需要稳定网络ID和独立存储?} Q2 -->|是| STS[StatefulSet ✅] Q2 -->|否| Q3{需要每个节点都运行?} Q3 -->|是| DS[DaemonSet ✅] Q3 -->|否| Q4{是一次性或定时任务?} Q4 -->|一次性| JOB[Job ✅] Q4 -->|定时| CRON[CronJob ✅]

下一节Service 类型与网络访问