So sánh cách tiếp cận: IaC Pipeline truyền thống vs. Control Plane chuẩn Kubernetes-Native
Sáu tháng trước, đội ngũ platform engineering của chúng tôi đã gặp phải điểm nghẽn lớn với quy trình hạ tầng truyền thống. Giống như nhiều đơn vị khác, chúng tôi dựa vào Terraform được quản lý qua Jenkins và GitHub Actions. Các manifest ứng dụng được lưu trên Git và đồng bộ tới cụm Kubernetes thông qua Argo CD, nhưng các tài nguyên phụ thuộc trên cloud—như S3 bucket, cơ sở dữ liệu RDS và IAM role—lại bị tụt lại phía sau trong các CI job rời rạc.
Quản lý hạ tầng thông qua các CI pipeline hướng sự kiện (event-driven) hoạt động khá ổn cho đến khi phát sinh vấn đề. Vận hành một vòng lặp kiểm soát liên tục (continuous control loop) là một mô hình hoạt động hoàn toàn khác biệt:
- Mô hình thực thi (Execution Model): Terraform dựa trên việc thực thi tại từng thời điểm (point-in-time). Pipeline chạy lệnh
terraform planvàapplykhi merge pull request. Nếu một kỹ sư mở rộng security group trực tiếp trên AWS console mười phút sau đó, sự sai lệch cấu hình (drift) đó sẽ không bị phát hiện cho đến lần deploy tiếp theo. Ngược lại, Crossplane hoạt động liên tục. Được xây dựng dựa trên Kubernetes Custom Resource Definitions (CRDs) và các controller, nó thăm dò (poll) API của cloud provider mỗi 60 giây để tự động kéo hạ tầng thực tế về đúng trạng thái đã khai báo trên Git. - Tính đồng nhất về API và quyền truy cập: Mô hình truyền thống buộc các lập trình viên phải xoay xở giữa cú pháp HCL, cloud CLI và AWS IAM role song song với Kubernetes manifest. Crossplane hợp nhất tất cả theo chuẩn Kubernetes API. Một instance Amazon RDS hay S3 bucket giờ đây vận hành tương tự như một
DeploymenthoặcServicenguyên bản. - Tích hợp GitOps: Việc chạy Terraform qua Argo CD hoặc Flux đòi hỏi các script bọc (wrapper) cồng kềnh và các runner pod như
tf-controller. Crossplane loại bỏ hoàn toàn lớp trung gian này. Vì tài nguyên cloud là các Kubernetes manifest tiêu chuẩn, GitOps engine của bạn có thể theo dõi, so sánh khác biệt (diff) và đồng bộ hạ tầng cloud thông qua quy trình review PR sẵn có. - Quản lý Secret: Việc chuyển output từ Terraform vào các pod thường đòi hỏi các công cụ kết nối tùy biến: job đồng bộ từ Vault, operator của AWS Secrets Manager hoặc bash script. Crossplane xử lý việc này trực tiếp. Nó tự động ghi các endpoint, username và thông tin xác thực vừa tạo vào các đối tượng
Secretnguyên bản của Kubernetes, sẵn sàng để các pod tiêu thụ ngay lập tức.
Ưu và nhược điểm sau 6 tháng chạy Production
Việc di chuyển hạ tầng sang Kubernetes đã giúp rút ngắn thời gian khởi tạo database từ 45 phút xuống dưới 3 phút cho toàn bộ đội ngũ kỹ thuật gồm 35 thành viên. Giờ đây, các lập trình viên có thể yêu cầu cấp phát hạ tầng chỉ bằng một pull request ngắn gọn 15 dòng thay vì phải tạo ticket hỗ trợ. Dẫu vậy, việc biến Kubernetes thành một control plane quản lý hạ tầng cũng đi kèm với những đánh đổi rõ ràng. Dưới đây là những bài học thực tế chúng tôi rút ra sau sáu tháng vận hành lưu lượng production.
Ưu điểm
- Tự động sửa lỗi sai lệch cấu hình (Automated Drift Correction): Crossplane truy vấn cloud API mỗi phút một lần. Gần đây, khi một kỹ sư chỉnh sửa trực tiếp parameter group của RDS trên AWS console để xử lý sự cố, Crossplane đã phát hiện ra sự khác biệt trong vòng 60 giây và tự động khôi phục về trạng thái chuẩn trên Git.
- Tùy biến API Self-Service: Composite Resource Definitions (XRDs) cho phép các kỹ sư senior đóng gói các kiến trúc phức tạp thành những bản trừu tượng hóa tinh gọn. Chúng tôi đã gom VPC, private subnet, security group và cụm Aurora vào một CRD có tên
AppDatabase. Nhờ đó, các product team có thể tự cấu hình dung lượng lưu trữ và phiên bản database engine mà không cần can thiệp vào tầng networking phức tạp bên dưới. - Hợp nhất RBAC và Policy Guard: Thay vì phải quản lý phân quyền riêng biệt trên 12 tài khoản AWS, đội ngũ bảo mật của chúng tôi thiết lập quyền truy cập bằng Kubernetes RBAC. Các policy của Kyverno kiểm tra tính hợp lệ của thông số hạ tầng ngay khi submit, từ chối các ổ lưu trữ chưa mã hóa hoặc endpoint công khai trước khi Crossplane kịp gọi lệnh tới AWS.
Thách thức
- Mức tiêu tốn bộ nhớ cao: Các provider xây dựng trên Upjet phải nạp toàn bộ schema của hàng trăm cloud API. Khi chúng tôi triển khai toàn bộ bộ
provider-awsban đầu, controller của nó đã ngốn tới 3.4 GB RAM. Việc sử dụng các scoped provider giúp giảm tải đáng kể, nhưng các controller vẫn đòi hỏi dung lượng node riêng biệt. - Khó khăn hơn trong việc khắc phục sự cố (Troubleshooting): Khi quá trình khởi tạo thất bại do sai cấu hình IAM, bạn sẽ không nhận được một bản diff rõ ràng trên terminal. Lỗi thường ẩn sâu trong các event của
kubectl describe, khối status của tài nguyên hoặc log của provider controller. Các lập trình viên vốn quen thuộc với output trực quan của Terraform plan sẽ cần thời gian để thích nghi. - Nguy cơ khi xóa Namespace: Lệnh
kubectl delete namespacesẽ xóa theo dạng cascade tất cả tài nguyên được quản lý bên trong nó. Nếu không có biện pháp phòng ngừa, Crossplane sẽ xóa sạch các database production và bucket tương ứng trên AWS. Bạn bắt buộc phải cấu hìnhdeletionPolicy: Orphancho các tài nguyên quan trọng và thực thi nghiêm ngặt qua admission webhook.
Kiến trúc khuyến nghị cho môi trường Production
Việc chạy các controller của Crossplane chung với workload của người dùng sẽ dễ dẫn đến vấn đề tranh chấp tài nguyên (noisy neighbor) và mở rộng bán kính ảnh hưởng khi gặp sự cố bảo mật (blast radius). Hãy tuân thủ bốn nguyên tắc production sau:
- Cụm Management chuyên dụng: Chạy Crossplane trong một cụm control plane cô lập, gọn nhẹ (chúng tôi dùng 3 node
t4g.large). Cụm này đảm nhiệm Crossplane, Argo CD và các secrets operator, đóng vai trò trung tâm điều phối tài nguyên cloud trên khắp các tài khoản staging và production từ một đầu mối an toàn duy nhất. - Sử dụng Scoped Provider chi tiết: Hãy bỏ qua các gói provider nguyên khối (monolithic). Việc triển khai các module chuyên biệt như
provider-aws-s3vàprovider-aws-rdsđã giúp cụm của chúng tôi giảm số lượng CRD từ hơn 900 xuống còn 68, giúp giảm khoảng 60% lượng RAM sử dụng của API server. - Xác thực qua Workload Identity: Tuyệt đối không lưu trữ thông tin xác thực cloud dài hạn bên trong secret của cụm. Hãy sử dụng AWS IAM Roles for Service Accounts (IRSA) hoặc GCP Workload Identity. Các pod sẽ trao đổi token OIDC ngắn hạn để lấy quyền truy cập cloud tạm thời và được xoay vòng tự động.
- Áp dụng Orphan Deletion Policy: Thiết lập
spec.deletionPolicy: Orphantrên các database production, VPC và storage bucket. Nếu ai đó vô tình xóa manifest trên Kubernetes, tài nguyên cloud cơ sở vẫn sẽ được giữ nguyên an toàn trên AWS cho đến khi có sự can thiệp thủ công.
Hướng dẫn triển khai: Cấp phát tài nguyên Cloud với Crossplane
Phần hướng dẫn này sẽ thiết lập Crossplane trên cụm Kubernetes, cấu hình AWS S3 provider theo dạng module bằng IRSA và cấp phát một S3 bucket thông qua GitOps.
Bước 1: Cài đặt Crossplane qua Helm
Thêm repository chart chính thức của Crossplane và cài đặt các controller cốt lõi vào một namespace chuyên dụng:
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set args='{"--enable-composition-functions=true"}'
Kiểm tra đảm bảo cả controller cốt lõi và pod quản lý RBAC đều đã ở trạng thái Running:
kubectl get pods -n crossplane-system
Bước 2: Cài đặt Scoped AWS S3 Provider
Triển khai module S3 provider để quản lý các bucket mà không cần nạp các dịch vụ AWS không cần thiết vào bộ nhớ:
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.3.0
EOF
Chờ cho đến khi cả hai cột INSTALLED và HEALTHY đều hiển thị True:
kubectl get provider provider-aws-s3 -w
Bước 3: Cấu hình xác thực Cloud thông qua ProviderConfig
Sau khi annotate ServiceAccount của provider với IAM Role ARN trên AWS qua IRSA, tạo một ProviderConfig để kích hoạt xác thực cho pod:
cat <<EOF | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-provider-config
spec:
credentials:
source: InjectedIdentity
EOF
Bước 4: Cấp phát S3 Bucket thông qua Managed Resource
Khai báo S3 bucket dưới dạng một manifest nguyên bản của Kubernetes:
cat <<EOF | kubectl apply -f -
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: app-analytics-production-data-2026
labels:
environment: production
managed-by: crossplane
spec:
forProvider:
region: us-east-1
deletionPolicy: Orphan
providerConfigRef:
name: aws-provider-config
EOF
Bước 5: Xác minh đồng bộ và phát hiện Drift
Kiểm tra trạng thái của managed resource bằng kubectl:
kubectl get bucket app-analytics-production-data-2026
Quan sát kết quả để kiểm tra hai chỉ số trạng thái quan trọng:
- READY: Chuyển sang
Truesau khi AWS hoàn tất việc khởi tạo bucket. - SYNCED: Chuyển sang
Truekhi vòng lặp đối soát (reconciliation loop) của Crossplane đồng bộ thành công giữa bucket thực tế trên AWS với khai báo YAML của bạn.
Để xem log đối soát chi tiết hoặc kiểm tra lỗi phân quyền IAM, hãy chạy:
kubectl describe bucket app-analytics-production-data-2026
Hãy tự mình kiểm tra khả năng tự phục hồi sai lệch (drift reconciliation). Đăng nhập vào AWS console và thêm một tag hoặc sửa đổi bucket policy theo cách thủ công. Trong vòng 60 giây, Crossplane sẽ phát hiện sự sai lệch và khôi phục lại các thông số chính xác như đã khai báo trong manifest của bạn. Giờ đây, hạ tầng cloud đã hoàn toàn tuân theo vòng đời GitOps tương tự như các đợt triển khai ứng dụng của bạn.

