작고 재사용 가능한 모듈 만들기

AWSBeginner
지금 연습하기

소개

두 팀에서 이름, 소유자, 보고서 내용이 서로 다른 동일한 소규모 보고서 저장소 설계가 필요합니다. 제공된 모듈의 인터페이스를 완성하고, 독립적인 두 루트에서 호출한 뒤, 기존 멤버를 교체하지 않고 안정적인 보고서 컬렉션을 확장합니다.

로컬 모듈, 변수, 출력값, 리소스 주소를 이해하고 있어야 합니다. 리소스의 기본 틀과 호출 측 입력값은 제공됩니다. 여러분은 이들의 계약을 작성하고, 준비된 도구를 사용하여 새로운 환경에 배포합니다. 개인 AWS 계정은 필요하지 않습니다.

관련 자격증 시험 항목

자격증 시험 과제 실습 내용
CloudOps Engineer – Associate (SOA-C03) Task 3.1, Skill 3.1.6 사용 중인 리소스를 보존하면서 검토된 구성 및 상태 변경으로 인프라를 유지관리하는 Terraform 기초 실습입니다.

실습 개요

개념도: 유지관리 작업은 구성, 상태, 기존 보고서 스토리지 사이의 관계를 보존합니다.

타입이 지정된 모듈 인터페이스 정의하기

이 단계에서는 재사용 가능한 소규모 스토리지 모듈의 입력 및 출력 계약을 완성합니다. 자식 모듈은 인터페이스 뒤에 리소스를 묶어 제공하고, 루트 모듈은 구체적인 입력값을 제공하며 자체 상태를 소유합니다.

cd /home/labex/project/reusable-reports
cat modules/report-store/main.tf
cat dev/main.tf

제공된 리소스의 기본 틀은 var.bucket_name, var.owner, var.reports를 사용합니다. for_each는 맵 키마다 객체 인스턴스를 하나씩 생성하며, aws_s3_object.reports["daily"] 같은 주소를 사용합니다. 이름이 있는 안정적인 키를 사용하면 기존 객체와 새로 추가한 멤버를 구분하여 유지할 수 있습니다. 버킷의 버전 관리 리소스는 명시적인 의존성이므로 보고서를 쓸 때 버전을 식별할 수 있는 ID가 부여됩니다.

인터페이스를 정의합니다. map(object({ body = string }))는 각 멤버가 보고서 내용을 제공해야 하는 이름 기반 컬렉션을 받습니다. 문서화되지 않은 입력 구조에 의존하는 대신 모듈이 기대하는 바를 명확히 표현합니다.

cat > modules/report-store/variables.tf <<'HCL'
variable "bucket_name" {
  type        = string
  description = "Unique bucket name supplied by this environment root."
}
variable "owner" {
  type        = string
  description = "Owner tag supplied by the caller."
}
variable "reports" {
  type        = map(object({ body = string }))
  description = "Stable report keys and their text content."
}
HCL

출력값은 호출 측에서 모듈 내부에 직접 접근하지 않고도 유용한 리소스 정보를 얻을 수 있게 합니다. 아래의 for 표현식은 컬렉션 키를 객체 키에 매핑하는 맵을 만듭니다.

cat > modules/report-store/outputs.tf <<'HCL'
output "bucket_id" {
  value = aws_s3_bucket.store.id
}
output "object_keys" {
  value = { for key, report in aws_s3_object.reports : key => report.key }
}
HCL

dev 루트를 초기화하고 계약을 확인합니다.

terraform -chdir=dev init
terraform -chdir=dev validate
terraform -chdir=dev plan

구성이 유효하며 3 to add가 표시되어야 합니다. 추가할 리소스는 버킷, 버전 관리 구성, daily 보고서 객체입니다. 호출 측의 버킷 이름, 소유자, 보고서 내용을 확인하기 전에는 적용하지 마세요. 독립적인 재무 참조 리소스는 이 모듈과 관련이 없으며 변경되지 않아야 합니다.

독립적인 두 루트에서 동일한 모듈 호출하기

이 단계에서는 같은 모듈에 서로 다른 입력값을 전달하여 dev와 preview를 배포합니다. 루트들은 모듈 소스 파일을 공유하며 상태를 공유하지 않습니다. 현재 별도의 작업 디렉터리는 별도의 로컬 상태를 사용합니다. for_each는 하나의 상태 안에서 리소스를 구분할 뿐입니다.

dev의 계획을 저장하여 검토하고 적용합니다.

terraform -chdir=dev plan -out=dev.tfplan

3 to add, 0 to change, 0 to destroy가 표시되어야 합니다.

terraform -chdir=dev apply dev.tfplan

preview를 초기화하기 전에 호출 측 구성을 읽습니다.

cat preview/main.tf
terraform -chdir=preview init
terraform -chdir=preview validate
terraform -chdir=preview plan -out=preview.tfplan

서로 다른 입력값으로 버킷 module-preview-reports, 소유자 preview, 내용 preview daily report를 선택합니다. dev에 대한 변경 없이 리소스 세 개를 생성하는 별도의 계획이 나와야 합니다.

terraform -chdir=preview apply preview.tfplan

각 루트의 출력값과 안정적인 인스턴스 주소를 확인합니다.

terraform -chdir=dev output
terraform -chdir=preview output
terraform -chdir=dev state list
terraform -chdir=preview state list

두 루트 모두 bucket_id와 object_keys를 제공하며, 각각 "daily" 키를 가진 보고서 인스턴스가 있습니다. 하지만 이 주소들은 서로 다른 로컬 상태와 서로 다른 버킷에 속합니다. 실제 내용을 읽습니다.

aws s3 \
  cp s3://module-dev-reports/reports/daily.txt -
aws s3 \
  cp s3://module-preview-reports/reports/daily.txt -

dev daily report와 preview daily report가 표시되어야 합니다. AWS View에는 독립적인 두 저장소와 재무 참조 리소스가 표시됩니다. 컬렉션을 확장한 뒤 비교할 수 있도록 dev의 현재 daily VersionId를 표시합니다.

aws s3api \
  head-object \
  --bucket module-dev-reports \
  --key reports/daily.txt \
  --query VersionId \
  --output text

기존 보고서를 교체하지 않고 안정적인 컬렉션 멤버 추가하기

이 단계에서는 dev의 맵만 확장합니다. 컬렉션의 키를 변경하면 리소스 인스턴스의 식별 정보가 바뀝니다. daily 키를 유지하면서 weekly를 추가하면 daily 객체는 온전히 유지되어야 합니다.

기존 입력값을 그대로 유지하고 새 멤버 하나를 추가한 내용으로 dev 호출 측 구성을 교체합니다.

cat > dev/main.tf <<'HCL'
module "report_store" {
  source      = "../modules/report-store"
  bucket_name = "module-dev-reports"
  owner       = "dev"
  reports = {
    daily  = { body = "dev daily report\n" }
    weekly = { body = "dev weekly report\n" }
  }
}
output "bucket_id" { value = module.report_store.bucket_id }
output "object_keys" { value = module.report_store.object_keys }
HCL

변경 사항을 검토합니다.

terraform -chdir=dev plan -out=extra.tfplan

1 to add, 0 to change, 0 to destroy가 표시되어야 하며, module.report_store.aws_s3_object.reports["weekly"]만 추가되어야 합니다. 기존 daily 객체나 버킷이 교체된다면 중단하고 키와 변경하지 않아야 할 입력값을 비교하세요.

terraform -chdir=dev apply extra.tfplan

daily VersionId를 이전 단계의 출력값과 비교합니다.

aws s3api \
  head-object \
  --bucket module-dev-reports \
  --key reports/daily.txt \
  --query VersionId \
  --output text

반드시 원래의 동일한 버전이어야 합니다. 새 멤버와 독립적인 preview 보고서를 읽습니다.

aws s3 \
  cp s3://module-dev-reports/reports/weekly.txt -
aws s3 \
  cp s3://module-preview-reports/reports/daily.txt -

dev weekly report와 변경되지 않은 preview daily report가 표시되어야 합니다. 백그라운드 검사는 교체된 객체의 바이트가 같다는 이유로 통과시키지 않고, 서비스가 부여한 최초 쓰기 버전을 비교합니다.

terraform -chdir=dev output
terraform -chdir=dev plan
terraform -chdir=preview plan

dev의 출력 맵에는 두 키가 모두 포함되고, preview에는 여전히 daily만 있습니다. 두 루트 모두 No changes가 표시되며 수렴해야 합니다. 사용 중인 저장소는 계속 사용할 수 있도록 유지하세요. 이 모듈은 인터페이스와 리소스 컬렉션을 정의합니다. 별도의 원격 백엔드 키를 선택하는 것은 환경 격리를 위한 추가 결정이며 이후에 다룹니다.

모듈 입력과 출력값을 경계로 사용하는 방법은 HashiCorp의 모듈 조합 지침을 참고하세요.

요약

타입이 지정된 모듈 인터페이스를 작성하고, 독립적인 두 루트에 유용한 출력값을 반환하며, 원래 보고서를 교체하지 않고 안정적인 for_each 멤버를 추가했습니다. 리소스 컬렉션은 환경의 상태 경계와는 별개입니다.