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
| Storage | Access Mode | Tốc độ | Chi phí | Phù hợp |
|---|---|---|---|---|
| EBS (Block) | ReadWriteOnce | Cao | $0.08/GB (gp3) | Database, single Pod |
| EFS (File) | ReadWriteMany | Trung bình | $0.30/GB | Shared storage, multi-Pod |
| FSx Lustre (File) | ReadWriteMany | Rất cao | $0.14/GB/tháng | ML training, HPC |
| FSx NetApp ONTAP | ReadWriteMany | Cao | Tùy cấu hình | Enterprise, NFS workload |
| S3 (Object) | Qua SDK/Mountpoint | Cao (throughput) | $0.023/GB | Data lake, backup, assets |
1.3. Kubernetes Storage Concepts
| Concept | Vai 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 |
| StorageClass | Template định nghĩa cách tạo PV tự động (dynamic provisioning) |
| CSI Driver | Plugin 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
- 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: Retaincho 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
- 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 —
storagetrong 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
- 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í | EBS | EFS | FSx Lustre | S3 Mountpoint |
|---|---|---|---|---|
| Access Mode | ReadWriteOnce | ReadWriteMany | ReadWriteMany | ReadWriteMany (giới hạn) |
| Performance | Rất cao (IOPS) | Trung bình | Cự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 Driver | aws-ebs-csi-driver | aws-efs-csi-driver | fsx-csi-driver | mountpoint-s3-csi-driver |
6.2. Decision Tree
6.3. Khuyến nghị theo workload
| Workload | Storage khuyến nghị | Lý do |
|---|---|---|
| PostgreSQL / MySQL | EBS gp3 | IOPS cao, consistent performance |
| Redis (persistent) | EBS gp3 | Low latency, single Pod |
| Shared file uploads | EFS | ReadWriteMany, multi-Pod |
| ML Training dataset | FSx Lustre hoặc S3 Mountpoint | High throughput, large dataset |
| Static assets / Media | S3 Mountpoint | Chi phí thấp, read-heavy |
| Log buffer (temp) | emptyDir | Ephemeral, 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: WaitForFirstConsumercho EBS StorageClass - ✔
encrypted: "true"cho mọi StorageClass - ✔
allowVolumeExpansion: truecho phép mở rộng volume - ✔
reclaimPolicy: Retaincho 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ỗi | Nguyên nhân | Giải pháp |
|---|---|---|
| Pod Pending — volume not found | EBS volume khác AZ với Node | Dùng WaitForFirstConsumer |
| PVC Pending — provisioning failed | Thiếu IAM permissions cho CSI Driver | Kiểm tra IRSA policy |
| Mount timeout (EFS) | Security Group chặn port 2049 | Mở NFS port từ Node SG |
| Volume resize không có hiệu lực | StorageClass thiếu allowVolumeExpansion | Tạo lại StorageClass |
| Data mất khi xóa PVC | reclaimPolicy: 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: