Skip to main content

EKS Storage

Phần này trình bày các giải pháp storage cho EKS: EBS CSI Driver, EFS CSI Driver, FSx, cùng các pattern PersistentVolume/PersistentVolumeClaim và StorageClass phổ biến trong production.


📌 1. Tổng quan Storage trong EKS

1.1. Bài toán Storage trong Kubernetes

Container mặc định là ephemeral — khi Pod restart, dữ liệu bị mất. Cần persistent storage cho:

  • Database (MySQL, PostgreSQL, MongoDB)
  • Cache (Redis, Memcached khi cần persistence)
  • File uploads, shared data giữa các Pod
  • Log buffer, queue data

1.2. Các loại storage trên AWS cho EKS

StorageAccess ModeTốc độChi phíPhù hợp
EBS (Block)ReadWriteOnceCao$0.08/GB (gp3)Database, single Pod
EFS (File)ReadWriteManyTrung bình$0.30/GBShared storage, multi-Pod
FSx Lustre (File)ReadWriteManyRất cao$0.14/GB/thángML training, HPC
FSx NetApp ONTAPReadWriteManyCaoTùy cấu hìnhEnterprise, NFS workload
S3 (Object)Qua SDK/MountpointCao (throughput)$0.023/GBData lake, backup, assets

1.3. Kubernetes Storage Concepts

ConceptVai trò
PersistentVolume (PV)Đại diện cho storage thực tế (EBS volume, EFS filesystem)
PersistentVolumeClaim (PVC)Yêu cầu storage từ phía ứng dụng
StorageClassTemplate định nghĩa cách tạo PV tự động (dynamic provisioning)
CSI DriverPlugin kết nối Kubernetes với storage backend (EBS, EFS,...)

💾 2. Amazon EBS CSI Driver

2.1. EBS CSI Driver là gì?

EBS CSI Driver cho phép Kubernetes tự động tạo, gắn, mở rộng và xóa EBS volume thông qua PVC/StorageClass. Đây là CSI driver phổ biến nhất cho EKS.

2.2. Cài đặt EBS CSI Driver

Cách 1: EKS Addon (khuyến nghị)

aws eks create-addon \
--cluster-name my-eks \
--addon-name aws-ebs-csi-driver \
--service-account-role-arn arn:aws:iam::123456789:role/EBSCSIDriverRole

Cách 2: Terraform

resource "aws_eks_addon" "ebs_csi" {
cluster_name = var.cluster_name
addon_name = "aws-ebs-csi-driver"
addon_version = "v1.28.0-eksbuild.1"
service_account_role_arn = aws_iam_role.ebs_csi.arn
resolve_conflicts_on_update = "OVERWRITE"
}

2.3. IAM Policy cho EBS CSI Driver

resource "aws_iam_role" "ebs_csi" {
name = "EBSCSIDriverRole"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.eks.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"${replace(aws_eks_cluster.main.identity[0].oidc[0].issuer, "https://", "")}:sub" = "system:serviceaccount:kube-system:ebs-csi-controller-sa"
}
}
}]
})
}

resource "aws_iam_role_policy_attachment" "ebs_csi" {
role = aws_iam_role.ebs_csi.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy"
}

2.4. StorageClass cho EBS

gp3 (khuyến nghị — mặc định):

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

io2 (high-performance database):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: io2-high-perf
provisioner: ebs.csi.aws.com
parameters:
type: io2
iopsPerGB: "50"
fsType: ext4
encrypted: "true"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

2.5. Sử dụng PVC với EBS

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: gp3
resources:
requests:
storage: 20Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: 500m
memory: 1Gi
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: gp3
resources:
requests:
storage: 20Gi

2.6. Mở rộng EBS Volume

EBS CSI Driver hỗ trợ online volume expansion — không cần restart Pod:

# Sửa PVC size
kubectl patch pvc postgres-data -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'

# Kiểm tra trạng thái
kubectl get pvc postgres-data

2.7. EBS Snapshots

Tạo VolumeSnapshot để backup:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: ebs-snapshot-class
driver: ebs.csi.aws.com
deletionPolicy: Retain
---
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: postgres-snapshot
spec:
volumeSnapshotClassName: ebs-snapshot-class
source:
persistentVolumeClaimName: postgres-data

Restore từ snapshot:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data-restored
spec:
accessModes:
- ReadWriteOnce
storageClassName: gp3
resources:
requests:
storage: 20Gi
dataSource:
name: postgres-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
Best Practices cho EBS
  • Luôn dùng volumeBindingMode: WaitForFirstConsumer — EBS volume phải cùng AZ với Pod.
  • Bật encrypted: "true" trong StorageClass cho production.
  • Dùng allowVolumeExpansion: true để cho phép mở rộng volume sau này.
  • Set reclaimPolicy: Retain cho production database — tránh mất dữ liệu khi xóa PVC.
  • Tạo VolumeSnapshot định kỳ cho backup.

📂 3. Amazon EFS CSI Driver

3.1. EFS CSI Driver là gì?

EFS CSI Driver cho phép mount Amazon EFS filesystem vào Pod. EFS hỗ trợ ReadWriteMany — nhiều Pod trên nhiều Node có thể đọc/ghi cùng một filesystem.

3.2. Khi nào dùng EFS?

  • Nhiều Pod cần shared storage (upload files, CMS assets)
  • Workload cần ReadWriteMany access mode
  • Data cần persist qua nhiều AZ
  • Không cần IOPS cao (throughput-oriented)

3.3. Cài đặt EFS CSI Driver

EKS Addon:

aws eks create-addon \
--cluster-name my-eks \
--addon-name aws-efs-csi-driver \
--service-account-role-arn arn:aws:iam::123456789:role/EFSCSIDriverRole

Terraform:

resource "aws_eks_addon" "efs_csi" {
cluster_name = var.cluster_name
addon_name = "aws-efs-csi-driver"
addon_version = "v2.0.4-eksbuild.1"
service_account_role_arn = aws_iam_role.efs_csi.arn
}

3.4. Tạo EFS Filesystem

resource "aws_efs_file_system" "eks" {
creation_token = "eks-shared-storage"
encrypted = true

performance_mode = "generalPurpose"
throughput_mode = "elastic"

lifecycle_policy {
transition_to_ia = "AFTER_30_DAYS"
}

lifecycle_policy {
transition_to_primary_storage_class = "AFTER_1_ACCESS"
}

tags = {
Name = "eks-shared-storage"
}
}

resource "aws_efs_mount_target" "eks" {
count = length(var.private_subnet_ids)
file_system_id = aws_efs_file_system.eks.id
subnet_id = var.private_subnet_ids[count.index]
security_groups = [aws_security_group.efs.id]
}

resource "aws_security_group" "efs" {
name = "eks-efs-sg"
vpc_id = var.vpc_id

ingress {
from_port = 2049
to_port = 2049
protocol = "tcp"
security_groups = [var.node_security_group_id]
}
}

3.5. StorageClass cho EFS

Static provisioning (dùng filesystem có sẵn):

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: efs-sc
provisioner: efs.csi.aws.com
parameters:
provisioningMode: efs-ap
fileSystemId: fs-0123456789abcdef
directoryPerms: "700"
basePath: "/dynamic_provisioning"

PVC sử dụng EFS:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-uploads
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 5Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: app
image: my-web-app:latest
volumeMounts:
- name: uploads
mountPath: /app/uploads
resources:
requests:
cpu: 250m
memory: 256Mi
volumes:
- name: uploads
persistentVolumeClaim:
claimName: shared-uploads
Lưu ý khi dùng EFS
  • EFS chậm hơn EBS đáng kể cho random I/O — không dùng cho database.
  • Chi phí EFS cao hơn EBS (~4x) — dùng Infrequent Access để tiết kiệm.
  • Security Group phải mở port 2049 (NFS) từ Node Security Group.
  • EFS không có giới hạn size — storage trong PVC chỉ là metadata, không enforce.

⚡ 4. FSx for Lustre

4.1. Khi nào dùng FSx Lustre?

FSx Lustre phù hợp cho workload cần throughput cực cao:

  • ML/AI training (đọc dataset lớn)
  • HPC (High Performance Computing)
  • Video processing, rendering
  • Tích hợp trực tiếp với S3 (lazy load data)

4.2. Cài đặt FSx CSI Driver

helm repo add aws-fsx-csi-driver https://kubernetes-sigs.github.io/aws-fsx-csi-driver
helm install aws-fsx-csi-driver aws-fsx-csi-driver/aws-fsx-csi-driver \
--namespace kube-system

4.3. StorageClass cho FSx Lustre

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fsx-lustre
provisioner: fsx.csi.aws.com
parameters:
subnetId: subnet-0123456789abcdef
securityGroupIds: sg-0123456789abcdef
deploymentType: SCRATCH_2
autoImportPolicy: NEW_CHANGED_DELETED
s3ImportPath: s3://my-training-data
s3ExportPath: s3://my-training-data/export
volumeBindingMode: Immediate

🪣 5. S3 Mountpoint (S3 CSI Driver)

5.1. S3 Mountpoint là gì?

Mountpoint for Amazon S3 cho phép mount S3 bucket vào Pod như một filesystem. Phù hợp cho workload read-heavy với dataset lớn.

5.2. Cài đặt S3 CSI Driver

aws eks create-addon \
--cluster-name my-eks \
--addon-name aws-mountpoint-s3-csi-driver \
--service-account-role-arn arn:aws:iam::123456789:role/S3CSIDriverRole

5.3. Sử dụng S3 Mountpoint

apiVersion: v1
kind: PersistentVolume
metadata:
name: s3-pv
spec:
capacity:
storage: 1Ti
accessModes:
- ReadWriteMany
csi:
driver: s3.csi.aws.com
volumeHandle: s3-csi-volume
volumeAttributes:
bucketName: my-data-bucket
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: s3-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
resources:
requests:
storage: 1Ti
volumeName: s3-pv
Hạn chế của S3 Mountpoint
  • Không hỗ trợ random write — chỉ sequential write (append) và read.
  • Không hỗ trợ symlinks, hard links, file locking.
  • Latency cao hơn EBS/EFS cho small file I/O.
  • Phù hợp cho: data lake reads, ML dataset, log archive.

📊 6. So sánh và lựa chọn Storage

6.1. Bảng so sánh chi tiết

Tiêu chíEBSEFSFSx LustreS3 Mountpoint
Access ModeReadWriteOnceReadWriteManyReadWriteManyReadWriteMany (giới hạn)
PerformanceRất cao (IOPS)Trung bìnhCực cao (throughput)Cao (throughput)
Chi phí /GB$0.08 (gp3)$0.30$0.14$0.023
Multi-AZ❌ (single AZ)✔ (S3)
Encryption
Snapshot/Backup✔ (EBS Snapshot)✔ (AWS Backup)✔ (S3 versioning)
Volume Expansion✔ (online)✔ (tự động)Hạn chếN/A
CSI Driveraws-ebs-csi-driveraws-efs-csi-driverfsx-csi-drivermountpoint-s3-csi-driver

6.2. Decision Tree

6.3. Khuyến nghị theo workload

WorkloadStorage khuyến nghịLý do
PostgreSQL / MySQLEBS gp3IOPS cao, consistent performance
Redis (persistent)EBS gp3Low latency, single Pod
Shared file uploadsEFSReadWriteMany, multi-Pod
ML Training datasetFSx Lustre hoặc S3 MountpointHigh throughput, large dataset
Static assets / MediaS3 MountpointChi phí thấp, read-heavy
Log buffer (temp)emptyDirEphemeral, không cần persist

🔒 7. Security và Backup

7.1. Encryption at Rest

Luôn bật encryption cho production:

# EBS StorageClass với encryption
parameters:
type: gp3
encrypted: "true"
# Dùng KMS key tùy chỉnh (optional)
kmsKeyId: arn:aws:kms:ap-southeast-1:123456789:key/xxx-yyy-zzz

7.2. Backup Strategy

EBS — dùng VolumeSnapshot (đã trình bày ở section 2.7)

EFS — dùng AWS Backup:

resource "aws_backup_plan" "efs" {
name = "efs-daily-backup"

rule {
rule_name = "daily"
target_vault_name = aws_backup_vault.main.name
schedule = "cron(0 3 * * ? *)"

lifecycle {
delete_after = 30
}
}
}

resource "aws_backup_selection" "efs" {
name = "efs-selection"
iam_role_arn = aws_iam_role.backup.arn
plan_id = aws_backup_plan.efs.id

resources = [
aws_efs_file_system.eks.arn
]
}

7.3. PodDisruptionBudget cho Stateful Workload

Đảm bảo không downtime khi scale/upgrade Node:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: postgres-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: postgres

🏗️ 8. Best Practices tổng hợp

Checklist Storage cho Production

  • ✔ EBS CSI Driver đã cài (EKS Addon)
  • ✔ Default StorageClass là gp3 (không phải gp2)
  • volumeBindingMode: WaitForFirstConsumer cho EBS StorageClass
  • encrypted: "true" cho mọi StorageClass
  • allowVolumeExpansion: true cho phép mở rộng volume
  • reclaimPolicy: Retain cho database/critical PV
  • ✔ VolumeSnapshot / AWS Backup đã cấu hình
  • ✔ PodDisruptionBudget cho stateful workload
  • ✔ EFS dùng lifecycle policy Infrequent Access tiết kiệm chi phí
  • ✔ Monitoring: theo dõi PVC usage, disk pressure trên Node

Các lỗi thường gặp

LỗiNguyên nhânGiải pháp
Pod Pending — volume not foundEBS volume khác AZ với NodeDùng WaitForFirstConsumer
PVC Pending — provisioning failedThiếu IAM permissions cho CSI DriverKiểm tra IRSA policy
Mount timeout (EFS)Security Group chặn port 2049Mở NFS port từ Node SG
Volume resize không có hiệu lựcStorageClass thiếu allowVolumeExpansionTạo lại StorageClass
Data mất khi xóa PVCreclaimPolicy: DeleteĐổi thành Retain cho production

9. Tổng kết

Storage trong EKS có nhiều lựa chọn phù hợp với từng loại workload:

  • EBS - Storage mặc định cho hầu hết workload, IOPS cao, single Pod
  • EFS - Shared storage cho multi-Pod, ReadWriteMany
  • FSx Lustre - High throughput cho ML/HPC
  • S3 Mountpoint - Chi phí thấp cho read-heavy dataset

Nguyên tắc chung: bắt đầu với EBS gp3, chỉ dùng EFS/FSx khi thực sự cần ReadWriteMany hoặc high throughput.

Tham khảo: