70·存储高级

存储最佳实践

kubernetesstoragebest-practicessecurityperformance

存储最佳实践

学习目标

  1. 掌握生产环境的存储配置最佳实践
  2. 了解存储安全和权限管理
  3. 学会存储监控和故障排查

核心实践

1. 存储类规划

推荐的 StorageClass 分层:

┌─────────────────────────────────────────┐
│           存储类分层                     │
│                                          │
│  ┌─────────────────────────────────────┐│
│  │  fast-ssd(高性能)                 ││
│  │  - io2/gp3 SSD                     ││
│  │  - 数据库、关键应用                 ││
│  │  - 成本:高                        ││
│  └─────────────────────────────────────┘│
│                                          │
│  ┌─────────────────────────────────────┐│
│  │  standard(标准)                   ││
│  │  - gp3/standard 磁盘               ││
│  │  - 一般应用                        ││
│  │  - 成本:中                        ││
│  └─────────────────────────────────────┘│
│                                          │
│  ┌─────────────────────────────────────┐│
│  │  cold-storage(冷存储)             ││
│  │  - st1/standard HDD                ││
│  │  - 日志、归档                      ││
│  │  - 成本:低                        ││
│  └─────────────────────────────────────┘│
└─────────────────────────────────────────┘
# 生产环境 StorageClass 定义
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"
provisioner: ebs.csi.aws.com
parameters:
  type: io2
  iops: "10000"
  fsType: ext4
  encrypted: "true"
reclaimPolicy: Retain          # 生产环境用 Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"  # 设为默认
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  fsType: ext4
  encrypted: "true"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

2. 访问模式选择

选择原则:

ReadWriteOnce (RWO):
  ✓ 数据库(MySQL、PostgreSQL)
  ✓ 单实例应用
  ✓ 块存储默认支持

ReadWriteMany (RWX):
  ✓ 共享文件存储
  ✓ CMS 媒体文件
  ✓ 多 Pod 需要读写同一目录
  ✗ 不适合数据库

ReadOnlyMany (ROX):
  ✓ 配置文件共享
  ✓ 静态资源
  ✓ 只读数据

ReadWriteOncePod (RWOP):
  ✓ 严格单 Pod 访问
  ✓ K8s 1.22+ 支持
  ✓ 最强一致性保证

3. 容量规划

容量规划公式:

总容量 = 数据量 + 增长预留 + 日志空间

示例(数据库):
  当前数据:50GB
  年增长:30%
  预留空间:20%
  日志空间:10GB

  总容量 = 50GB + 50GB×30%×2年 + 50GB×20% + 10GB
         = 50GB + 30GB + 10GB + 10GB
         = 100GB

建议:
  - 初始不要分配过大
  - 使用 allowVolumeExpansion: true
  - 监控使用率,及时扩容

4. 安全配置

# 加密存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: encrypted-sc
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  encrypted: "true"              # 启用加密
  kmsKeyId: "arn:aws:kms:..."   # 指定 KMS 密钥

---
# RBAC 控制 PVC 创建权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pvc-creator
rules:
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["create", "get", "list", "watch"]

---
# NetworkPolicy 限制存储访问(NFS 场景)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: nfs-access
spec:
  podSelector:
    matchLabels:
      app: nfs-client
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/24  # NFS 服务器网段
      ports:
        - port: 2049           # NFS 端口

5. 监控和告警

# Prometheus 监控规则
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: storage-alerts
spec:
  groups:
    - name: storage
      rules:
        # PVC 使用率告警
        - alert: PVCUsageHigh
          expr: |
            kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes > 0.85
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "PVC {{ $labels.persistentvolumeclaim }} 使用率超过 85%"

        # PVC 使用率严重告警
        - alert: PVCUsageCritical
          expr: |
            kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes > 0.95
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "PVC {{ $labels.persistentvolumeclaim }} 使用率超过 95%"

        # PV 状态异常
        - alert: PVStatusAbnormal
          expr: kube_persistentvolume_status_phase{phase=~"Failed|Released"} > 0
          for: 1m
          labels:
            severity: warning
# 查看 PVC 使用率
kubectl top pvc

# 查看 PV 状态
kubectl get pv

# 查看存储相关事件
kubectl get events --field-selector reason=FailedMount

6. 备份策略

备份层次:

┌─────────────────────────────────────────┐
│            备份策略                      │
│                                          │
│  ┌─────────────────────────────────────┐│
│  │  L1: VolumeSnapshot(快照)         ││
│  │  - 频率:每小时/每天               ││
│  │  - 保留:7-30 天                   ││
│  │  - 用途:快速恢复                  ││
│  └─────────────────────────────────────┘│
│                                          │
│  ┌─────────────────────────────────────┐│
│  │  L2: 应用级备份                     ││
│  │  - mysqldump / pg_dump             ││
│  │  - 频率:每天                      ││
│  │  - 保留:90 天                     ││
│  │  - 用途:逻辑恢复、跨版本迁移      ││
│  └─────────────────────────────────────┘│
│                                          │
│  ┌─────────────────────────────────────┐│
│  │  L3: 集群级备份(Velero)           ││
│  │  - 频率:每周                      ││
│  │  - 保留:1 年                      ││
│  │  - 用途:灾难恢复、集群迁移        ││
│  └─────────────────────────────────────┘│
└─────────────────────────────────────────┘
# 定时快照 CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
  name: volume-snapshot-cron
spec:
  schedule: "0 */6 * * *"    # 每 6 小时
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: snapshot-creator
          containers:
            - name: snapshot
              image: bitnami/kubectl
              command:
                - /bin/sh
                - -c
                - |
                  cat <<EOF | kubectl apply -f -
                  apiVersion: snapshot.storage.k8s.io/v1
                  kind: VolumeSnapshot
                  metadata:
                    name: mysql-snapshot-$(date +%Y%m%d-%H%M%S)
                    namespace: database
                  spec:
                    volumeSnapshotClassName: csi-snapclass
                    source:
                      persistentVolumeClaimName: mysql-data-mysql-0
                  EOF
          restartPolicy: OnFailure

7. 故障排查

# 常见问题排查流程

# 1. PVC 一直处于 Pending
kubectl describe pvc <pvc-name>
# 检查:
# - StorageClass 是否存在
# - 是否有匹配的 PV
# - 容量是否满足

# 2. Pod 无法挂载 Volume
kubectl describe pod <pod-name>
kubectl get events --field-selector involvedObject.name=<pod-name>
# 检查:
# - PVC 是否 Bound
# - CSI Driver 是否正常
# - 节点是否有存储访问权限

# 3. 存储性能问题
# 检查 IOPS 和吞吐量
kubectl exec <pod> -- fio --name=test --ioengine=libaio --rw=randread --bs=4k --numjobs=1 --size=1G --runtime=60

# 4. 磁盘空间不足
kubectl exec <pod> -- df -h
# 扩容 PVC 或清理数据

8. 成本优化

成本优化策略:

1. 选择合适的存储类型
   - 不是所有数据都需要 SSD
   - 日志和归档用 HDD

2. 设置合理的回收策略
   - 开发/测试环境:Delete(自动清理)
   - 生产环境:Retain(手动管理)

3. 使用 WaitForFirstConsumer
   - 避免创建未使用的 PV

4. 定期清理未使用的 PV/PVC
   kubectl get pvc --all-namespaces | grep Bound
   kubectl get pv | grep Available

5. 监控存储使用率
   - 删除不再使用的 PVC
   - 缩容过度分配的存储

6. 使用存储分层
   - 热数据:SSD
   - 温数据:标准磁盘
   - 冷数据:归档存储

实践练习

练习 1:创建生产级 StorageClass

# 为不同应用场景创建存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iopsPerGB: "50"
  fsType: ext4
  encrypted: "true"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard-hdd
provisioner: ebs.csi.aws.com
parameters:
  type: st1
  fsType: ext4
  encrypted: "true"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

练习 2:配置存储监控

# 查看 PVC 使用情况
kubectl get pvc -A -o custom-columns=\
NAMESPACE:.metadata.namespace,\
NAME:.metadata.name,\
STATUS:.status.phase,\
VOLUME:.spec.volumeName,\
CAPACITY:.spec.resources.requests.storage

# 查看 PV 使用率(需要 metrics-server)
kubectl top pv

练习 3:模拟故障恢复

# 1. 创建测试数据
kubectl exec mysql-0 -- mysql -uroot -ppassword123 -e "CREATE DATABASE disaster_test; USE disaster_test; CREATE TABLE t1(data VARCHAR(100)); INSERT INTO t1 VALUES('backup_test');"

# 2. 创建快照
kubectl apply -f - <<EOF
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: disaster-backup
spec:
  volumeSnapshotClassName: csi-snapclass
  source:
    persistentVolumeClaimName: mysql-data-mysql-0
EOF

# 3. 模拟数据丢失
kubectl exec mysql-0 -- mysql -uroot -ppassword123 -e "DROP DATABASE disaster_test;"

# 4. 从快照恢复
# ... 创建新 PVC 并验证恢复

常见误解

1. 默认 StorageClass 不一定是最佳选择

默认 StorageClass 可能使用 Delete 回收策略
生产环境应明确指定 StorageClass
不要依赖集群默认配置

2. 大容量不等于高性能

IOPS 和吞吐量与容量相关但不是线性关系
高 IOPS 场景需要选择支持预配置 IOPS 的存储类型
容量规划和性能规划要分开考虑

小结

要点说明
存储分层按场景选择 SSD/HDD/冷存储
安全配置加密、RBAC、网络策略
备份策略快照 + 应用备份 + 集群备份
监控告警PVC 使用率、PV 状态
故障排查描述资源、查看事件、检查 CSI
成本优化合理选择、定期清理、使用分层

练习编辑器

bash
Loading...

继续学习

完成本课后,建议继续学习下一课「调度器简介」 以巩固所学知识。