Thiết kế Terraform Repository cho Production
Hướng dẫn cách tổ chức Terraform repository theo chuẩn production để dễ mở rộng, dễ review và quản lý nhiều môi trường như dev, staging và production.

Thiết kế Terraform Repository cho Production
Ở các bài trước, chúng ta đã tìm hiểu:
- Terraform hoạt động như thế nào
- Terraform State
- Terraform Modules
- Provider
- Data Sources
- Những tính năng Terraform sử dụng hằng ngày
Đến đây, chúng ta đã có đủ kiến thức để viết Terraform.
Nhưng khi bắt đầu áp dụng vào production, sẽ xuất hiện một vấn đề khác.
Không còn là viết được Terraform nữa.
Mà là...
Làm thế nào để hàng chục, hàng trăm file Terraform vẫn dễ quản lý sau nhiều năm?
Đây là lúc cách tổ chức repository trở nên quan trọng hơn cả syntax.
Dự án nhỏ thì cấu trúc nào cũng được
Rất nhiều tutorial bắt đầu với cấu trúc như sau:
terraform/
main.tf
variables.tf
outputs.tf
provider.tf
versions.tf
Hoặc:
terraform/
network.tf
compute.tf
database.tf
iam.tf
Đối với demo thì hoàn toàn ổn.
Nhưng production thì khác.
Sau vài tháng sẽ có thêm:
- VPC
- IAM
- ECS
- RDS
- S3
- CloudFront
- Route53
- Lambda
- EventBridge
- Monitoring
- Secrets
- ...
Một thư mục có hàng chục file .tf.
Lúc này việc tìm một resource cũng trở nên khó khăn.
Sai lầm phổ biến
Rất nhiều team tổ chức repository theo service.
Ví dụ:
terraform/
ec2/
rds/
s3/
iam/
route53/
Thoạt nhìn có vẻ hợp lý.
Nhưng thực tế Terraform không hoạt động theo thư mục.
Terraform hoạt động theo state.
Nếu tất cả đều nằm trong cùng một state thì việc chia thư mục gần như chỉ mang tính hình thức.
Ngược lại, nếu mỗi thư mục là một state riêng thì dependency giữa chúng sẽ nhanh chóng trở nên phức tạp.
Hãy nghĩ theo Environment trước
Production thường có nhiều môi trường:
Development
Staging
Production
Mỗi môi trường sẽ có:
- tài nguyên riêng
- state riêng
- pipeline riêng
- quyền truy cập riêng
Do đó điều đầu tiên nên tách là:
live/
dev/
staging/
production/
Đây cũng là cách nhiều tổ chức lớn quản lý Infrastructure.
Tiếp theo là chia theo Infrastructure
Ví dụ:
live/
production/
network/
compute/
database/
monitoring/
Mỗi thư mục đại diện cho một stack.
Ví dụ:
network
sẽ quản lý
- VPC
- Subnets
- NAT Gateway
- Internet Gateway
Trong khi
database
chỉ quản lý
- RDS
- Parameter Groups
- Subnet Groups
Như vậy mỗi stack sẽ có state riêng.
Modules không nên nằm trong live
Một sai lầm phổ biến khác.
live/
production/
modules/
vpc/
ecs/
Thực tế:
Modules là code có thể tái sử dụng.
Environment chỉ là nơi sử dụng module.
Do đó nên tách riêng.
repository/
modules/
vpc/
ecs/
rds/
live/
dev/
production/
Khi đó:
live
chỉ chứa configuration.
Còn
modules
chứa implementation.
Repository chuẩn thường trông như thế nào?
terraform/
modules/
vpc/
ecs/
rds/
iam/
s3/
live/
dev/
network/
compute/
database/
production/
network/
compute/
database/
Đây là layout phổ biến của rất nhiều repository Terraform production.
Bạn sẽ thấy cấu trúc này xuất hiện trong rất nhiều dự án Open Source.
Một Environment chỉ nên chứa rất ít code
Ví dụ:
live/production/network/main.tf
không nên dài hàng nghìn dòng.
Thay vào đó chỉ gọi module.
module "network" {
source = "../../../modules/vpc"
cidr = "10.0.0.0/16"
environment = "production"
}Đó gần như là tất cả.
Logic thực sự nằm trong:
modules/vpc
Điều này giúp:
- code tái sử dụng
- review dễ hơn
- update ít rủi ro hơn
Variables nên nằm ở đâu?
Thông thường:
modules/
variables.tf
outputs.tf
main.tf
Còn environment sẽ truyền giá trị.
Ví dụ:
module "database" {
instance_class = "db.t4g.medium"
allocated_storage = 100
backup_retention_period = 30
}
Không hard-code bên trong module.
Module càng generic thì càng tái sử dụng được.
Một state hay nhiều state?
Đây là câu hỏi rất phổ biến.
Nhiều người mới học thường để toàn bộ infrastructure trong một state.
Everything
↓
terraform.tfstate
Điều này sẽ dẫn tới:
- Plan rất lâu
- Apply lâu
- Lock toàn bộ infrastructure
- Chỉ một thay đổi nhỏ cũng phải đọc toàn bộ state
Production thường chia thành nhiều state.
Ví dụ:
network
↓
compute
↓
database
↓
monitoring
Mỗi stack apply độc lập.
Nếu deploy ECS thì không cần lock cả VPC.
Đừng để Production phụ thuộc vào Local
Có những repository vẫn để:
terraform.tfstate
ngay trong Git repository.
Đây là điều không nên.
Production nên dùng:
- Terraform Cloud
- S3 Backend
- Azure Storage
- GCS
Remote Backend giúp:
- Lock State
- Version History
- Team Collaboration
- Backup
- Security
State là tài sản quan trọng nhất của Terraform.
Đừng lưu nó trên máy cá nhân.
Naming Convention rất quan trọng
Ví dụ:
modules/
aws-vpc
aws-rds
aws-ecs
hoặc
modules/
network
database
compute
Quan trọng nhất là consistency.
Không nên:
vpc/
ecs/
RDS/
S3Module/
networking/
Một repository nên có một quy tắc đặt tên duy nhất.
Repository sẽ còn phát triển
Khi infrastructure lớn hơn, repository sẽ tiếp tục có thêm:
- CI/CD
- Policy Check
- Security Scan
- Cost Estimation
- Drift Detection
- Documentation
Nếu ngay từ đầu repository được tổ chức tốt thì việc mở rộng sau này sẽ rất đơn giản.
Một ví dụ thực tế
Repository Terraform mình đang sử dụng hiện nay có cấu trúc gần như sau:
terraform/
modules/
aws/
vercel/
cloudflare/
supabase/
live/
dev/
aws/
ap-southeast-1/
blog/
production/
aws/
ap-southeast-1/
blog/
shared/
Mỗi provider có module riêng.
Mỗi môi trường có state riêng.
Mỗi workload có configuration riêng.
Nhờ vậy việc review Pull Request hay rollback đều đơn giản hơn rất nhiều.
Những điều mình rút ra
Sau nhiều dự án, mình nhận ra:
- Repository structure quan trọng không kém Terraform code.
- Module nên chứa logic, environment chỉ chứa configuration.
- Tách state theo stack sẽ giúp giảm rủi ro khi deploy.
- Luôn dùng Remote Backend cho production.
- Đừng tối ưu cho hôm nay, hãy tối ưu cho repository sau 2 năm nữa.
Terraform rất dễ bắt đầu.
Nhưng để repository vẫn gọn gàng sau hàng nghìn lần commit mới là điều khó.
Tổng kết
Terraform không chỉ là viết file .tf.
Một repository được thiết kế tốt sẽ giúp:
- dễ review
- dễ mở rộng
- giảm xung đột khi làm việc nhóm
- giảm thời gian deploy
- dễ bảo trì trong nhiều năm
Đây là nền tảng để một hệ thống Infrastructure có thể phát triển bền vững.
Bài tiếp theo
Cho đến lúc này, chúng ta đều giả sử rằng toàn bộ Infrastructure đều được Terraform tạo ra ngay từ đầu.
Nhưng trong thực tế, rất nhiều công ty đã có sẵn hàng trăm tài nguyên trên AWS, Azure hay GCP trước khi quyết định sử dụng Terraform.
Vậy làm thế nào để đưa những tài nguyên đang tồn tại đó vào Terraform mà không phải xóa và tạo lại?
Chúng ta sẽ cùng tìm hiểu trong bài tiếp theo:
Import Infrastructure có sẵn vào Terraform.
Tiếp tục series
Bình luận
Đang tải bình luận…