Bài giảng: hiểu luồng trước khi chạy lệnh
Bài toán: Tự động tạo bucket, upload cả thư mục static bằng fileset và kiểm soát cache cho từng loại file.
terraform fmt
terraform init
terraform validate
terraform plan
terraform apply
terraform plan -destroy
terraform destroyKhi nào S3 là lựa chọn phù hợp?
Landing page, tài liệu tĩnh hoặc SPA build sẵn có thể lưu trên S3. Trong production, thường đặt CloudFront phía trước và dùng Origin Access Control thay vì mở bucket công khai. Ví dụ dưới đây ưu tiên hiểu cách Terraform upload file; hãy khóa quyền public theo yêu cầu bảo mật của hệ thống.
Giả sử thư mục có dạng:
site/
├── index.html
└── assets/app.js
Tạo bucket và upload file
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 6.0" }
}
}
provider "aws" { region = "ap-southeast-1" }
resource "aws_s3_bucket" "site" {
bucket = "demo-static-site-12345"
}
locals {
site_root = "${path.module}/site"
files = fileset(local.site_root, "**/*")
mime_types = {
html = "text/html"
css = "text/css"
js = "application/javascript"
svg = "image/svg+xml"
}
}
resource "aws_s3_object" "site_files" {
for_each = { for file in local.files : file => file }
bucket = aws_s3_bucket.site.id
key = each.key
source = "${local.site_root}/${each.key}"
content_type = lookup(local.mime_types, split(".", each.key)[length(split(".", each.key)) - 1], "application/octet-stream")
etag = filemd5("${local.site_root}/${each.key}")
}
fileset trả về các path tương đối; for_each biến mỗi file thành một object riêng. filemd5 khiến Terraform nhận ra file đã đổi và upload lại. Không dùng file() cho binary: file() dành cho nội dung text, còn upload object dùng source.
terraform init
terraform fmt
terraform plan
terraform apply
Cache và deploy lặp lại
File HTML thường cache ngắn, còn asset có hash tên file có thể cache lâu hơn:
cache_control = endswith(each.key, ".html") ? "no-cache" : "public,max-age=31536000,immutable"
Khi đổi website, nên build vào thư mục mới rồi chạy plan/apply. Khi xóa bucket, S3 bucket phải rỗng; trong lab có thể dùng force_destroy = true, nhưng production không nên bật tùy tiện vì nó cho phép Terraform xóa toàn bộ object.
Kiểm tra một lần deploy
Sau apply, kiểm tra object và metadata thay vì chỉ nhìn số resource:
aws s3 ls s3://demo-static-site-12345/ --recursive
aws s3api head-object \
--bucket demo-static-site-12345 \
--key index.html \
--query '{Type:ContentType,Cache:CacheControl,ETag:ETag}'
Nếu thay nội dung mà plan không upload lại, kiểm tra source có trỏ đúng path và etag = filemd5(...) có nằm trong resource. Nếu dùng pipeline, hãy build website trước, lưu artifact và để Terraform upload đúng thư mục artifact đó; không build khác nhau giữa bước plan và apply.
Với SPA, còn phải xử lý fallback 403/404 về index.html, HTTPS, OAC và invalidation CloudFront. Upload được file lên S3 mới chỉ là nửa đầu của một website production.
Expected state, security gate và deploy drill
Dùng bucket tên có hậu tố lab, tag Training = terraform-04, thư mục site/ cố định và một AWS account/region sandbox. Expected state là mỗi file trong fileset có một aws_s3_object, content type/cache đúng extension, HTML cache ngắn, asset hash cache dài, và plan lần hai no-op khi artifact không đổi. Bucket lab phải block public access mặc định; nếu bài minh họa website endpoint cần public thì phải tách branch/lab, ghi rõ rủi ro và không dùng bucket production.
Thực hiện các drill:
- Thêm/sửa/xóa một file trong
site/, chạy plan và xác nhận chỉ object tương ứng create/update/delete; kiểm trahead-objectcontent type, cache-control và ETag. - Đổi tên một asset, xem Terraform có xóa key cũ và tạo key mới; kiểm tra reference trong HTML để tránh deploy artifact không đồng bộ.
- Đổi
site_roothoặc chạy plan ở thư mục sai, đọcfileset/source error rồi khôi phục; không trỏsourcevào thư mục workspace chứa secret hoặc.env. - Chạy
terraform plan -destroyvà kiểm tra bucket/object scope; không bậtforce_destroytrên production. Với bucket versioning/OAC/CloudFront, ghi migration/retention/invalidation plan riêng.
Quality gate
Pass khi người học chứng minh được artifact deterministic (build một lần, plan/apply cùng output), content/cache metadata đúng, public access không mở ngoài chủ ý, drift/object deletion được review, website smoke test/CloudFront path có evidence và cleanup không để bucket/object/request phát sinh chi phí. Terraform upload file không tự giải quyết HTTPS, SPA fallback, OAC hay cache invalidation.