Khi 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.
Xem bài nguồn và luôn chạy
terraform destroy/dọn bucket sau thử nghiệm.