Bỏ qua đến nội dung chính
TerraformIaCDevOpsinfrastructureautomation

Terraform Basics: Infrastructure As Code Cho Người Mới

Terraform basics: provider, resource, state, module. Code mẫu deploy AWS S3, Cloudflare DNS. State backend, drift detection, best practices 2026.

Xuất bản 8 phút đọc

Terraform basics là kỹ năng DevOps không thể thiếu — viết hạ tầng dạng code thay vì click Console. Bài này code đầy đủ deploy S3 + Cloudflare DNS, kèm best practices state management.

Infrastructure as Code — vì sao quan trọng?

Click Console: nhanh nhưng không reproducible. Server crash → setup lại 4 tiếng. Team mới khó onboard. Audit "ai đổi gì" không có.

Terraform: hạ tầng = file Git. Review qua PR. Rollback bằng git revert. Disaster recovery 30 phút. Đó là lý do mọi team production từ 5 người trở lên đều dùng IaC.

3 khái niệm cốt lõi

ObjectVai trò
ProviderPlugin nói chuyện với cloud (aws, google, cloudflare, kubernetes)
ResourceTài nguyên cloud cụ thể (S3 bucket, DNS record, VM)
StateJSON file lưu trạng thái thực tế cloud, mapping resource → real ID
ModuleBundle resource tái sử dụng
VariableInput có thể thay đổi (env, region, instance type)
OutputGiá trị export sau apply (URL, ARN)

Hello World: S3 bucket

# main.tf
terraform {
  required_version = ">= 1.6"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-southeast-1"
}

resource "aws_s3_bucket" "uploads" {
  bucket = "alodev-uploads"
  tags = {
    Project = "alodev"
    Env     = "production"
  }
}

resource "aws_s3_bucket_public_access_block" "uploads" {
  bucket = aws_s3_bucket.uploads.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

output "bucket_name" {
  value = aws_s3_bucket.uploads.id
}
terraform init        # tải provider, init backend
terraform plan        # xem thay đổi
terraform apply       # thực thi (gõ 'yes')
terraform destroy     # xoá toàn bộ (cẩn thận)

State backend remote

Local state (terraform.tfstate trong Git) — KHÔNG bao giờ. Lý do:

  • Chứa output secret (password, ARN) plain text
  • 2 dev apply cùng lúc → race, corrupt state
  • Mất file = mất khả năng manage hạ tầng

S3 backend chuẩn:

terraform {
  backend "s3" {
    bucket         = "alodev-tf-state"
    key            = "production/terraform.tfstate"
    region         = "ap-southeast-1"
    encrypt        = true
    dynamodb_table = "alodev-tf-locks"   # lock chống concurrent apply
  }
}

S3 versioning ON → recover state cũ khi cần. DynamoDB table có 1 attribute LockID (string) làm primary key.

Variable + tfvars

variable "env" {
  description = "Environment (dev, staging, production)"
  type        = string
  default     = "dev"
}

variable "instance_type" {
  type    = string
  default = "t3.small"
}

resource "aws_instance" "api" {
  ami           = "ami-0c..."
  instance_type = var.instance_type
  tags = { Env = var.env }
}
# production.tfvars
env           = "production"
instance_type = "t3.large"
terraform apply -var-file=production.tfvars

Module — tái sử dụng pattern

# modules/web-service/main.tf
variable "name" { type = string }
variable "image" { type = string }

resource "aws_ecs_service" "this" {
  name = var.name
  # ... 50 dòng config
}

output "url" {
  value = aws_lb.this.dns_name
}
# root main.tf — gọi module 2 lần
module "api" {
  source = "./modules/web-service"
  name   = "api"
  image  = "ghcr.io/alodev/api:v1.2.3"
}

module "worker" {
  source = "./modules/web-service"
  name   = "worker"
  image  = "ghcr.io/alodev/worker:v1.2.3"
}

Khi pattern thay đổi (e.g. thêm CloudWatch alarm), sửa module — cả api + worker auto cập nhật.

Multi-provider: AWS + Cloudflare

provider "cloudflare" {
  api_token = var.cloudflare_token
}

resource "aws_lb" "api" {
  name = "api-lb"
  # ...
}

resource "cloudflare_record" "api" {
  zone_id = var.cf_zone_id
  name    = "api"
  value   = aws_lb.api.dns_name
  type    = "CNAME"
  proxied = true
}

Terraform tạo LB AWS, lấy DNS name, tạo CNAME Cloudflare trỏ vào — tất cả trong 1 apply.

Workspace cho multi-env

terraform workspace new staging
terraform workspace new production
terraform workspace select production
terraform apply -var-file=production.tfvars

Mỗi workspace có state riêng — không nhầm staging vs prod. Hoặc dùng repo riêng cho mỗi env (an toàn hơn).

10 best practices

  • ✅ Pin version provider (~> 5.0) — không bị break khi major update
  • ✅ Remote state với encryption + locking
  • terraform fmt + tflint trong pre-commit
  • ✅ Plan trong PR, apply qua CI sau review
  • ✅ Tag mọi resource (Env, Project, Owner)
  • ✅ Đặt secret ngoài code — pass qua TF_VAR env
  • ✅ Drift detection cron hằng ngày
  • ✅ Module versioned (Git tag) cho production
  • terraform import resource đã tồn tại thay vì tạo mới
  • prevent_destroy cho production database

Kết luận

Terraform basics đủ cho 90% use case — provider, resource, state, module. Bắt đầu nhỏ với 1-2 resource quan trọng, mở rộng dần. Khi production lớn, đầu tư vào Atlantis hoặc Terraform Cloud cho workflow CI/CD chuẩn. Đọc CI/CD GitHub Actions để tự động plan + apply.

Zalo