K8s StatefulSet 与 DaemonSet¶
一句话概述:StatefulSet 管理有状态应用(如数据库),保证 Pod 有固定标识和持久存储;DaemonSet 确保每个节点上都运行一个 Pod(如日志收集、监控代理)。
核心知识点¶
| 概念 | 白话解释 |
|---|---|
| StatefulSet | 有状态集 = 每个 Pod 有固定名字(pod-0, pod-1)和独立存储 |
| DaemonSet | 守护集 = 每个节点自动运行一个 Pod 副本 |
| Headless Service | 无头服务 = StatefulSet 必须配合使用,提供 Pod 的 DNS |
| PVC | 持久卷声明 = 向 K8s 申请一块存储空间 |
| PV | 持久卷 = 实际的存储资源 |
| Ordinal Index | 序号 = StatefulSet 中 Pod 的编号(0, 1, 2...) |
| Stable Network ID | 稳定网络标识 = Pod 重启后名字和 DNS 不变 |
基本使用¶
1. StatefulSet(有状态应用)¶
# 先创建 Headless Service(StatefulSet 必须)
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None # Headless = 不分配 ClusterIP
selector:
app: mysql
ports:
- port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless # 关联的 Headless Service
replicas: 3 # 3个副本:mysql-0, mysql-1, mysql-2
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeMounts:
- name: data
mountPath: /var/lib/mysql # 数据目录
volumeClaimTemplates: # 每个 Pod 自动创建独立的 PVC
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"] # 单节点读写
resources:
requests:
storage: 10Gi # 每个 Pod 10GB 存储
kubectl apply -f mysql-statefulset.yaml # 创建
# Pod 按顺序创建:mysql-0 → mysql-1 → mysql-2
kubectl get pods -l app=mysql # 查看 Pod
# 每个 Pod 有固定的 DNS 名:
# mysql-0.mysql-headless.default.svc.cluster.local
# mysql-1.mysql-headless.default.svc.cluster.local
# 每个 Pod 有独立的 PVC:
kubectl get pvc # data-mysql-0, data-mysql-1, data-mysql-2
2. DaemonSet(节点守护进程)¶
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: fluentd
image: fluentd:latest
volumeMounts:
- name: varlog
mountPath: /var/log # 挂载节点的日志目录
readOnly: true
resources:
limits:
cpu: "200m"
memory: "256Mi"
volumes:
- name: varlog
hostPath:
path: /var/log # 主机的 /var/log 目录
tolerations: # 容忍污点,让 DaemonSet 能在所有节点运行
- effect: NoSchedule
operator: Exists
kubectl apply -f daemonset.yaml
kubectl get daemonset # 查看 DaemonSet
kubectl get pods -l app=log-collector -o wide # 每个节点一个 Pod
3. DaemonSet 常见场景¶
# 监控代理(每个节点运行 Prometheus Node Exporter)
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true # 使用主机网络
containers:
- name: node-exporter
image: prom/node-exporter:latest
ports:
- containerPort: 9100
hostPort: 9100 # 直接绑定到节点端口
高级用法¶
StatefulSet 更新策略¶
spec:
updateStrategy:
type: RollingUpdate # 滚动更新
rollingUpdate:
partition: 1 # 只更新序号 >= 1 的 Pod(金丝雀发布)
# mysql-0 保持旧版本,mysql-1、mysql-2 更新
DaemonSet 只在特定节点运行¶
常见报错¶
| 报错信息 | 原因 | 解决方法 |
|---|---|---|
Pod stuck in Pending | 没有可用 PV 或存储类 | 检查 StorageClass 和 PV |
FailedMount | PVC 挂载失败 | 检查 PVC 状态和存储后端 |
OrderedReady timeout | Pod 启动太慢 | 检查 readinessProbe 或增加超时 |
| DaemonSet Pod 未调度 | 节点有污点 | 添加 tolerations |
速查表¶
# === StatefulSet ===
kubectl get statefulsets # 列出
kubectl describe sts <name> # 详情
kubectl scale sts <name> --replicas=5 # 扩缩容
kubectl rollout status sts <name> # 更新状态
kubectl delete sts <name> --cascade=orphan # 删除 STS 不删 Pod
# === DaemonSet ===
kubectl get daemonsets # 列出
kubectl describe ds <name> # 详情
kubectl rollout status ds <name> # 更新状态
# === StatefulSet vs Deployment ===
# Deployment: Pod 名随机(web-abc123),无状态
# StatefulSet: Pod 名固定(db-0, db-1),有状态
# Deployment: Pod 可以任意调度
# StatefulSet: Pod 按顺序启动/停止
# Deployment: 共享存储或无存储
# StatefulSet: 每个 Pod 独立存储(volumeClaimTemplates)
# === DaemonSet 适用场景 ===
# 日志收集(Fluentd、Filebeat)
# 监控代理(Node Exporter、Datadog Agent)
# 网络插件(Calico、Cilium)
# 存储插件(CSI 驱动)
参考:K8s StatefulSet | K8s DaemonSet | 更新于 2026 年