← 返回文章列表

Kubernetes StatefulSet 完全指南

深入理解 Kubernetes StatefulSet:与 Deployment 的区别、存储卷管理、有状态应用部署

6 分钟阅读
字号

Kubernetes StatefulSet 完全指南

本文基于 Kubernetes 1.28


概述

在 Kubernetes 中,Deployment 适合部署无状态应用,但对于数据库、消息队列等有状态应用,StatefulSet 是更好的选择。

StatefulSet 为 Pod 提供:

  • 稳定的网络身份(固定的 Pod 名称和 DNS)
  • 稳定的存储(每个 Pod 有专属的 PVC)
  • 有序的部署和扩缩容

一、StatefulSet vs Deployment

对比表

特性DeploymentStatefulSet
Pod 名称随机哈希有序编号
存储各 Pod 独立每个 Pod 专属 PVC
启动顺序同时启动按序号顺序
删除顺序同时删除逆序删除
网络身份不稳定稳定(DNS 固定)
适用场景Web/API(无状态)数据库(有状态)

示例对比

Deployment:
  web-deployment-abcde123
  web-deployment-defgh456
  web-deployment-ijkl789
 
StatefulSet:
  mysql-0           ← 固定名字
  mysql-1           ← 固定名字
  mysql-2           ← 固定名字

二、核心概念

1. 稳定的网络身份

mysql-0.mysql-headless.default.svc.cluster.local → IP1
mysql-1.mysql-headless.default.svc.cluster.local → IP2
mysql-2.mysql-headless.default.svc.cluster.local → IP3
 
即使 Pod 重启:
  - 名字不变(还是叫 mysql-0)
  - DNS 会更新指向新 IP

2. 稳定的存储

mysql-0 → 专属 PVC:mysql-data-mysql-0(20Gi)
mysql-1 → 专属 PVC:mysql-data-mysql-1(20Gi)
mysql-2 → 专属 PVC:mysql-data-mysql-2(20Gi)
 
即使 Pod 重启:
  - 绑定的 PVC 不变
  - 数据不会丢失

3. 有序的部署和扩缩容

部署顺序:mysql-0 → mysql-1 → mysql-2
扩容顺序:先创建 mysql-3,再创建 mysql-4
缩容顺序:先删除 mysql-2,再删除 mysql-1...

三、YAML 详解

StatefulSet 完整示例

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  # 1. 服务名(必须和无头 Service 对应)
  serviceName: mysql-headless
  
  # 2. 副本数
  replicas: 3
  
  # 3. 选择器
  selector:
    matchLabels:
      app: mysql
  
  # 4. Pod 模板
  template:
    metadata:
      labels:
        app: mysql
    spec:
      terminationGracePeriodSeconds: 10
      
      containers:
      - name: mysql
        image: mysql:8.0
        
        ports:
        - containerPort: 3306
          name: mysql
        
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "root123"
        
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
        
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        
        # 健康检查
        readinessProbe:
          exec:
            command: ["mysqladmin", "ping"]
          initialDelaySeconds: 30
          periodSeconds: 10
  
  # 5. 卷声明模板(自动创建 PVC)
  volumeClaimTemplates:
  - metadata:
      name: mysql-data
    spec:
      accessModes: [ReadWriteOnce]
      resources:
        requests:
          storage: 20Gi

无头 Service

apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
spec:
  clusterIP: None              # 关键:设为 None
  selector:
    app: mysql
  ports:
  - port: 3306
    targetPort: 3306

四、Volume Claim Templates

什么是 Volume Claim Templates

自动为每个 Pod 创建专属 PVC。

volumeClaimTemplates:
- metadata:
    name: mysql-data
  spec:
    accessModes: [ReadWriteOnce]
    resources:
      requests:
        storage: 20Gi

自动创建的 PVC 名称

格式:{metadata.name}-{StatefulSet名}-{Pod序号}
 
示例:
  mysql-data-mysql-0    → mysql-0 用的 PVC
  mysql-data-mysql-1    → mysql-1 用的 PVC
  mysql-data-mysql-2    → mysql-2 用的 PVC

五、创建过程

1. 创建 StatefulSet

kubectl apply -f mysql-statefulset.yaml

2. 按顺序创建 Pod

mysql-0 创建中...
  → PVC: mysql-data-mysql-0 创建
  → PVC: Bound
  → Pod: mysql-0 创建
  → Pod: Running & Ready
 
mysql-1 创建中...
  → PVC: mysql-data-mysql-1 创建
  → ...
 
mysql-2 创建中...
  → ...

3. 查看状态

kubectl get statefulset
# NAME     READY   AGE
# mysql    3/3     5m
 
kubectl get pods
# NAME       READY   STATUS    RESTARTS   AGE
# mysql-0    1/1     Running   0          5m
# mysql-1    1/1     Running   0          3m
# mysql-2    1/1     Running   0          1m
 
kubectl get pvc
# NAME                    STATUS   VOLUME   CAPACITY
# mysql-data-mysql-0      Bound    pvc-xxx  20Gi
# mysql-data-mysql-1      Bound    pvc-yyy  20Gi
# mysql-data-mysql-2      Bound    pvc-zzz  20Gi

六、扩缩容

扩容

kubectl scale statefulset mysql --replicas=5
过程(从后往前创建):
  mysql-3 创建 → PVC mysql-data-mysql-3 创建 → Bound → Pod Ready
  mysql-4 创建 → PVC mysql-data-mysql-4 创建 → Bound → Pod Ready

缩容

kubectl scale statefulset mysql --replicas=2
过程(逆序删除):
  mysql-4 终止(等待优雅终止完成)
  mysql-4 删除
  mysql-3 终止...
  
注意:缩容不会删除 PVC!数据保留。

七、删除

删除 StatefulSet

kubectl delete statefulset mysql
 
# PVC 保留!数据不会丢失

删除 PVC

# 手动删除才会丢失数据
kubectl delete pvc mysql-data-mysql-0
kubectl delete pvc mysql-data-mysql-1
kubectl delete pvc mysql-data-mysql-2

八、适用场景

应用为什么用 StatefulSet
MySQL/MariaDB每个实例有独立数据
PostgreSQL副本集成员数据独立
Redis主从数据独立
MongoDB副本集成员数据独立
Kafka每个 Broker 有独立数据
Elasticsearch每个节点有独立数据

九、注意事项

  1. 存储选择:使用支持 ReadWriteOnce 的存储(云盘)
  2. 数据备份:缩容/删除前确保数据已备份
  3. 节点亲和性:避免所有 Pod 调度到同一节点
  4. 健康检查:配置 livenessProbe 和 readinessProbe
  5. 优雅终止:设置 terminationGracePeriodSeconds

十、总结

Deployment → 无状态应用(Web/API)
StatefulSet → 有状态应用(数据库)
 
StatefulSet 核心特点:
  - 稳定的网络身份(Pod 名称固定)
  - 稳定的存储(每个 Pod 专属 PVC)
  - 有序的部署和扩缩容

相关文档

分享

// RELATED_POSTS

0%