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 S3 như một giải pháp lưu trữ với Amazon EKS bằng cách sử dụng Terraform và các tài liệu Kubernetes YAML. Chúng ta sẽ triển khai một container Nginx đơn giản phục vụ các tệp web được lưu trữ trong một bucket S3.
Cách tiếp cận này tận dụng driver Mountpoint cho S3 CSI, cho phép các workload Kubernetes truy cập các đối tượng Amazon S3 bằng các giao diện POSIX tiêu chuẩn.
Hiểu về Amazon S3 cho Kubernetes
Amazon S3 là gì?
Amazon Simple Storage Service (Amazon S3) là một dịch vụ lưu trữ đối tượng được thiết kế cho khả năng mở rộng, độ bền và tính sẵn sàng. Khác với lưu trữ khối truyền thống (như EBS) hoặc lưu trữ tệp (như EFS), S3 lưu trữ dữ liệu dưới dạng các đối tượng trong các bucket, điều này làm cho nó lý tưởng cho nội dung tĩnh, nhật ký và sao lưu.
Sơ đồ kiến trúc
Kiến trúc của việc kết nối lưu trữ Amazon S3 với một cluster EKS xoay quanh driver S3 CSI (Container Storage Interface) và tích hợp Mountpoint cho S3.
Ở lớp cơ sở, một bucket S3 đóng vai trò là kho lưu trữ đối tượng ở phía backend, nơi dữ liệu ứng dụng được giữ. Trong Kubernetes, một StorageClass định nghĩa cách thức lưu trữ được cấp phát và tiêu thụ. Tuy nhiên, với S3, hiện tại chỉ hỗ trợ cấp phát tĩnh—có nghĩa là một PersistentVolume (PV) phải được tạo thủ công và ánh xạ vào một bucket S3 hiện có, sau đó một PersistentVolumeClaim (PVC) sẽ liên kết với PV đó để các workload có thể truy cập.
Khi một pod được triển khai, Kubernetes sẽ gắn PVC vào hệ thống tệp của container thông qua driver S3 CSI, mà nội bộ sử dụng Mountpoint cho S3 để cung cấp quyền truy cập tương tự như hệ thống tệp vào các đối tượng trong bucket.
Mặc dù cấp phát động—nơi PVC tự động kích hoạt việc tạo ra các volume lưu trữ mới—là điều phổ biến cho các driver như EBS và EFS, nhưng hiện tại nó chưa có sẵn cho S3. Điều này khiến việc cấp phát tĩnh trở thành lựa chọn duy nhất, yêu cầu các quản trị viên phải định nghĩa trước ánh xạ giữa các PV và các bucket S3. Bảo mật được xử lý thông qua IAM Roles for Service Accounts (IRSA), đảm bảo rằng các pod chỉ có quyền tối thiểu cần thiết để truy cập vào các bucket S3 cụ thể.
Lợi ích chính khi sử dụng S3 với EKS
- Khả năng mở rộng: Dung lượng lưu trữ gần như không giới hạn.
- Độ bền: Đảm bảo độ bền 11 9’s.
- Chi phí hiệu quả: Chỉ phải trả cho những gì bạn sử dụng mà không cần cấp phát trước.
- Tích hợp: Tích hợp dễ dàng với các dịch vụ AWS như Athena, Glue và CloudFront.
Một số cân nhắc quan trọng cho EKS
- Yêu cầu driver CSI: Driver Mountpoint cho S3 CSI phải được cài đặt.
- Hỗ trợ danh tính pod: Hiện tại, IRSA (IAM Roles for Service Accounts) là yêu cầu. Danh tính pod chưa được hỗ trợ.
- Giới hạn: Chỉ hỗ trợ cấp phát tĩnh tính đến thời điểm này. Cấp phát động đang được lên kế hoạch.
- Hạn chế tài nguyên: Theo dõi các giới hạn như số lượng mô tả tệp mở và băng thông mạng khi mở rộng các workload.
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 S3 với EKS là cấp phát một cluster Kubernetes hoạt động an toàn trong một VPC riêng biệt. Chúng ta sẽ sử dụng các mô-đun cộng đồng Terraform AWS được sử dụng rộng rãi cho 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 bucket S3
Bucket S3: Bucket S3 được mã hóa với phiên bản và quyền truy cập
hcl
resource "aws_s3_bucket" "main" {
bucket = var.bucket_name
tags = {
Name = var.bucket_name
Environment = var.environment
Terraform = "true"
}
}
Phiên bản bucket S3
hcl
resource "aws_s3_bucket_versioning" "main" {
bucket = aws_s3_bucket.main.id
versioning_configuration {
status = var.versioning_enabled ? "Enabled" : "Disabled"
}
}
Mã hóa bucket S3
hcl
resource "aws_s3_bucket_server_side_encryption_configuration" "main" {
bucket = aws_s3_bucket.main.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
bucket_key_enabled = true
}
}
Khối quyền truy cập công khai cho bucket S3
hcl
resource "aws_s3_bucket_public_access_block" "main" {
bucket = aws_s3_bucket.main.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
IAM Role: Cho driver S3 CSI
hcl
resource "aws_iam_role" "s3_csi_driver_role" {
name = "${var.cluster_name}-s3-csi-driver-role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}"
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}:sub" = "system:serviceaccount:kube-system:s3-csi-driver-sa"
"${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}:aud" = "sts.amazonaws.com"
}
}
}
]
})
tags = {
Name = "${var.cluster_name}-s3-csi-driver-role"
Environment = var.environment
Terraform = "true"
}
}
Chính sách driver S3 CSI (Dựa trên tài liệu AWS)
hcl
resource "aws_iam_policy" "s3_csi_driver_policy" {
name = "${var.cluster_name}-s3-csi-driver-policy"
description = "Chính sách IAM cho driver S3 CSI dựa trên tài liệu AWS"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:ListBucket"
]
Resource = aws_s3_bucket.main.arn
},
{
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:AbortMultipartUpload",
"s3:DeleteObject"
]
Resource = "${aws_s3_bucket.main.arn}/*"
}
]
})
tags = {
Name = "${var.cluster_name}-s3-csi-driver-policy"
Environment = var.environment
Terraform = "true"
}
}
Gắn chính sách driver S3 CSI
hcl
resource "aws_iam_role_policy_attachment" "s3_csi_driver_policy" {
role = aws_iam_role.s3_csi_driver_role.name
policy_arn = aws_iam_policy.s3_csi_driver_policy.arn
}
Add-on Mountpoint cho S3: Driver S3 CSI cho tích hợp Kubernetes
hcl
resource "aws_eks_addon" "s3_mountpoint_csi_driver" {
cluster_name = module.eks.cluster_name
addon_name = "aws-mountpoint-s3-csi-driver"
service_account_role_arn = module.s3.s3_csi_driver_role_arn
depends_on = [module.s3]
tags = {
Name = "${var.cluster_name}-s3-mountpoint-csi-driver"
Environment = var.environment
Terraform = "true"
}
}
Bước 3: Mô hình triển khai lưu trữ S3
Vì chỉ hỗ trợ cấp phát tĩnh cho S3 ngày nay, chúng ta sẽ định nghĩa các PersistentVolumes (PV) tham chiếu một bucket S3.
storage-class.yaml - StorageClass cho driver S3 CSI
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: s3-csi-sc
provisioner: s3.csi.aws.com
parameters:
bucketName: ${S3_BUCKET_NAME}
prefix: "k8s-storage/"
volumeBindingMode: Immediate
allowVolumeExpansion: false
persistent-volume.yaml - PersistentVolume cho bucket S3 (chỉ cấp phát tĩnh)
yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: s3-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: s3-csi-sc
csi:
driver: s3.csi.aws.com
volumeHandle: s3-csi-driver-volume
volumeAttributes:
bucketName: ${S3_BUCKET_NAME}
prefix: "k8s-storage/"
persistent-volume-claim.yaml - PVC sử dụng driver S3 CSI
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: s3-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: s3-csi-sc
resources:
requests:
storage: 1Gi
nginx-pod.yaml - Pod Nginx với lưu trữ S3 gắn và tạo nội dung
yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-s3-pod
namespace: default
labels:
app: nginx-s3
spec:
securityContext:
runAsUser: 0
runAsGroup: 0
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
command: ["/bin/sh", "-c"]
args:
- |
echo '<h1>Hello from S3 Mountpoint!</h1><p><b>Pod:</b> '$POD_NAME'</p>' > /usr/share/nginx/html/index.html || true
sed -i 's/user nginx;/user root;/' /etc/nginx/nginx.conf
nginx -g 'daemon off;'
volumeMounts:
- name: s3-storage
mountPath: /usr/share/nginx/html
volumes:
- name: s3-storage
persistentVolumeClaim:
claimName: s3-pvc
nginx-service.yaml - Dịch vụ ClusterIP để phơi bày nginx trên cổng 80
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-s3-service
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
selector:
app: nginx-s3
Các bước triển khai cho việc cấp phát tĩnh
- Lấy tên bucket S3 từ Terraform:
bash
cd infrastructure
S3_BUCKET_NAME=$(terraform output -raw s3_bucket_name 2>/dev/null || echo "")
- Cập nhật manifests với các giá trị S3:
bash
sed "s/\${S3_BUCKET_NAME}/$S3_BUCKET_NAME/g" storage-class.yaml > storage-class-final.yaml
sed "s/\${S3_BUCKET_NAME}/$S3_BUCKET_NAME/g" persistent-volume.yaml > persistent-volume-final.yaml
- Áp dụng manifests:
bash
kubectl apply -f storage-class-final.yaml
kubectl apply -f persistent-volume-final.yaml
kubectl apply -f persistent-volume-claim.yaml
kubectl apply -f nginx-pod.yaml
kubectl apply -f nginx-service.yaml
Tham khảo deploy.sh
cho script triển khai tự động.
bash
$ kubectl get sc,pv,pvc
Xác minh
bash
# Kiểm tra trạng thái driver S3 CSI:
kubectl get pods -n kube-system -l app=aws-mountpoint-s3-csi-driver
# Kiểm tra trạng thái triển khai:
kubectl get pod nginx-s3-pod
kubectl get service nginx-s3-service
kubectl get pvc s3-pvc
kubectl get pv
# Kiểm tra máy chủ web nginx:
kubectl port-forward service/nginx-s3-service 8084:80
# Sau đó truy cập http://localhost:8084
# Kiểm tra sự tồn tại tệp S3
kubectl exec nginx-s3-pod -- ls -la /usr/share/nginx/html/
kubectl exec nginx-s3-pod -- cat /usr/share/nginx/html/index.html
# Kiểm tra nội dung bucket S3:
aws s3 ls s3://$S3_BUCKET_NAME/k8s-storage/
Dọn dẹp
bash
kubectl delete -f nginx-service.yaml
kubectl delete -f nginx-pod.yaml
kubectl delete -f persistent-volume-claim.yaml
kubectl delete -f persistent-volume.yaml
kubectl delete -f storage-class.yaml
Sau đó, bạn có thể xóa cơ sở hạ tầng EKS bằng Terraform nếu không còn sử dụng để tiết kiệm chi phí.
Kết luận
Amazon S3 cung cấp một giải pháp lưu trữ có khả năng mở rộng và tiết kiệm chi phí cho các workload chạy trên EKS. Với driver Mountpoint cho S3 CSI, các pod Kubernetes có thể trực tiếp gắn các bucket S3 và phục vụ các tệp tĩnh một cách liền mạch. Mặc dù hiện tại chỉ giới hạn ở cấp phát tĩnh, nhưng sự tích hợp này là một cách mạnh mẽ để quản lý lưu trữ đối tượng trong các môi trường container hóa.