Dependency Management trong Terragrunt
Trong bài trước, chúng ta đã tìm hiểu ba tính năng giúp Terragrunt loại bỏ phần lớn cấu hình lặp lại:
includegenerateread_terragrunt_config
Nhờ đó, repository trở nên sạch hơn và dễ bảo trì hơn.
Tuy nhiên, vẫn còn một bài toán rất lớn mà Infrastructure as Code phải giải quyết:
Làm sao biết project nào cần được triển khai trước?
Đây chính là lúc Dependency Management phát huy tác dụng.
Infrastructure luôn có dependency
Một hệ thống cloud không phải là tập hợp các resource độc lập.
Ví dụ:
VPC
↓
Subnets
↓
EKS
↓
Applications
Hay:
VPC
↓
Security Groups
↓
RDS
Hay:
Route53
↓
ACM Certificate
↓
ALB
↓
CloudFront
Mọi thứ đều phụ thuộc vào nhau.
Terraform có thể quản lý dependency bên trong một project.
Nhưng còn dependency giữa nhiều Terraform project thì sao?
Terraform chỉ nhìn thấy một project
Giả sử bạn chia infrastructure thành:
vpc/
eks/
rds/
redis/
Mỗi thư mục là một Terraform project riêng.
Terraform hoàn toàn không biết:
- EKS cần VPC
- RDS cần Security Group
- Redis cần Subnet
Đối với Terraform, đây chỉ là bốn project độc lập.
Nó sẽ không tự quyết định project nào cần chạy trước.
Giải pháp truyền thống
Thông thường, team sẽ có một tài liệu như:
Deployment Order
1. Network
2. IAM
3. VPC
4. Security Groups
5. RDS
6. Redis
7. EKS
8. Monitoring
9. Applications
Mỗi lần deploy:
Developer sẽ đọc tài liệu.
Sau đó chạy từng project.
Nếu quên một bước?
Toàn bộ deployment có thể thất bại.
Khi repository ngày càng lớn
Giả sử hệ thống có:
120 Terraform Projects
Dependency graph sẽ giống như:
Network
├── IAM
├── DNS
├── Monitoring
└── Shared Services
↓
Platform
↓
Applications
↓
Observability
↓
Data Platform
Không ai có thể nhớ hết.
Ngay cả người xây dựng hệ thống cũng khó có thể nhớ toàn bộ dependency sau vài tháng.
Repository cần có cách để tự mô tả mối quan hệ này.
Dependency trong Terragrunt
Terragrunt giới thiệu block:
dependencyÝ tưởng rất đơn giản:
Một project có thể khai báo rằng:
"Tôi phụ thuộc vào project khác."
Ví dụ:
EKS
↓
VPC
Terragrunt sẽ biết rằng:
VPC phải được xử lý trước.
Dependency không chỉ là thứ tự
Đây là điểm nhiều người mới dễ hiểu nhầm.
Dependency không chỉ giúp:
Run Before
Nó còn giúp chia sẻ:
Terraform Outputs
Ví dụ:
Project VPC sinh ra:
vpc_id
private_subnets
public_subnets
Project EKS cần toàn bộ thông tin này.
Thay vì nhập tay hoặc copy giá trị, Terragrunt sẽ tự lấy output từ project VPC.
Điều này giúp các project luôn đồng bộ với nhau.
Dependency Graph
Hãy tưởng tượng repository như sau:
VPC
↓
EKS
↓
Helm
↓
Applications
Terragrunt sẽ xây dựng một đồ thị:
VPC
↓
EKS
↓
Helm
↓
Applications
Đây gọi là Dependency Graph.
Terragrunt hiểu được:
- node nào chạy trước
- node nào chạy sau
- node nào có thể chạy song song
Toàn bộ quá trình được tính toán tự động.
run-all
Một trong những lệnh nổi tiếng nhất của Terragrunt là:
terragrunt run-all applyThoạt nhìn, có vẻ nó chỉ đơn giản là chạy mọi project.
Nhưng thực tế, Terragrunt sẽ:
- phân tích toàn bộ dependency
- xây dựng dependency graph
- sắp xếp thứ tự triển khai
- thực hiện deployment theo đúng trình tự
Ví dụ:
VPC
↓
EKS
↓
Applications
Terragrunt sẽ không bao giờ deploy Applications trước khi EKS hoàn tất.
Chạy song song khi có thể
Giả sử:
VPC
├── RDS
├── Redis
└── EKS
Ba project này chỉ phụ thuộc vào VPC.
Điều đó có nghĩa:
Sau khi VPC hoàn thành,
Terragrunt hoàn toàn có thể chạy:
RDS
Redis
EKS
cùng lúc.
Đây là một trong những lợi ích lớn nhất của Dependency Graph.
Repository lớn vẫn có thể deploy rất nhanh.
Outputs trở thành contract
Trong Terragrunt, output của Terraform không còn chỉ là dữ liệu.
Nó trở thành contract giữa các project.
Ví dụ:
Project Network cung cấp:
vpc_id
private_subnets
Project EKS sử dụng:
vpc_id
private_subnets
Nếu Network thay đổi implementation nhưng vẫn giữ nguyên outputs,
EKS hoàn toàn không cần sửa.
Đây là một nguyên tắc rất quen thuộc trong Software Engineering:
Phụ thuộc vào contract, không phụ thuộc vào implementation.
Tránh Circular Dependency
Một dependency graph hợp lệ phải luôn có dạng:
A
↓
B
↓
C
Không bao giờ nên là:
A
↓
B
↓
A
Hay:
A
↓
B
↓
C
↓
A
Đây gọi là Circular Dependency.
Terragrunt sẽ phát hiện những trường hợp này và dừng deployment.
Việc thiết kế dependency rõ ràng ngay từ đầu sẽ giúp repository ổn định hơn rất nhiều.
Dependency không thay thế Terraform
Một điểm cần phân biệt:
Terraform đã có dependency.
Ví dụ:
aws_subnet
↓
aws_instance
Đây là dependency bên trong cùng một Terraform project.
Terragrunt giải quyết bài toán khác.
Nó quản lý dependency giữa:
Project A
↓
Project B
↓
Project C
Hai cơ chế này bổ sung cho nhau chứ không thay thế nhau.
Một repository production thực sự
Khi nhìn vào một repository Terragrunt trưởng thành, bạn sẽ không chỉ thấy:
Folders
Mà còn thấy:
Infrastructure Graph
Mỗi project đều có vị trí rõ ràng.
Mỗi dependency đều được khai báo.
Mỗi output đều là contract.
Điều này giúp repository có thể mở rộng từ vài project lên hàng trăm project mà không cần thay đổi cách tổ chức.
Tổng kết
Dependency Management là một trong những lý do lớn nhất khiến Terragrunt trở thành lựa chọn phổ biến trong các hệ thống production.
Thay vì ghi nhớ:
- project nào chạy trước
- project nào lấy output từ đâu
- project nào có thể chạy song song
Terragrunt sẽ tự xây dựng dependency graph và điều phối toàn bộ quá trình triển khai.
Đó là bước tiến rất lớn so với việc quản lý nhiều Terraform project bằng tay.
Bài tiếp theo
Ở bài tiếp theo, chúng ta sẽ tìm hiểu cách Terragrunt quản lý Multi-environment và Multi-account, từ Development, Staging đến Production, đồng thời chia sẻ cấu hình giữa nhiều AWS Account mà vẫn giữ repository đơn giản và nhất quán.
