跳过正文

云原生存储方案选型:EFS/EBS/OSS 实践

·855 字·5 分钟·
目录

云原生存储需求分析
#

在 K8s 中使用存储,需要先明确几个维度:

  • 访问模式:单节点读写(RWO)还是多节点共享读写(RWX)
  • 性能要求:IOPS、吞吐量、延迟
  • 数据生命周期:跟随 Pod 还是独立持久
  • 成本敏感度:热数据/冷数据分层
  • 跨 AZ 需求:是否要跨可用区共享

AWS 存储方案对比
#

特性EBS (gp3)EFSS3
访问模式RWO(单节点)RWX(多节点多AZ)对象存储,非 POSIX
协议BlockNFS v4.1HTTP/S3 API
延迟<1ms数ms数十ms
吞吐量最高 1000 MB/s最高 3 GB/s(burst)无上限(受并发限制)
跨 AZ不支持(Zone 内)原生支持原生支持
最大容量64 TiB/卷无上限(PB 级)无上限
价格(us-west-2)$0.08/GB/月$0.30/GB/月$0.023/GB/月
适用场景数据库、高性能单实例共享配置、CMS、机器学习数据集日志归档、静态资源、备份

选型决策:有状态单实例(MySQL/Redis)→ EBS;多实例共享(模型权重/Notebook)→ EFS;归档/对象 → S3。


EBS in Kubernetes
#

安装 EBS CSI Driver
#

# 通过 EKS Add-on 安装(推荐)
aws eks create-addon \
  --cluster-name prod-cluster \
  --addon-name aws-ebs-csi-driver \
  --addon-version v1.35.0-eksbuild.1 \
  --service-account-role-arn arn:aws:iam::123456789012:role/ebs-csi-driver-role

# EBS CSI Driver 需要的 IAM 权限
eksctl create iamserviceaccount \
  --cluster prod-cluster \
  --name ebs-csi-controller-sa \
  --namespace kube-system \
  --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
  --approve \
  --override-existing-serviceaccounts

StorageClass 配置
#

# gp3 StorageClass(推荐,比 gp2 性价比更高)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer   # 等 Pod 调度后再创建 EBS,保证同 AZ
reclaimPolicy: Retain                      # 生产环境用 Retain,防止误删
parameters:
  type: gp3
  iops: "3000"
  throughput: "125"
  encrypted: "true"
  kmsKeyId: arn:aws:kms:us-west-2:123456789012:key/mrk-xxx
allowVolumeExpansion: true

PVC 使用示例
#

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: gp3
  resources:
    requests:
      storage: 100Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql
  template:
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: gp3
        resources:
          requests:
            storage: 100Gi

EBS 快照备份
#

# VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: ebs-vsc
driver: ebs.csi.aws.com
deletionPolicy: Retain
---
# 创建快照
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: mysql-data-snapshot-20251209
spec:
  volumeSnapshotClassName: ebs-vsc
  source:
    persistentVolumeClaimName: mysql-data

注意:EBS 卷是 Zone 级别的,volumeBindingMode: WaitForFirstConsumer 保证 PV 在 Pod 所在 AZ 创建,否则 Pod 和 PV 可能跨 AZ,导致挂载失败。


EFS in Kubernetes
#

安装 EFS CSI Driver
#

# 创建 EFS 文件系统(先在 AWS 侧)
EFS_ID=$(aws efs create-file-system \
  --performance-mode generalPurpose \
  --throughput-mode elastic \
  --encrypted \
  --tags Key=Name,Value=k8s-shared-storage \
  --query 'FileSystemId' --output text)

echo "EFS ID: $EFS_ID"

# 创建挂载点(每个 AZ 各一个)
for SUBNET_ID in subnet-aaa subnet-bbb subnet-ccc; do
  aws efs create-mount-target \
    --file-system-id $EFS_ID \
    --subnet-id $SUBNET_ID \
    --security-groups sg-xxxxxxxx
done

# 安装 EFS CSI Driver
aws eks create-addon \
  --cluster-name prod-cluster \
  --addon-name aws-efs-csi-driver \
  --addon-version v2.0.7-eksbuild.1

动态供给 StorageClass
#

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: efs-sc
provisioner: efs.csi.aws.com
parameters:
  provisioningMode: efs-ap          # 用 Access Point 做动态供给
  fileSystemId: fs-0123456789abcdef0
  directoryPerms: "700"
  gidRangeStart: "1000"
  gidRangeEnd: "2000"
  basePath: "/dynamic"

静态供给(共享同一 EFS 根目录)
#

apiVersion: v1
kind: PersistentVolume
metadata:
  name: efs-pv-shared
spec:
  capacity:
    storage: 5Ti             # EFS 实际不限大小,这里是声明值
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: ""
  csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-0123456789abcdef0   # EFS ID
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: efs-pvc-shared
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: ""
  resources:
    requests:
      storage: 5Ti
  volumeName: efs-pv-shared

多 Pod 共享挂载示例
#

# Deployment 多副本共享同一个 EFS
apiVersion: apps/v1
kind: Deployment
metadata:
  name: model-server
spec:
  replicas: 5
  template:
    spec:
      containers:
        - name: server
          image: my-model-server:latest
          volumeMounts:
            - name: model-weights
              mountPath: /models
              readOnly: true
      volumes:
        - name: model-weights
          persistentVolumeClaim:
            claimName: efs-pvc-shared

阿里云存储对比
#

在阿里云 ACK 环境中,对应关系如下:

AWS阿里云特性差异
EBS gp3云盘 ESSD PL1阿里云 ESSD 单盘 IOPS 上限更高(PL3: 1M IOPS)
EFSNAS 通用型/极速型极速型延迟更低,但价格贵 3 倍
S3OSSAPI 兼容 S3,可用 s3cmd/mc 操作
# 阿里云 NAS StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: alicloud-nas
provisioner: nasplugin.csi.alibabacloud.com
parameters:
  volumeAs: subpath
  server: "xxx.cn-hangzhou.nas.aliyuncs.com"
  path: "/"
  vers: "3"
  mode: "755"
reclaimPolicy: Retain

存储性能测试
#

在 Pod 内用 fio 测试实际性能:

# 测试 Job
apiVersion: batch/v1
kind: Job
metadata:
  name: storage-perf-test
spec:
  template:
    spec:
      containers:
        - name: fio
          image: nixery.dev/shell/fio
          command:
            - /bin/sh
            - -c
            - |
              # 顺序写测试
              fio --name=seq-write \
                --directory=/data \
                --rw=write \
                --bs=1M \
                --size=4G \
                --numjobs=1 \
                --iodepth=32 \
                --runtime=60 \
                --time_based \
                --output-format=json \
                --output=/data/seq-write.json

              # 随机读写测试(IOPS 敏感场景)
              fio --name=rand-rw \
                --directory=/data \
                --rw=randrw \
                --rwmixread=70 \
                --bs=4K \
                --size=4G \
                --numjobs=4 \
                --iodepth=64 \
                --runtime=60 \
                --time_based \
                --output-format=json \
                --output=/data/rand-rw.json

              cat /data/seq-write.json | python3 -c "
              import json,sys
              d=json.load(sys.stdin)
              j=d['jobs'][0]
              print(f'Write BW: {j[\"write\"][\"bw_bytes\"]/1024/1024:.1f} MB/s')
              print(f'Write IOPS: {j[\"write\"][\"iops\"]:.0f}')
              "
          volumeMounts:
            - name: test-vol
              mountPath: /data
      restartPolicy: Never
      volumes:
        - name: test-vol
          persistentVolumeClaim:
            claimName: your-pvc-name

典型测试结果参考(us-west-2,实际以测试为准):

存储类型顺序写吞吐随机读 IOPS (4K)
EBS gp3 (默认)~125 MB/s~3000
EBS gp3 (调优)~1000 MB/s~16000
EFS 通用~100 MB/s~500
EFS Elastic 吞吐~300 MB/s~1500

Velero 备份 PVC 数据
#

# 安装 Velero
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm install velero vmware-tanzu/velero \
  --namespace velero \
  --create-namespace \
  --set configuration.backupStorageLocation[0].name=default \
  --set configuration.backupStorageLocation[0].provider=aws \
  --set configuration.backupStorageLocation[0].bucket=my-velero-backup \
  --set configuration.backupStorageLocation[0].config.region=us-west-2 \
  --set configuration.volumeSnapshotLocation[0].name=default \
  --set configuration.volumeSnapshotLocation[0].provider=aws \
  --set configuration.volumeSnapshotLocation[0].config.region=us-west-2 \
  --set serviceAccount.server.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789012:role/velero-role

# 创建按需备份
velero backup create my-backup \
  --include-namespaces production \
  --storage-location default \
  --volume-snapshot-locations default

# 创建定时备份(每天凌晨 2 点)
velero schedule create daily-backup \
  --schedule="0 2 * * *" \
  --include-namespaces production \
  --ttl 720h0m0s    # 保留 30 天

# 查看备份状态
velero backup describe my-backup --details

# 恢复
velero restore create --from-backup my-backup \
  --include-namespaces production

选型决策矩阵
#

需求推荐方案理由
MySQL/PostgreSQL 单实例EBS gp3低延迟,RWO 符合数据库独占需求
Redis 持久化EBS gp3同上
Jupyter Notebook 共享EFS多用户同时挂载,跨 AZ 可用
ML 模型权重只读共享EFS 静态供给多 Pod 并发只读,EFS 完美匹配
日志归档S3(Loki/直接写)成本最低,不需要 POSIX 语义
CI/CD 构建缓存EFS 或 EBS(取决于并发)单 Builder: EBS;并发 Builder: EFS
配置文件/证书共享ConfigMap/Secret 或 EFS小文件用 CM/Secret,大文件用 EFS
跨区域备份S3 + 跨区域复制S3 原生支持 CRR
Wenzhuo Huang
作者
Wenzhuo Huang
搞运维的工程师,写代码的运维人。专注 Kubernetes、AWS、GitOps 与基础设施可靠性。这个博客既是我的技术笔记本,也是我踩过的坑的受害者档案。

相关文章

Kubernetes 存储体系生产实践:PV/PVC/StorageClass 全解

·1000 字·5 分钟
从存储基础概念到生产实战,覆盖 StorageClass 动态供给配置、AWS EBS 和 EFS CSI 驱动安装、StatefulSet 存储管理、PVC 在线扩容操作、跨 AZ 挂载失败排查,以及有状态服务数据迁移方案。

AWS EKS 实战指南

·877 字·5 分钟
覆盖 EKS 核心架构、eksctl/aws cli 常用操作、IRSA 原理与配置、VPC CNI 网络限制、升级流程及常见故障排查。