ข้ามไปยังเนื้อหา

Installing Terraform and Project Structure

ติดตั้ง Terraform ผ่าน version manager แทนการใช้ binary ตัวเดียวที่ pin ตายตัว เขียน resource แรกที่เป็น AWS จริง แล้วแยกออกเป็นไฟล์หลายไฟล์ตามชื่อที่เป็น convention — ซึ่งไม่มีตัวไหนที่ Terraform บังคับจริง ๆ

ติดตั้ง Terraform (และทำไม version manager ถึงดีกว่า binary เดี่ยว)

หัวข้อที่มีชื่อว่า “ติดตั้ง Terraform (และทำไม version manager ถึงดีกว่า binary เดี่ยว)”

คุณดาวน์โหลด Terraform binary ตัวเดียวจาก HashiCorp แล้ววางไว้ใน PATH ได้ และวิธีนี้ก็ใช้งานได้ดีถ้าทำ experiment คนเดียว แต่พอทำงานมากกว่าหนึ่งโปรเจกต์ วิธีนี้จะเริ่มมีปัญหา repository หนึ่งเขียนไว้สำหรับ Terraform 1.5 อีกอันต้องใช้ฟีเจอร์ของ 1.9 และอีกอันก็ migrate ไปใช้ OpenTofu แล้ว การคอยสลับ binary ตัวเดียวให้ตรงกับโปรเจกต์ที่คุณอยู่ตอนนั้นคืองานที่ต้องทำตลอดและผิดพลาดได้ง่าย

Version manager แก้ปัญหานี้ด้วยการติดตั้งหลายเวอร์ชันไว้พร้อมกัน แล้วสลับใช้ตามโปรเจกต์ ส่วนใหญ่อ้างอิงจากไฟล์บอกเวอร์ชันที่ commit ไว้ใน repository tenv เป็นตัวเลือกที่ดีเพราะไม่ได้ผูกกับเครื่องมือตัวเดียว จัดการเวอร์ชันของ Terraform, OpenTofu, Terragrunt และ Atmos ทั้งหมดจาก CLI ตัวเดียว ซึ่งสำคัญมากเมื่อทีมของคุณรัน Terragrunt คู่กับ Terraform (จะพูดถึงในคอร์สนี้ช่วงหลัง)

Terminal window
# install tenv (macOS, via Homebrew)
brew install tenv
# install and pin a specific Terraform version for the current directory
tenv tf install 1.9.0
tenv tf use 1.9.0
# tenv reads a .terraform-version file (or the terraform block's
# required_version constraint) to pick the right version automatically
terraform version

ไม่ว่าคุณจะใช้วิธีติดตั้งแบบไหน คำสั่งที่คุณรันกับ terraform binary ในแต่ละวันก็เหมือนกันทุกประการ — version manager แค่เปลี่ยนวิธีที่ binary นั้นมาอยู่บนเครื่องคุณเท่านั้น

โปรเจกต์ Terraform คือไดเรกทอรีที่มีไฟล์ .tf หนึ่งไฟล์หรือมากกว่านั้น ไฟล์ที่เล็กที่สุดแต่ใช้งานได้จริงคือการประกาศ provider กับ resource เดียว

terraform {
required_version = ">= 1.7.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "reports" {
bucket = "acme-monthly-reports"
}

นั่นคือ configuration ที่สมบูรณ์และ apply ได้จริง ไม่มี VPC ไม่มีเรื่อง networking ไม่มี prerequisite อะไรนอกจาก AWS credential ใน environment ของคุณ aws_s3_bucket เป็น resource แรกที่ดีด้วยเหตุผลนี้เป๊ะ ๆ คือไม่ต้องพึ่งอะไรให้มีอยู่ก่อน

โปรเจกต์จริงแยกไฟล์เดียวนั้นออกเป็นหลายไฟล์ ตาม convention

providers.tf
terraform {
required_version = ">= 1.7.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
variables.tf
variable "bucket_name" {
description = "Name of the S3 bucket to create"
type = string
default = "acme-monthly-reports"
}
main.tf
resource "aws_s3_bucket" "reports" {
bucket = var.bucket_name
}
outputs.tf
output "bucket_arn" {
description = "ARN of the created S3 bucket"
value = aws_s3_bucket.reports.arn
}

ชื่อ main.tf, variables.tf, outputs.tf, providers.tf และ versions.tf เป็น convention ไม่ใช่ข้อบังคับของ Terraform Terraform ไม่ได้สนใจชื่อไฟล์เลยแม้แต่น้อย แต่โหลดทุกไฟล์ .tf ในไดเรกทอรี รวมเข้าเป็น configuration เดียว และไม่สนว่าคุณตั้งชื่อไฟล์ว่า main.tf, zzz.tf หรือ whatever.tf resource ใน outputs.tf กับ variable ที่อ้างอิงใน main.tf ทำงานเหมือนกันทุกอย่างกับตอนที่ทุกอย่างอยู่ในไฟล์เดียว Terraform สร้าง dependency graph เดียวกันไม่ว่าจะแยกไฟล์แบบไหน การแยกตาม concern (provider, variable, resource, output) มีไว้เพื่อให้คนที่เปิดไดเรกทอรีรู้ว่าต้องไปดูตรงไหนเท่านั้น ไม่ใช่เพราะ Terraform ต้องการเส้นแบ่งนั้น

flowchart TB
  subgraph dir["Project directory"]
    main["main.tf"]
    vars["variables.tf"]
    outs["outputs.tf"]
    prov["providers.tf"]
    ver["versions.tf"]
  end
  main --> combined["One combined Terraform configuration"]
  vars --> combined
  outs --> combined
  prov --> combined
  ver --> combined
Terraform loads every .tf file in a directory into one combined configuration

มีสองคำสั่งที่ควรรันก่อน commit ทุกครั้ง และรันบ่อยแค่ไหนก็ไม่มีต้นทุนอะไร

terraform fmt เขียนไฟล์ทับในที่เดิมให้เป็น canonical formatting ของ Terraform คือ indentation สม่ำเสมอ เครื่องหมาย = เรียงตรงกัน spacing สม่ำเสมอ แก้แค่ style ไม่ได้แก้ logic

Terminal window
terraform fmt

terraform validate ตรวจว่า configuration สอดคล้องกันภายในตัวเอง คือ HCL syntax ถูกต้อง argument type ถูกต้อง variable ที่อ้างอิงมีอยู่จริง จับ typo และความผิดพลาดเชิงโครงสร้างได้ก่อนที่จะติดต่อ AWS ด้วยซ้ำ

Terminal window
terraform validate
Success! The configuration is valid.

สิ่งที่ validate ไม่ทำ คือตรวจอะไรก็ตามกับ AWS API จริง validate ไม่รู้ว่า account ของคุณชน service quota หรือเปล่า ชื่อ bucket ที่คุณเลือกถูกใช้ไปแล้วทั่วโลกหรือเปล่า หรือ IAM credential ของคุณมีสิทธิ์สร้างจริงหรือเปล่า ทั้งหมดนี้จะโผล่มาก็ต่อเมื่อคุณรัน terraform plan เพราะเป็นคำสั่งแรกที่ติดต่อกับ AWS จริง ๆ configuration หนึ่งอาจผ่าน validate แบบไม่มีปัญหา แล้วยังพังตอน plan หรือ apply ได้

Terraform สนใจไหมว่า resource ถูกประกาศใน main.tf หรือชื่อไฟล์อื่น
terraform fmt ทำอะไร
terraform validate ตรวจอะไร
ทำไม terraform validate ผ่านไม่ได้แปลว่าจะไม่มีปัญหาฝั่ง AWS จริง