Giới thiệu
Trong bài viết này, chúng ta sẽ tìm hiểu cách tích hợp Amazon Elastic Block Store (EBS) với Amazon Elastic Kubernetes Service (EKS). Chúng ta sẽ cấu hình một cluster EKS bằng Terraform, thiết lập driver EBS CSI, và chạy một container Nginx sử dụng EBS để lưu trữ các tệp website.
Bài viết này là hướng dẫn thực tiễn cho bất kỳ ai xây dựng các workload có trạng thái trên EKS.
Hiểu về Amazon EBS cho Kubernetes
Amazon EBS là gì?
Amazon Elastic Block Store (EBS) cung cấp các volume lưu trữ block bền vững có thể được gắn vào các instance Amazon EC2. Trong Kubernetes, các volume EBS có thể được truy xuất bởi các Pods thông qua driver EBS CSI (Container Storage Interface), cho phép các workload duy trì dữ liệu vượt qua vòng đời của pod.
Sơ đồ Kiến trúc
Khi bạn sử dụng Amazon EBS với Amazon EKS, ứng dụng của bạn yêu cầu lưu trữ thông qua một PersistentVolumeClaim (PVC). Kubernetes sau đó sẽ kết nối yêu cầu này với một EBS volume hiện có (cung cấp tĩnh) hoặc tự động tạo mới một volume (cung cấp động) với sự trợ giúp của StorageClass và driver EBS CSI.
Driver CSI sẽ giao tiếp với AWS để tạo và gắn volume vào nút worker mà Pod của bạn đang chạy, và volume sẽ được gắn vào bên trong container tại đường dẫn chỉ định (như /usr/share/nginx/html). Một điều quan trọng cần nhớ là các volume EBS chỉ hoạt động trong một Availability Zone (AZ) duy nhất. Điều này có nghĩa là Pod của bạn và volume EBS phải nằm trong cùng một AZ. Cung cấp động thường sẽ xử lý điều này một cách tự động, nhưng đối với cung cấp tĩnh, bạn cần đảm bảo volume được tạo trong AZ đúng.
Lợi ích chính cho EKS
- Độ bền: Dữ liệu tồn tại qua các lần khởi động lại pod.
- Hiệu suất: Nhiều loại volume (gp3, io2, st1, v.v.) cho thông lượng hoặc IOPS tối ưu.
- Tính linh hoạt: Các volume có thể được thay đổi kích thước mà không cần dừng hoạt động.
- Chi phí hợp lý: Chỉ trả tiền cho lưu trữ đã được cấp phát.
Những lưu ý quan trọng khi sử dụng EKS
- Các volume EBS có phạm vi theo AZ – một Pod sử dụng EBS phải chạy trong cùng một Availability Zone với volume.
- Cần có Kubernetes v1.17+ với hỗ trợ driver CSI.
- Các Pod cần EBS phải sử dụng StatefulSets hoặc các Deployments được lên lịch cẩn thận.
- Cần theo dõi hạn mức tài nguyên để tránh cạn kiệt lưu trữ hoặc vượt quá giới hạn API.
Bước 1: Cấp phát Cluster EKS với Terraform trong VPC
Bước đầu tiên trong việc tích hợp Amazon EBS với EKS là cấp phát một cluster Kubernetes chạy an toàn bên trong một VPC riêng biệt. Chúng tôi sẽ sử dụng các mô-đun Terraform cộng đồng AWS phổ biến cho cả việc thiết lập VPC và EKS. Vui lòng tham khảo mô-đun chính trong repo GitHub.
Bước 2: Tạo Hệ Thống Tệp EFS
EBS Storage: Lưu trữ EBS được mã hóa với tùy chọn mã hóa
hcl
resource "aws_ebs_volume" "static_volume" {
count = var.create_static_volume ? 1 : 0
availability_zone = var.availability_zones[0]
size = var.static_volume_size
type = var.ebs_volume_type
encrypted = var.ebs_encrypted
kms_key_id = var.ebs_kms_key_id
# Cấu hình IOPS cho các volume gp3, io1, io2
iops = var.ebs_volume_type == "gp3" || var.ebs_volume_type == "io1" || var.ebs_volume_type == "io2" ? var.ebs_volume_iops : null
# Cấu hình throughput cho các volume gp3
throughput = var.ebs_volume_type == "gp3" ? var.ebs_volume_throughput : null
tags = {
Name = "${var.cluster_name}-static-ebs-volume"
Environment = var.environment
Terraform = "true"
Purpose = "Static EBS volume for Kubernetes testing"
}
}
IAM Role: Đối với EFS CSI driver với danh tính pod
hcl
resource "aws_iam_role" "ebs_csi_driver_role" {
name = "${var.cluster_name}-ebs-csi-driver-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "pods.eks.amazonaws.com"
}
Action = [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
})
tags = {
Name = "${var.cluster_name}-ebs-csi-driver-role"
Environment = var.environment
Terraform = "true"
}
}
Bước 3: Triển Khai Các Mẫu Lưu Trữ EBS
Cung cấp tĩnh
Trong cung cấp tĩnh, PersistentVolume (PV) được tạo thủ công bởi quản trị viên. PV sẽ chỉ rõ ID volume EBS hiện có và thư mục.
Cách hoạt động:
- Bạn đầu tiên cấp phát một EBS Volume bằng Terraform/CLI.
- Sau đó, bạn định nghĩa một tài nguyên PersistentVolume (PV) của Kubernetes tham chiếu đến ID volume EBS.
- Tiếp theo, bạn tạo một PersistentVolumeClaim (PVC) yêu cầu lưu trữ phù hợp với các thông số của PV.
- Triển khai Pod của bạn (ví dụ: Nginx) và gắn PVC như một volume để lưu trữ tệp.
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-static-sc
provisioner: ebs.csi.aws.com
parameters:
type: gp3
fsType: ext4
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: ebs-static-pv
spec:
capacity:
storage: 10Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: ebs-static-sc
csi:
driver: ebs.csi.aws.com
volumeHandle: ${EBS_VOLUME_ID}
fsType: ext4
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ebs-static-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: ebs-static-sc
volumeName: ebs-static-pv
resources:
requests:
storage: 10Gi
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-ebs-static-pod
namespace: default
labels:
app: nginx-ebs-static
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: ebs-storage
mountPath: /usr/share/nginx/html
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command: ["/bin/sh"]
args: ["-c", "echo '<h1>Hello from EBS Static Volume!</h1><p><b>Pod:</b> '$POD_NAME'</p>' > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"]
volumes:
- name: ebs-storage
persistentVolumeClaim:
claimName: ebs-static-pvc
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-ebs-static-service
namespace: default
labels:
app: nginx-ebs-static
spec:
selector:
app: nginx-ebs-static
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Bước 4: Triển Khai cho Cung Cấp Tĩnh
- Lấy giá trị EBS từ Terraform:
cd infrastructure
EBS_VOLUME_ID=$(terraform output -raw ebs_volume_id 2>/dev/null || echo "")
- Cập nhật các manifest với giá trị EFS:
sed "s/\${EBS_VOLUME_ID}/$EBS_VOLUME_ID/g" static-persistent-volume.yaml > static-persistent-volume-final.yaml
- Áp dụng các manifest tĩnh:
kubectl apply -f static-storage-class.yaml
kubectl apply -f static-persistent-volume-final.yaml
kubectl apply -f static-persistent-volume-claim.yaml
kubectl apply -f static-nginx-pod.yaml
kubectl apply -f static-nginx-service.yaml
Cung cấp động (Khuyến nghị)
Trong cung cấp động, Kubernetes tự động tạo EBS volumes theo yêu cầu bằng driver EBS CSI và một StorageClass.
Cách hoạt động:
- Định nghĩa một StorageClass chỉ định volume EBS (ví dụ: loại gp3, chính sách giữ lại, chế độ gắn kết).
- Khi một ứng dụng yêu cầu lưu trữ thông qua PVC, Kubernetes sẽ tạo động:
- Một PV mới được hỗ trợ bởi một EBS volume mới.
- Các Pod gắn PV được cấp phát động thông qua PVC.
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ebs-dynamic-sc
provisioner: ebs.csi.aws.com
parameters:
type: gp3
fsType: ext4
encrypted: "true"
iops: "3000"
throughput: "125"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ebs-dynamic-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: ebs-dynamic-sc
resources:
requests:
storage: 10Gi
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-ebs-dynamic-pod
namespace: default
labels:
app: nginx-ebs-dynamic
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: ebs-storage
mountPath: /usr/share/nginx/html
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo '<h1>Hello from EBS Dynamic Volume!</h1><p><b>Pod:</b> '$POD_NAME'</p>' > /usr/share/nginx/html/index.html"]
volumes:
- name: ebs-storage
persistentVolumeClaim:
claimName: ebs-dynamic-pvc
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-ebs-dynamic-service
namespace: default
labels:
app: nginx-ebs-dynamic
spec:
selector:
app: nginx-ebs-dynamic
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
Bước 5: Triển Khai cho Cung Cấp Động
- Áp dụng các manifest tĩnh:
kubectl apply -f dynamic-storage-class.yaml
kubectl apply -f dynamic-persistent-volume-claim.yaml
kubectl apply -f dynamic-nginx-pod.yaml
kubectl apply -f dynamic-nginx-service.yaml
Kiểm tra
Kiểm tra rằng mọi thứ đang hoạt động:
# Kiểm tra pods EFS CSI driver
kubectl get pods -n kube-system -l app=efs-csi-controller
# Kiểm tra các lớp lưu trữ
kubectl get storageclass ebs-sc
# Đối với Cung cấp Tĩnh:
kubectl get pv ebs-static-pv
kubectl get pvc ebs-static-pvc
kubectl get pod nginx-ebs-static
kubectl get service nginx-ebs-static-service
# Đối với Cung cấp Động:
kubectl get pvc ebs-dynamic-pvc
kubectl get pod nginx-ebs-dynamic
kubectl get service nginx-ebs-dynamic-service
Dọn dẹp
Dọn dẹp Cung cấp Tĩnh
kubectl delete -f static-storage-class.yaml
kubectl delete -f static-persistent-volume-final.yaml
kubectl delete -f static-persistent-volume-claim.yaml
kubectl delete -f static-nginx-pod.yaml
kubectl delete -f static-nginx-service.yaml
Dọn dẹp Cung cấp Động
kubectl delete -f dynamic-nginx-service.yaml
kubectl delete -f dynamic-nginx-pod.yaml
kubectl delete -f dynamic-persistent-volume-claim.yaml
kubectl delete -f dynamic-storage-class.yaml
Và sau đó terraform destroy hạ tầng EKS nếu bạn không sử dụng để tiết kiệm chi phí.
Kết luận
Amazon EBS cung cấp lưu trữ block đáng tin cậy cho các workload có trạng thái trên Amazon EKS. Việc sử dụng Terraform để cấp phát cơ sở hạ tầng và các manifest Kubernetes cho cấu hình lưu trữ mang lại cho bạn cả tự động hóa và tính linh hoạt. Với việc thiết lập đúng các vai trò IAM, driver CSI và các thực tiễn tốt nhất, bạn có thể tự tin chạy các workload như Nginx với lưu trữ bền vững trên EKS.