DRY Configuration with include
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”include block คือวิธีที่ terragrunt.hcl ของ unit หนึ่งดึงทุกอย่างที่ประกาศไว้ใน root.hcl หรือใน intermediate config file ไหนก็ตามเข้ามาใช้ โดยไม่ต้องพิมพ์ซ้ำสักบรรทัด
include กับ find_in_parent_folders
หัวข้อที่มีชื่อว่า “include กับ find_in_parent_folders”vpc/terragrunt.hcl ในบทที่แล้วเปิดด้วย block นี้ ตอนนี้ถึงเวลาอธิบายให้ชัดเจน
include "root" { path = find_in_parent_folders("root.hcl")}find_in_parent_folders("root.hcl") เดินขึ้น directory tree จากตำแหน่งของ unit ปัจจุบัน ทีละชั้น จนกว่าจะเจอไฟล์ที่ชื่อ root.hcl เป๊ะ ๆ จากนั้น include "root" จะ merge ทุกอย่างที่ไฟล์นั้นประกาศไว้เข้ามาใน config ของ unit ปัจจุบัน เหมือนกับพิมพ์ไว้ตรงนั้นเอง ทั้ง remote_state block, backend.tf ที่ generate ไว้, provider generate block ทั้งหมด
ที่การเดินหาแบบนี้สำคัญก็เพราะ include บรรทัดเดียวกันเป๊ะใช้ได้ทั้งกับ unit ที่อยู่ต่ำกว่า root.hcl แค่ชั้นเดียวหรือลึกไปห้าชั้น ย้าย unit ไปอยู่ subdirectory ใหม่ตอน reorganize โครงสร้าง บรรทัดนี้ก็ยังทำงานเหมือนเดิมไม่ต้องแก้ เพราะไม่เคย hard-code relative path แบบ ../../../root.hcl ที่จะพังทันทีที่โครงสร้าง tree เปลี่ยนไป
locals กับ read_terragrunt_config สำหรับหนึ่งชั้นถัดลงมา
หัวข้อที่มีชื่อว่า “locals กับ read_terragrunt_config สำหรับหนึ่งชั้นถัดลงมา”include ไม่ใช่กลไก inherit เดียวที่มี และไม่ใช่ตัวเลือกที่ถูกเสมอไป บางครั้งคุณอยากแชร์ค่าที่เล็กกว่าและเจาะจงกว่าลงไปแค่บางส่วนของ tree ไม่ใช่ทั้งหมด ลองนึกภาพไฟล์ region.hcl ตัวกลางที่อยู่ต่ำกว่า root จริงหนึ่งชั้น ครอบคลุมเฉพาะ unit ที่อยู่ใน AWS region หนึ่งเจาะจง
locals { aws_region = "us-east-1"}unit ที่อยู่ใต้ directory ของ region นั้นอ่านไฟล์นั้นด้วย read_terragrunt_config() ผสมกับ find_in_parent_folders() ตัวเดิมที่คุณรู้จักแล้ว
include "root" { path = find_in_parent_folders("root.hcl")}
locals { region_vars = read_terragrunt_config(find_in_parent_folders("region.hcl"))}
terraform {}
inputs = { aws_region = local.region_vars.locals.aws_region cidr_block = "10.0.0.0/16"}read_terragrunt_config() parse Terragrunt config ไฟล์อื่นแล้วส่งเนื้อหากลับมาเป็นค่า และ locals block ของไฟล์นั้นจะซ้อนอยู่ใต้ .locals ในผลลัพธ์ จึงเขียนเป็น local.region_vars.locals.aws_region unit ที่อยู่ใต้ prod/ap-southeast-1/ ก็จะมี region.hcl ของตัวเองที่ประกาศ aws_region = "ap-southeast-1" ส่วน unit ไหนก็ตามในทั้ง tree ยังคง share root.hcl เดียวกันสำหรับ backend และ provider root เดียวกัน แต่ region ต่างกันในแต่ละ subtree โดยไม่มี unit ไหนต้อง hard-code region ของตัวเองไว้ตรง ๆ เลย
inputs: เทียบเท่า tfvars file ของ Terragrunt
หัวข้อที่มีชื่อว่า “inputs: เทียบเท่า tfvars file ของ Terragrunt”ทุกตัวอย่างที่ผ่านมาจบด้วย inputs = { ... } block ทั้งนั้น และสมควรมีคำอธิบายของตัวเอง นี่คือวิธีที่ unit ส่ง input variable ของ Terraform module ที่อยู่ข้างใต้เข้าไป ทำหน้าที่เหมือน .tfvars file ที่ใช้กับ Terraform root module ธรรมดาทุกประการ เพียงแต่เขียนตรง ๆ เป็น Terragrunt HCL แทนที่จะเป็นไฟล์แยกที่ต้องบอก Terraform ให้โหลด แต่ละ key ใน inputs แม็พไปที่ variable ที่ module ประกาศไว้ และ Terragrunt ส่ง block ทั้งหมดผ่านไปให้ Terraform เป็นค่า -var อยู่เบื้องหลัง
เพราะ inputs คือ HCL จริง ไม่ใช่ .tfvars file แบบ static จึงอ้างอิงอะไรก็ได้ในไฟล์ config เดียวกัน local.region_vars.locals.aws_region ข้างบนคือตัวอย่างหนึ่ง และบทถัดไปจะแนะนำการอ้างอิง output ของ unit อื่นด้วยวิธีเดียวกันนี้
flowchart TD root["root.hcl (remote_state + generate)"] region["prod/us-east-1/region.hcl (locals.aws_region)"] unit["prod/us-east-1/vpc/terragrunt.hcl"] root -->|include + find_in_parent_folders| unit region -->|read_terragrunt_config + find_in_parent_folders| unit unit --> inputs["inputs = aws_region, cidr_block"]