Mục lục
- Resource Cloud Đầu Tiên Của Bạn
- 📦 Code Examples
- Bạn Sẽ Build Cái Gì
- Trước Khi Bắt Đầu
- File Configuration Đầu Tiên
- Initialize Terraform
- Preview Changes với terraform plan
- Common Errors (Bạn Sẽ Gặp Một Trong Số Này)
- Apply Changes (Thực Sự Tạo Instance)
- Chuyện Gì Vừa Xảy Ra?
- State File (terraform.tfstate)
- Hiểu Plan vs Apply
- Making Changes to Resources
- Khi Resources Bị Replaced
- Cleaning Up: Destroy Resources
- Thêm Vài Lỗi Bạn Có Thể Gặp
- Test Yourself
- Bạn Vừa Học Được Gì
- Tiếp Theo: HCL Fundamentals
- Troubleshooting: SSH Access
- Additional Resources
Resource Cloud Đầu Tiên Của Bạn
Giờ thì dừng đọc lại và bắt đầu phá đồ thôi.
Bạn đã vượt qua phần lý thuyết (Part 1) và sống sót qua phần setup (Part 2) rồi đó. Giờ mình sẽ tạo thứ gì đó thật sự: một EC2 instance thực tế trên AWS bằng Terraform.
Đây là lúc bạn sẽ hiểu. Hoặc là lúc bạn nhận ra mình ghét declarative infrastructure. Dù sao thì bạn cũng sẽ biết thôi.
📦 Code Examples
Repository: terraform-hcl-tutorial-series Phần Này: Part 3 - First Resource Example
Lấy ví dụ hoạt động:
git clone https://github.com/khuongdo/terraform-hcl-tutorial-series.git
cd terraform-hcl-tutorial-series
git checkout part-03
cd examples/part-03-first-resource/
# Initialize and deploy
terraform init
terraform plan
terraform apply
# Clean up when done
terraform destroy
Bạn Sẽ Build Cái Gì
Đến cuối tutorial này, bạn sẽ deploy được một EC2 instance lên AWS, hiểu cách Terraform track những gì nó tạo ra, và (hy vọng là) destroy nó đi để khỏi bị bill. Trong quá trình đó, bạn sẽ gặp ít nhất một lỗi, mà điều đó tốt đó—debugging dạy bạn nhiều hơn là success.
Cảnh báo về chi phí: Mình dùng t2.micro instances, thuộc free-tier. Nếu bạn destroy resources khi xong, thì cost là $0. Nếu bạn quên và để nó chạy? Khoảng $10/tháng. Nhớ đặt lịch nhắc nhở nhé.
Trước Khi Bắt Đầu
Đảm bảo bạn hoàn thành Part 2 rồi. Nghiêm túc đó. Nếu những command này fail, quay lại fix setup trước:
# Terraform installed?
terraform --version
# Should show v1.6+
# AWS credentials configured?
aws sts get-caller-identity
# Should show your account info
# Working directory ready?
mkdir -p ~/terraform-tutorial/part-03
cd ~/terraform-tutorial/part-03
Nếu có gì lỗi, đừng tiếp tục. Bạn chỉ lãng phí thời gian debug sai chỗ thôi.
File Configuration Đầu Tiên
Tạo file tên main.tf:
# Provider configuration
provider "aws" {
region = "us-east-1"
}
# EC2 instance resource
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "MyFirstTerraformInstance"
Environment = "tutorial"
ManagedBy = "terraform"
}
}
Giải thích từng phần nè:
provider "aws" báo cho Terraform biết là mình dùng AWS ở region us-east-1. Đơn giản vậy thôi.
resource "aws_instance" "web" khai báo một EC2 instance. Format là resource "<type>" "<local_name>". Type (aws_instance) đến từ AWS provider. Local name (web) là tùy bạn đặt—nó chỉ là cách bạn reference resource này trong code.
ami là Amazon Machine Image—về cơ bản là operating system bạn muốn. Cái này là Ubuntu 20.04. AMI IDs khác nhau theo region, nên nếu bạn không ở us-east-1, sẽ phải đổi. Mình sẽ gặp lỗi đó trong chốc lát.
instance_type là kích thước. t2.micro = 1 vCPU, 1 GB RAM, free-tier eligible. Đủ cho tutorial rồi.
tags là metadata. Luôn luôn tag resources nhé. Tag ManagedBy = "terraform" giúp bạn sau này khi cố tìm xem cái nào safe để delete.
Initialize Terraform
Trước khi Terraform làm gì được, nó cần download AWS provider plugin:
terraform init
Bạn sẽ thấy output kiểu này:
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v5.31.0...
- Installed hashicorp/aws v5.31.0 (signed by HashiCorp)
Terraform has been successfully initialized!
Chuyện gì vừa xảy ra? Terraform đọc file main.tf, thấy bạn dùng AWS, và download AWS provider plugin (khoảng 500 MB đó). Nó cũng tạo một thư mục .terraform/ và file .terraform.lock.hcl để lock phiên bản provider.
Bạn chỉ chạy terraform init một lần mỗi project, hoặc khi thêm providers mới.
Preview Changes với terraform plan
Đây là thói quen quan trọng nhất bạn sẽ có: luôn chạy terraform plan trước terraform apply.
terraform plan
Output:
Terraform will perform the following actions:
# aws_instance.web will be created
+ resource "aws_instance" "web" {
+ ami = "ami-0c55b159cbfafe1f0"
+ instance_type = "t2.micro"
+ id = (known after apply)
+ public_ip = (known after apply)
+ private_ip = (known after apply)
...
+ tags = {
+ "Environment" = "tutorial"
+ "ManagedBy" = "terraform"
+ "Name" = "MyFirstTerraformInstance"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Đây là Terraform đang nói "mình sẽ làm những thứ này đây." Dấu + nghĩa là nó sẽ tạo thứ gì đó. (known after apply) là các giá trị sẽ không tồn tại cho đến khi AWS thực sự tạo instance.
Đọc plan output là một kỹ năng đó. Ở production, một dòng bỏ lỡ có thể xóa database của bạn. Quen với việc đọc kỹ từ giờ nhé.
Common Errors (Bạn Sẽ Gặp Một Trong Số Này)
Error: "No valid credential sources found"
Error: No valid credential sources found for AWS Provider
Fix: Chạy aws configure và nhập access keys.
Error: "AMI not found"
Error: creating EC2 Instance: InvalidAMIID.NotFound
Fix: AMI IDs khác nhau theo region. AMI trong ví dụ là cho us-east-1. Nếu bạn dùng region khác, tìm AMI của bạn ở Ubuntu Cloud Images và update giá trị ami trong main.tf.
Error: "Insufficient IAM permissions"
Error: creating EC2 Instance: UnauthorizedOperation
Fix: AWS user của bạn cần EC2 permissions. Nếu bạn dùng personal account, cứ cho mình admin access luôn. Nếu đang ở company account, hỏi admin xin policy AmazonEC2FullAccess.
Apply Changes (Thực Sự Tạo Instance)
Khi plan trông ok rồi, apply nó:
terraform apply
Terraform hiển thị plan lại một lần nữa và hỏi xác nhận:
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
Gõ yes (không phải y, phải gõ full word):
aws_instance.web: Creating...
aws_instance.web: Still creating... [10s elapsed]
aws_instance.web: Still creating... [20s elapsed]
aws_instance.web: Creation complete after 32s [id=i-0abc123def456789]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Xin chúc mừng. Bạn vừa tạo cloud infrastructure bằng code đó.
Vào check AWS Console đi. EC2 → Instances. Instance của bạn đó, có tag "MyFirstTerraformInstance," đang chạy thật.
Chuyện Gì Vừa Xảy Ra?
Khi bạn chạy terraform apply, đây là những gì Terraform làm:
- Build dependency graph (trong trường hợp này chỉ một resource, nên không exciting lắm)
- Gọi AWS API calls (
ec2:RunInstances) với parameters của bạn - Đợi AWS provision instance
- Ghi lại mọi thứ trong file tên
terraform.tfstate - Đưa bạn instance ID
File state đó rất quan trọng. Nói về nó nào.
State File (terraform.tfstate)
Sau khi apply, bạn sẽ thấy file mới:
ls -la
# .terraform/
# .terraform.lock.hcl
# main.tf
# terraform.tfstate <-- Cái này mới
Mở terraform.tfstate. Nó là JSON. Trông kiểu này:
{
"version": 4,
"terraform_version": "1.6.0",
"resources": [
{
"type": "aws_instance",
"name": "web",
"instances": [
{
"attributes": {
"id": "i-0abc123def456789",
"ami": "ami-0c55b159cbfafe1f0",
"instance_type": "t2.micro",
"public_ip": "54.123.45.67",
...
}
}
]
}
]
}
Đây là bộ nhớ của Terraform. Nó map aws_instance.web trong code của bạn với i-0abc123def456789 trong AWS. Không có file này, Terraform sẽ không biết nó đã tạo gì, cái gì cần update, hoặc cái gì có thể safely destroy.
Đừng bao giờ edit file này manually. Coi nó như database. Dùng Terraform commands để tương tác với nó, không phải text editor.
Ở production, bạn sẽ store state remotely (S3, Terraform Cloud, v.v.), nhưng bây giờ local file ổn rồi.
Hiểu Plan vs Apply
Workflow của Terraform là hai bước: plan rồi apply. Đây là chủ ý.
terraform plan là read-only. Nó query AWS để xem cái gì tồn tại, compare với configuration của bạn, và show cái gì sẽ thay đổi. Chạy lúc nào cũng an toàn. Không có gì bị modify.
Nghĩ về nó như git diff trước khi commit.
terraform apply thực sự làm changes. Nó gọi AWS APIs. Nó creates, updates, và deletes resources. Nó tốn tiền.
Nghĩ về nó như git push lên production.
Quy tắc vàng: luôn chạy plan trước apply. Luôn đọc output. Đừng bao giờ gõ yes một cách phản xạ.
Một resource bị destroy nhầm có thể tốn hàng giờ recovery. Hoặc tệ hơn, mất data.
Making Changes to Resources
Thử modify instance nhé. Update main.tf để thêm tag:
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "MyFirstTerraformInstance"
Environment = "tutorial"
ManagedBy = "terraform"
Owner = "YourName" # <-- Thêm cái này
}
}
Chạy plan:
terraform plan
Output:
Terraform will perform the following actions:
# aws_instance.web will be updated in-place
~ resource "aws_instance" "web" {
id = "i-0abc123def456789"
~ tags = {
+ "Owner" = "YourName"
# (3 unchanged elements hidden)
}
# (20 unchanged attributes hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
Để ý dấu ~ nè. Nghĩa là "update in-place." Terraform có thể thêm tags mà không cần recreate instance. Không downtime.
Apply nó:
terraform apply
# Type: yes
# Output:
# aws_instance.web: Modifying... [id=i-0abc123def456789]
# aws_instance.web: Modifications complete after 2s
Xong rồi. Tags đã update, instance vẫn đang chạy. Đây là sức mạnh của declarative infrastructure—bạn nói bạn muốn gì, Terraform tìm ra minimal changes cần thiết.
Khi Resources Bị Replaced
Một số changes không thể made in-place. Chúng cần destroy resource cũ và tạo cái mới.
Thử đổi AMI (đừng apply thật nha, chỉ xem plan thôi):
resource "aws_instance" "web" {
ami = "ami-0xyz987new654321" # Changed
instance_type = "t2.micro"
...
}
Chạy plan:
terraform plan
Terraform will perform the following actions:
# aws_instance.web must be replaced
-/+ resource "aws_instance" "web" {
~ ami = "ami-0c55b159cbfafe1f0" -> "ami-0xyz987new654321" # forces replacement
~ id = "i-0abc123def456789" -> (known after apply)
...
}
Plan: 1 to add, 0 to change, 1 to destroy.
Thấy forces replacement không? AWS không thể change AMI của instance sau khi nó được launched. Terraform phải destroy instance cũ và tạo cái mới.
Đừng apply change này. Revert AMI về giá trị ban đầu. Mình sẽ cover resource replacement chi tiết ở Part 6.
Cleaning Up: Destroy Resources
Khi thử nghiệm xong, destroy instance để tránh charges:
terraform destroy
Output:
Terraform will perform the following actions:
# aws_instance.web will be destroyed
- resource "aws_instance" "web" {
- ami = "ami-0c55b159cbfafe1f0" -> null
- id = "i-0abc123def456789" -> null
...
}
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value:
Gõ yes:
aws_instance.web: Destroying... [id=i-0abc123def456789]
aws_instance.web: Still destroying... [10s elapsed]
aws_instance.web: Destruction complete after 32s
Destroy complete! Resources: 1 destroyed.
Check AWS Console. Instance state: "Terminated."
State file của bạn vẫn tồn tại (nó track history), nhưng resources đã mất rồi.
Thêm Vài Lỗi Bạn Có Thể Gặp
Error: "Resource already exists"
Cái này xảy ra nếu bạn manually tạo instance, rồi cố chạy terraform apply. Terraform không biết về manually created resources. Hoặc xóa manual instance hoặc import nó vào Terraform state (mình sẽ cover imports ở Part 9).
Error: "State file locked"
Error: Error acquiring the state lock
Đây là cơ chế an toàn của Terraform. Nếu bạn nhấn Ctrl+C trong lúc apply, Terraform lock state để tránh corruption. Đợi 2 phút hoặc force unlock:
terraform force-unlock <lock-id-from-error>
Chỉ force unlock nếu bạn chắc chắn không có Terraform process nào khác đang chạy.
Error: "Provider version mismatch"
Error: Provider version constraint not met
Ai đó dùng provider version mới hơn. Fix nó:
terraform init -upgrade
Test Yourself
Trước khi chuyển sang Part 4, đảm bảo bạn trả lời được:
terraform planlàm gì?terraform.tfstatelà gì và tại sao nó quan trọng?- Khác biệt giữa in-place update và resource replacement là gì?
- Command nào destroy tất cả Terraform-managed resources?
- Dấu
+trong plan output nghĩa là gì?
Nếu bạn không trả lời được, đọc lại phần liên quan. Những khái niệm này là nền tảng đó.
Bạn Vừa Học Được Gì
Bạn đã deploy cloud infrastructure bằng code. Đó là giá trị cơ bản của Terraform.
Bạn cũng học được workflow: viết code, chạy plan để preview, chạy apply để execute, chạy destroy để clean up. Pattern này scale từ một EC2 instance đến hàng nghìn resources trên nhiều clouds.
Và bạn có lẽ đã gặp lỗi rồi. Tốt đó. Debugging dạy bạn cách mọi thứ thực sự hoạt động. Documentation chỉ dạy happy path thôi.
Tiếp Theo: HCL Fundamentals
Ở Part 4, mình sẽ đi sâu vào HashiCorp Configuration Language. Variables, outputs, data types, functions, conditionals, loops—tất cả tools bạn cần để viết flexible, reusable Terraform configurations.
Hiện tại, main.tf của bạn đang hardcoded. Part 4 dạy bạn cách làm nó dynamic.
Sẵn sàng chưa? Continue to Part 4 → (coming soon)
Troubleshooting: SSH Access
Nếu bạn muốn SSH vào instance (mình không setup cái đó), bạn sẽ cần security group:
resource "aws_security_group" "allow_ssh" {
name = "allow_ssh"
description = "Allow SSH inbound traffic"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # Warning: Allows SSH from anywhere
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.allow_ssh.id]
tags = {
Name = "MyFirstTerraformInstance"
Environment = "tutorial"
ManagedBy = "terraform"
}
}
Mình sẽ cover security groups đàng hoàng ở Part 5. Bây giờ chỉ cần biết là 0.0.0.0/0 cho phép SSH từ bất cứ đâu, cái này insecure cho production. Ổn cho tutorial thôi.
Additional Resources
- AWS Provider Documentation - Mọi AWS resource Terraform hỗ trợ
- Terraform State Deep Dive - Official docs về state management
- AWS Free Tier Details - Biết cái gì free trước khi deploy
Bài này là phần của series "Terraform from Fundamentals to Production". Theo dõi để master Infrastructure as Code với Terraform.
Điều hướng series:
- Phần 1: Tại sao cần Infrastructure as Code?
- Phần 2: Cài đặt Terraform
- Phần 3: Tài nguyên Cloud đầu tiên (Bạn đang ở đây)
- Phần 4: Cơ bản về HCL
- Phần 5: Variables, Outputs & State
- Phần 6: Quy trình làm việc với Terraform
- Phần 7: Modules để tổ chức code (Sắp ra mắt)
- Phần 8: Mô hình Multi-Cloud (Sắp ra mắt)
- Phần 9: Quản lý State & Team Workflows (Sắp ra mắt)
- Phần 10: Testing & Validation (Sắp ra mắt)
- Phần 11: Bảo mật & Quản lý Secrets (Sắp ra mắt)
- Phần 12: Production Patterns & DevSecOps (Sắp ra mắt)