Terraform
← Tổng quan series

IaC và Terraform: bắt đầu từ vấn đề thật

Hiểu Infrastructure as Code, Terraform state và quy trình tạo một EC2 đầu tiên mà không phải click thủ công trong AWS Console.

Instructor walkthrough

Bài giảng: hiểu luồng trước khi chạy lệnh

Bài toán: Hiểu Infrastructure as Code, Terraform state và quy trình tạo một EC2 đầu tiên mà không phải click thủ công trong AWS Console.

01Chuẩn bịkiểm tra account, region, provider và chi phí
02Đọc planđối chiếu resource address, diff và dependency
03Thực hànhapply mutation nhỏ trong sandbox, lưu evidence
04Khôi phụcre-run, failure drill, destroy hoặc rollback
Command reference · baseline
terraform fmt
terraform init
terraform validate
terraform plan
terraform apply
terraform plan -destroy
terraform destroy

Mục tiêu của bài

Nếu hôm nay một người trong team nghỉ việc, người mới có thể dựng lại môi trường staging trong bao lâu? Nếu câu trả lời là “phải nhớ từng lần click trong AWS Console”, ta đang có một hạ tầng khó kiểm soát. Infrastructure as Code (IaC) giải quyết việc đó bằng cách biến hạ tầng thành code có thể review, version-control và chạy lại.

Terraform là công cụ IaC theo kiểu declarative: ta mô tả trạng thái mong muốn, Terraform tự tính các bước cần làm để đi từ trạng thái hiện tại đến trạng thái đó. Terraform dùng provider để giao tiếp với AWS, Azure, GCP và nhiều dịch vụ khác.

Luồng hoạt động cần nhớ

HCL -> terraform plan -> review -> terraform apply -> state

File terraform.tfstate là bản ghi Terraform dùng để biết resource trong code tương ứng với resource nào ngoài cloud. State không phải “log”, cũng không nên commit bừa vào Git vì nó có thể chứa thông tin nhạy cảm.

Terraform khác Ansible ở trọng tâm: Terraform tạo và quản lý hạ tầng, còn Ansible phù hợp hơn cho việc cấu hình máy chủ sau khi máy đã tồn tại. Một pipeline thực tế có thể là Terraform tạo network/EC2, Ansible cài Docker, sau đó Docker hoặc Kubernetes chạy ứng dụng.

Ví dụ đầu tiên: tạo EC2

Giả sử đã cài AWS CLI và cấu hình profile. Với tài khoản cá nhân, hãy dùng sandbox hoặc giới hạn quyền; EC2, EBS và Elastic IP có thể phát sinh phí.

aws configure
terraform version
mkdir terraform-hello && cd terraform-hello

Tạo main.tf:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

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

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

resource "aws_instance" "hello" {
  ami           = data.aws_ami.amazon_linux.id
  instance_type = "t3.micro"

  tags = { Name = "terraform-hello" }
}

data chỉ đọc dữ liệu đã có (ở đây là AMI mới nhất); resource là thứ Terraform sẽ tạo. Cú pháp aws_instance.hello là địa chỉ để Terraform theo dõi resource đó.

terraform fmt
terraform init
terraform validate
terraform plan
terraform apply
# Khi thử xong, xóa tài nguyên:
terraform destroy

Ở bước apply, hãy gõ yes sau khi đọc plan. -auto-approve tiện trong CI nhưng nguy hiểm khi chạy tay.

Cách tự kiểm chứng, không chỉ nhìn thấy “Apply complete!”

Sau apply, hãy lấy ID từ state và đối chiếu với AWS:

terraform state show aws_instance.hello
terraform output
aws ec2 describe-instances \
  --filters "Name=tag:Name,Values=terraform-hello" \
  --query 'Reservations[].Instances[].{Id:InstanceId,State:State.Name}'

Sau đó sửa tag Name, chạy plan và quan sát Terraform đề xuất ~ thay vì tạo thêm EC2. Đây là bài kiểm tra quan trọng: nếu mỗi lần chạy lại đều thấy +, cấu hình hoặc identity resource đang không ổn định.

Lab đạt chuẩn: expected state và failure drill

Tạo một thư mục lab riêng, đặt tag Training = terraform-00 và ghi lại account, region, profile, resource address và thời điểm bắt đầu. Trước apply, expected state là: một aws_instance.hello dùng AMI hợp lệ trong đúng region, instance type đúng, tag đúng và plan không có resource ngoài phạm vi bài. Nếu plan có destroy hoặc replace ngoài chủ ý, dừng lại và điều tra.

Thực hiện ba kiểm tra có chủ đích:

  1. Đổi chỉ tag Name, chạy plan và xác nhận một update in-place (~), không tạo instance thứ hai.
  2. Đổi region hoặc filter AMI trong một bản sao lab, quan sát lỗi data source/AMI rồi khôi phục; không apply bản cấu hình chưa có AMI hợp lệ.
  3. Chạy terraform plan lần nữa sau apply và đối chiếu No changes, sau đó kiểm tra AWS instance state theo tag. Nếu plan còn drift, ghi nguyên nhân thay vì đánh dấu pass.

Khi cleanup, chạy terraform plan -destroy trước terraform destroy, xác nhận chỉ resource có địa chỉ aws_instance.hello sẽ bị xóa và kiểm tra AWS không còn instance/EBS do lab tạo. Nếu dùng profile/account chung, dừng ở plan hoặc dùng sandbox; không dùng -auto-approve để bỏ qua review.

Troubleshooting nhanh

  • No valid credential sources: kiểm tra profile/role/region và credential chain; không chép access key vào .tf hoặc log.
  • Your query returned no results: kiểm tra region, owner và filter AMI; dùng aws ec2 describe-images read-only để xác minh.
  • Plan tạo thêm resource mỗi lần: kiểm tra resource address, provider alias, state/backend và thay đổi ngoài Terraform; không xóa state để “đồng bộ”.
  • Destroy bị kẹt: đọc dependency/error và refresh state; không dùng state rm như cách xóa resource ngoài cloud.

Không dùng terraform destroy trên account có resource khác nếu bạn chưa đọc plan. Thử thói quen plan -> review -> apply ngay từ bài đầu.

Checklist sau bài

  • Biết phân biệt resource, data, provider và state.
  • Đã chạy fmt, init, validate, plan trước apply.
  • Đã kiểm tra AWS Console và chạy terraform destroy.
  • Không commit .terraform/, *.tfstate hay credentials vào Git.
  • Đã ghi expected state và dừng khi plan có destroy/replace ngoài chủ ý.
  • Đã hoàn thành tag/AMI/drift failure drills và xác nhận plan no-op sau apply.
  • Đã chạy destroy plan, cleanup đúng resource và kiểm tra không còn tài nguyên lab.