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.
terraform fmt
terraform init
terraform validate
terraform plan
terraform apply
terraform plan -destroy
terraform destroyMụ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:
- Đổi chỉ tag
Name, chạy plan và xác nhận một update in-place (~), không tạo instance thứ hai. - Đổ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ệ.
- Chạy
terraform planlần nữa sau apply và đối chiếuNo 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.tfhoặc log.Your query returned no results: kiểm tra region, owner và filter AMI; dùngaws ec2 describe-imagesread-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 rmnhư cách xóa resource ngoài cloud.
Không dùng
terraform destroytrên account có resource khác nếu bạn chưa đọc plan. Thử thói quenplan -> review -> applyngay từ bài đầu.
Checklist sau bài
- Biết phân biệt
resource,data, provider và state. - Đã chạy
fmt,init,validate,plantrướcapply. - Đã kiểm tra AWS Console và chạy
terraform destroy. - Không commit
.terraform/,*.tfstatehay 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.