트리거(Trigger)

도은호·2025년 9월 23일

terraform

목록 보기
19/32

Terraform엔 “이벤트 리스너” 같은 실시간 트리거는 없어.
대신 계획/적용(plan/apply) 시점에 “무엇이 바뀌면 무엇을 다시 만들지(Replace)”를 선언하는 방식으로 트리거를 구성.

  • 리소스 수준: lifecycle.replace_triggered_by — “저게 바뀌면 나도 새로 만들기”
  • 범용 마커: terraform_data.triggers_replace — “이 값이 바뀌면 내가 갈아끼워짐”
  • 레거시: null_resource.triggers — 과거의 표준(요즘은 terraform_data 권장)

1) lifecycle.replace_triggered_by — “A가 바뀌면 B도 교체”

이론

  • 어떤 리소스 B가, 다른 리소스/인스턴스 A교체(replace)연동되어 함께 교체되게 만들고 싶을 때.
  • “원래는 업데이트로 끝나는 변경”도 강제로 재생성하게 만들 수 있어, 롤링/리빌드 트리거에 유용.

예제: userdata.sh가 바뀌면 EC2를 새로 만들기

locals {
  userdata_sha = filesha256("${path.module}/userdata.sh")
}

# 1) 파일 해시 변화 → 이 리소스가 교체됨(아래 2번에서 연결고리로 사용)
resource "terraform_data" "app_spec" {
  triggers_replace = { userdata = local.userdata_sha }
}

# 2) EC2는 app_spec이 교체될 때마다 "나도 교체"
resource "aws_instance" "web" {
  ami           = data.aws_ssm_parameter.al2023.value
  instance_type = "t3.micro"
  subnet_id     = var.public_subnet_id

  user_data = file("${path.module}/userdata.sh")

  lifecycle {
    replace_triggered_by = [terraform_data.app_spec]
  }
}

확인

terraform apply -auto-approve
# userdata.sh 내용 변경
terraform plan    # ← aws_instance.web replace planned

  • 직접 파일 해시를 replace_triggered_by에 넣을 수는 없어.
    그래서 중간에 terraform_data를 ‘연결고리’로 두는 패턴이 깔끔해.

2) terraform_data.triggers_replace — “이 값이 바뀌면 나를 교체”

이론

  • 범용 트리거 리소스. 내부 상태를 관리하지 않지만, triggers_replace 값이 바뀌면 자기 자신이 교체됨.
  • 여기에 provisioner(최후의 수단) 를 붙여 외부 스크립트를 실행하거나, 위 1)처럼 다른 리소스의 replace 트리거 소스로 활용.

예제: 아티팩트 해시가 바뀌면 스크립트 한 번 실행

locals {
  artifact_sha = filesha256("${path.module}/app.zip")
}

resource "terraform_data" "redeploy" {
  triggers_replace = { artifact = local.artifact_sha }

  # 필요한 경우에만 사용 (로그에 비밀 노출 주의)
  provisioner "local-exec" {
    command = "echo 'artifact changed; do deploy step here'"
  }
}

확인

terraform apply
# app.zip 교체 또는 내용 변경
terraform plan   # ← terraform_data.redeploy will be replaced

베스트 프랙티스

  • triggers_replace 값은 결정적(deterministic) 이어야 해.
    (timestamp() 같은 값 넣으면 매번 교체 → 끝없는 흔들림)
  • 진짜 배포/설정은 가급적 cloud-init/Ansible/Packer 로.
    provisioner는 최후의 수단으로만 써.

3) null_resource.triggers — 레거시 트리거(이해는 필수)

이론

  • 예전엔 null_resource + triggers로 “입력 값이 바뀌면 리소스를 교체→프로비저너 실행”을 많이 썼어.
  • 지금은 terraform_data가 권장 대체. 기존 코드 읽을 때만 이해해두면 충분.

예제(기존 코드 스타일)

resource "null_resource" "build" {
  triggers = {
    artifact = filesha256("${path.module}/app.zip")
  }

  provisioner "local-exec" {
    command = "echo build because ${self.triggers.artifact}"
  }
}

주의

  • triggers비결정적 값을 넣으면 항상 재실행(반복 churn).
  • 비밀이 명령행에 노출될 수 있으니 로깅 주의.

언제 어떤 트리거를 쓰나?

상황추천 패턴
다른 리소스가 교체되면 나도 반드시 교체lifecycle.replace_triggered_by
파일/아티팩트/입력 값 변화 감지 자체가 필요terraform_data.triggers_replace
레거시 코드 유지/읽기null_resource.triggers (새 코드에선 지양)

공통 체크리스트

  • 트리거 입력은 결정적 값(해시, 버전, 태그)으로 — timestamp() 금지
  • 비밀은 노출 금지: sensitive/시크릿 매니저 사용, provisioner 명령행 주의
  • 의존성 명확화: 필요한 경우 depends_on 또는 replace_triggered_by로 연결
  • 적용은 항상 plan -out → apply plan.bin
  • 반복 실행되어도 멱등성 유지(스크립트가 여러 번 돌아도 안전)

자주 묻는 질문(FAQ)

Q. “트리거”가 실시간 이벤트처럼 동작하나요?
A. 아니요. Terraform은 plan/apply 사이클에서만 동작. 파일이 바뀐 즉시 자동 실행 같은 건 없어.

Q. replace_triggered_by에 파일 해시를 바로 넣으면 안 돼요?
A. 불가능. 대신 위 예제처럼 terraform_data를 연결고리로 사용하면 돼.

Q. Provisioner는 꼭 필요할 때만?
A. 맞아. 설치/설정은 cloud-init(UserData)/Ansible/Packer가 더 안전하고 재현성 좋아.


요약

Terraform의 트리거는 “무엇이 바뀌면 무엇을 다시 만들지”를 선언하는 기술.
교체 연동replace_triggered_by, 변화 감지terraform_data.triggers_replace,
레거시는 null_resource.triggers—이 세 가지면 실전에서 다 커버된다.

profile
`•.¸¸.•´´¯`••._.• 🎀 𝒸𝓇𝒶𝓏𝓎 𝓅𝓈𝓎𝒸𝒽💞𝓅𝒶𝓉𝒽 🎀 •._.••`¯´´•.¸¸.•`

0개의 댓글