StatefulSet #

一、StatefulSet概述 #

StatefulSet用于管理有状态应用,提供稳定的网络标识和持久存储。

1.1 与Deployment对比 #

特性 Deployment StatefulSet
Pod标识 随机名称 固定序号名称
网络标识 随机分配 稳定DNS名称
存储 共享存储 独立PVC
启动顺序 并行启动 有序启动
适用场景 无状态应用 有状态应用

1.2 StatefulSet特性 #

text
StatefulSet特性
    │
    ├── 稳定的网络标识
    │   ├── 固定Pod名称
    │   └── 稳定DNS名称
    │
    ├── 稳定的持久存储
    │   ├── 每个Pod独立PVC
    │   └── Pod重建后数据保留
    │
    ├── 有序部署和扩展
    │   ├── 顺序启动
    │   └── 顺序停止
    │
    └── 有序滚动更新
        └── 按序更新Pod

二、创建StatefulSet #

2.1 基本示例 #

yaml
# nginx-statefulset.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-headless
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx-sts
spec:
  serviceName: nginx-headless
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
          name: web

2.2 创建和查看 #

bash
# 创建StatefulSet
kubectl apply -f nginx-statefulset.yaml

# 查看StatefulSet
kubectl get sts

# 输出示例
NAME         READY   AGE
nginx-sts    3/3     1m

# 查看Pod(注意名称格式)
kubectl get pods -l app=nginx

# 输出示例
NAME           READY   STATUS    RESTARTS   AGE
nginx-sts-0    1/1     Running   0          1m
nginx-sts-1    1/1     Running   0          50s
nginx-sts-2    1/1     Running   0          40s

2.3 Headless Service #

yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-headless
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
text
DNS解析格式
    │
    ├── Pod DNS
    │   └── <pod-name>.<service-name>.<namespace>.svc.cluster.local
    │
    └── 示例
        └── nginx-sts-0.nginx-headless.default.svc.cluster.local

三、持久存储 #

3.1 volumeClaimTemplates #

yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web-sts
spec:
  serviceName: web-headless
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        image: nginx:1.25
        ports:
        - containerPort: 80
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "standard"
      resources:
        requests:
          storage: 1Gi

3.2 PVC命名规则 #

text
PVC命名格式
    │
    └── <pvc-name>-<statefulset-name>-<ordinal>
    
示例
    │
    ├── www-web-sts-0
    ├── www-web-sts-1
    └── www-web-sts-2

3.3 查看PVC #

bash
# 查看PVC
kubectl get pvc

# 输出示例
NAME             STATUS   VOLUME                                     CAPACITY   AGE
www-web-sts-0    Bound    pvc-xxx                                    1Gi        1m
www-web-sts-1    Bound    pvc-yyy                                    1Gi        50s
www-web-sts-2    Bound    pvc-zzz                                    1Gi        40s

四、部署和扩展 #

4.1 有序部署 #

text
部署顺序
    │
    ├── 1. nginx-sts-0 启动
    │       └── 等待Running和Ready
    │
    ├── 2. nginx-sts-1 启动
    │       └── 等待Running和Ready
    │
    └── 3. nginx-sts-2 启动
            └── 等待Running和Ready

4.2 扩容 #

bash
# 扩容到5个副本
kubectl scale sts nginx-sts --replicas=5

# 查看扩容过程
kubectl get pods -l app=nginx -w

# 输出示例
nginx-sts-0    1/1     Running   0          2m
nginx-sts-1    1/1     Running   0          1m
nginx-sts-2    1/1     Running   0          50s
nginx-sts-3    0/1     Pending   0          0s
nginx-sts-3    1/1     Running   0          5s
nginx-sts-4    0/1     Pending   0          0s
nginx-sts-4    1/1     Running   0          5s

4.3 缩容 #

bash
# 缩容到2个副本
kubectl scale sts nginx-sts --replicas=2

# 缩容顺序:从高序号开始删除
# nginx-sts-4 → nginx-sts-3 → nginx-sts-2

五、更新策略 #

5.1 RollingUpdate策略 #

yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web-sts
spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0
  template:
    spec:
      containers:
      - name: web
        image: nginx:1.26

5.2 分区更新 #

yaml
updateStrategy:
  type: RollingUpdate
  rollingUpdate:
    partition: 2
text
分区更新(partition=2)
    │
    ├── nginx-sts-0 ─── 不更新
    │
    ├── nginx-sts-1 ─── 不更新
    │
    ├── nginx-sts-2 ─── 更新
    │
    ├── nginx-sts-3 ─── 更新
    │
    └── nginx-sts-4 ─── 更新

5.3 OnDelete策略 #

yaml
updateStrategy:
  type: OnDelete
text
OnDelete策略
    │
    ├── 更新Pod模板后
    │
    └── 手动删除Pod才会更新

六、完整配置示例 #

6.1 数据库StatefulSet #

yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-headless
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: init-mysql
        image: mysql:8.0
        command:
        - bash
        - "-c"
        - |
          set -ex
          [[ $(hostname) =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          echo [mysqld] > /mnt/conf.d/server-id.cnf
          echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
        volumeMounts:
        - name: conf
          mountPath: /mnt/conf.d
      containers:
      - name: mysql
        image: mysql:8.0
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-secret
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
        livenessProbe:
          exec:
            command: ["mysqladmin", "ping"]
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          exec:
            command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
          initialDelaySeconds: 5
          periodSeconds: 2
      volumes:
      - name: conf
        emptyDir: {}
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: standard
      resources:
        requests:
          storage: 10Gi

七、Pod管理 #

7.1 Pod标识 #

bash
# Pod名称
nginx-sts-0
nginx-sts-1
nginx-sts-2

# Pod DNS
nginx-sts-0.mysql-headless.default.svc.cluster.local
nginx-sts-1.mysql-headless.default.svc.cluster.local
nginx-sts-2.mysql-headless.default.svc.cluster.local

7.2 Pod重建 #

bash
# 删除Pod
kubectl delete pod nginx-sts-0

# StatefulSet会重建同名Pod
kubectl get pod nginx-sts-0

# 新Pod具有相同的:
# - 名称
# - 网络标识
# - 持久存储

7.3 Pod恢复顺序 #

text
Pod恢复
    │
    ├── 1. 识别缺失的Pod
    │
    ├── 2. 按序号顺序重建
    │
    └── 3. 等待Running和Ready

八、故障排查 #

8.1 常见问题 #

bash
# 查看StatefulSet状态
kubectl describe sts nginx-sts

# 查看Pod状态
kubectl get pods -l app=nginx

# 查看PVC状态
kubectl get pvc

# 查看事件
kubectl get events --field-selector involvedObject.name=nginx-sts

8.2 问题诊断 #

问题 原因 解决方案
Pod卡在Pending PVC未绑定 检查StorageClass
Pod启动失败 初始化失败 检查initContainer
更新卡住 Pod不健康 检查健康检查

九、最佳实践 #

9.1 Headless Service #

yaml
apiVersion: v1
kind: Service
metadata:
  name: app-headless
spec:
  clusterIP: None
  selector:
    app: app
  ports:
  - port: 8080

9.2 资源配置 #

yaml
resources:
  requests:
    cpu: 500m
    memory: 512Mi
  limits:
    cpu: 1
    memory: 1Gi

9.3 健康检查 #

yaml
livenessProbe:
  exec:
    command: ["pg_isready"]
  initialDelaySeconds: 30
readinessProbe:
  exec:
    command: ["pg_isready"]
  initialDelaySeconds: 5

十、总结 #

10.1 核心要点 #

要点 说明
稳定标识 固定Pod名称和DNS
持久存储 每个Pod独立PVC
有序部署 按序号启动和停止
更新策略 RollingUpdate/OnDelete

10.2 下一步 #

掌握了StatefulSet后,让我们学习 DaemonSet,了解如何在每个节点运行Pod。

最后更新:2026-03-28