본문 바로가기
클라우드

🚀 terraform apply는 언제 써야 할까? — 마이그레이션 vs 드리프트 수정, 둘 다 맞다

by gasbugs 2026. 4. 13.

Terraform은 선언형 도구다. 하지만 '언제 apply해야 하는가'는 생각보다 훨씬 복잡한 문제다.

🎯 이 글에서 다루는 것

  • terraform apply의 정확한 동작 원리
  • 마이그레이션 시나리오에서의 apply 사용법
  • 드리프트(Drift) 발생 시 apply의 역할과 주의점
  • 두 케이스의 차이점과 공통 원칙
  • 실수하기 쉬운 패턴과 권장 워크플로

📌 도입: "그냥 apply 치면 되는 거 아닌가요?"

Terraform을 처음 배우면 누구나 이렇게 생각한다. 코드 작성하고 plan 보고 apply — 심플하다. 그런데 실제 운영 환경에서 일하다 보면 고민이 생긴다.

"콘솔에서 직접 보안그룹 규칙 하나 추가했는데… apply 해도 되나?"

"기존 인프라를 Terraform으로 관리하려는데 어디서부터 시작해야 하지?"

 

 

이 두 질문이 바로 오늘 다룰 핵심이다. 마이그레이션드리프트 수정은 언뜻 비슷해 보이지만 성격이 전혀 다르고, 각각에 맞는 apply 전략이 있다.


🔍 먼저 알아야 할 것: Terraform의 상태(State)

Terraform은 .tfstate 파일에 인프라의 현재 상태를 기록한다. apply를 실행하면 다음 3가지를 비교해서 행동을 결정한다.

비교 대상 설명
코드(HCL) 내가 원하는 상태 (desired state)
State 파일 Terraform이 알고 있는 상태 (known state)
실제 인프라 클라우드에 실제로 존재하는 상태 (actual state)

 

이 세 가지가 일치하면 apply는 아무것도 하지 않는다. 불일치가 생겼을 때 apply가 필요해진다.


🧳 케이스 1: 마이그레이션 — 기존 인프라를 Terraform으로 가져오기

언제 이 케이스인가?

  • 콘솔이나 CLI로 수동 생성된 인프라가 이미 존재한다
  • 이걸 이제 Terraform으로 코드화(IaC화) 하고 싶다
  • State 파일에는 해당 리소스가 없는 상태다

잘못된 접근: 코드 작성 후 바로 apply

# ❌ 위험한 방법
terraform apply

 

이미 존재하는 S3 버킷, EC2 인스턴스를 코드로 작성한 뒤 apply하면 Terraform은 새로 만들려고 시도한다. 이미 같은 이름의 리소스가 있으면 에러가 나고, 운이 나쁘면 기존 리소스가 삭제 후 재생성되는 사고가 발생한다.

 

올바른 접근: terraform import 먼저

# ✅ 올바른 방법: import로 State에 먼저 등록
terraform import aws_s3_bucket.my_bucket my-existing-bucket-name

 

import 명령은 실제 인프라 리소스를 State 파일에 등록한다. 이후 plan을 실행해서 코드와 State가 일치하는지 확인하고, 차이가 없을 때 비로소 안전하게 관리할 수 있다.

 

Terraform 1.5+ : import 블록으로 선언형 마이그레이션

Terraform 1.5부터는 import 블록을 HCL 코드 안에 직접 작성할 수 있다.

# import.tf
import {
  to = aws_s3_bucket.my_bucket
  id = "my-existing-bucket-name"
}

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-existing-bucket-name"
  # ... 기타 속성
}
# plan으로 import 결과 미리 확인
terraform plan

# 문제 없으면 apply
terraform apply

 

이 방식에서 apply는 import + 코드 동기화를 한 번에 처리한다. 마이그레이션 완료 후 import 블록은 삭제해도 된다.

 

마이그레이션에서 apply 권장 시점 정리

  1. ✅ terraform import로 State 등록 완료 후
  2. ✅ terraform plan에서 No changes 또는 의도한 변경만 표시될 때
  3. ✅ import 블록 방식에서 plan 결과를 검토한 후

🔄 케이스 2: 드리프트(Drift) — State와 실제 인프라가 어긋났을 때

드리프트란?

드리프트(Configuration Drift)는 Terraform이 관리하는 리소스가 코드나 State 밖에서 변경되었을 때 발생한다.

 

흔한 원인들:

  • 👤 누군가 콘솔에서 직접 보안그룹 규칙 수정
  • 🔧 다른 팀원이 AWS CLI로 태그 변경
  • ☁️ 클라우드 서비스가 자동으로 속성 업데이트 (예: EKS 노드 그룹)
현재 상태:
코드(HCL)    →  포트 443만 허용
State 파일   →  포트 443만 허용  (apply 시점 기록)
실제 AWS     →  포트 443 + 8080 허용  ← 누군가 콘솔에서 추가!

 

이 상태에서 terraform plan을 실행하면?

terraform plan
# ~ aws_security_group_rule.allow_https will be updated in-place
#   - from_port = 8080  (삭제 예정)

 

Terraform은 코드(HCL)를 기준으로 8080 규칙을 제거하려 한다.

apply 전에 반드시 해야 할 것: 드리프트 감지

# State를 실제 인프라와 동기화하여 드리프트 감지
terraform refresh

# 또는 plan과 함께
terraform plan -refresh-only

 

-refresh-only 플래그는 실제 인프라 상태를 State에 반영만 하고, 인프라는 변경하지 않는다. 드리프트가 어디서 어떻게 발생했는지 파악하는 데 매우 유용하다.

 

드리프트 처리 전략: 두 가지 선택지

전략 A: 코드를 현실에 맞게 업데이트 (드리프트 수용)

콘솔에서 추가한 변경이 의도된 것이라면, 코드를 업데이트해서 apply한다.

# 코드에 8080 규칙 추가
resource "aws_security_group_rule" "allow_8080" {
  type        = "ingress"
  from_port   = 8080
  to_port     = 8080
  protocol    = "tcp"
  cidr_blocks = ["10.0.0.0/8"]
  security_group_id = aws_security_group.main.id
}
terraform plan   # 확인
terraform apply  # 코드와 실제 상태 일치시킴

 

전략 B: 인프라를 코드 기준으로 되돌리기 (드리프트 제거)

무단 변경이라면 apply로 코드 기준 상태로 되돌린다.

# 코드는 수정하지 않고 그대로 apply
terraform apply
# → 8080 규칙이 제거되고 코드 상태로 복원

드리프트 시나리오에서 apply 권장 시점 정리

  1. ✅ terraform plan -refresh-only로 드리프트 범위 파악 후
  2. ✅ 드리프트가 의도된 것인지 무단 변경인지 판단 후
  3. ✅ 전략 A(코드 업데이트) 또는 전략 B(원상복구) 결정 후
  4. ❌ 드리프트 원인도 모른 채 무작정 apply하면 안 됨

⚠️ 주의사항: apply 전 반드시 확인할 것들

1. plan 없는 apply는 사고의 지름길

# ❌ 절대 금지 패턴
terraform apply -auto-approve

CI/CD 자동화에서도 plan 결과를 사람이 검토하는 단계를 반드시 넣어야 한다.

 

2. State 파일은 절대 수동으로 편집하지 말 것

드리프트가 발생했다고 해서 .tfstate 파일을 직접 수정하면 더 큰 문제가 생긴다. 반드시 terraform state 명령어를 사용한다.

# 특정 리소스를 State에서 제거 (인프라는 유지)
terraform state rm aws_s3_bucket.old_bucket

# State에서 리소스 목록 확인
terraform state list

 

3. 원격 State 사용은 선택이 아닌 필수

팀 환경에서 로컬 State를 쓰면 드리프트와 충돌이 일상이 된다.

# S3 + DynamoDB로 원격 State 구성
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-2"
    dynamodb_table = "terraform-lock"
    encrypt        = true
  }
}

 

4. 프로덕션에서는 target 플래그 사용을 최소화

# ⚠️ 긴급 상황이 아니면 피할 것
terraform apply -target=aws_instance.web

 

특정 리소스만 골라서 apply하면 의존 관계가 꼬일 수 있다.


✅ 정리: 마이그레이션 vs 드리프트, 뭐가 다른가?

구분 마이그레이션 드리프트 수정

구분 마이그레이션  드리프트 수정
상황 기존 인프라를 Terraform으로 편입 관리 중 인프라가 외부에서 변경됨
State 상태 해당 리소스 State 없음 State와 실제 인프라 불일치
apply 전 작업 terraform import 또는 import 블록 terraform plan -refresh-only
apply 목적 코드와 State 동기화 코드 기준 복원 또는 코드 업데이트 후 동기화
위험도 높음 (잘못하면 삭제/재생성) 중간 (의도치 않은 변경 적용 가능)

 

결론: 둘 다 apply를 쓴다. 하지만 절차가 다르다.

 

terraform apply는 도구일 뿐이다. 마이그레이션이든 드리프트 수정이든, 핵심은 apply 전에 plan을 보고, 어떤 변경이 일어나는지 이해한 상태에서 실행하는 것이다. Terraform의 진짜 위력은 apply 명령 한 줄이 아니라, 그 전에 수행하는 plan과 refresh에서 나온다.