테라폼 - apply는 성공했는데 왜 서비스는 동작하지 않을까?
Create, Ready, Attach, Activate로 이해하는 Terraform 배포 흐름
이전 글에서는 Terraform 리소스를 생성 조건과 동작 특성으로 나누어 정리했다.
리소스를 단순히 AWS 서비스 이름으로 보는 것이 아니라, 다음과 같은 관점으로 바라보는 방식이었다.
Layer = 생성 구조
Property = 동작 특성
이번 글에서는 그 내용을 조금 더 확장해서, Terraform에서 자주 마주치는 문제를 다뤄보려 한다.
terraform apply는 성공했는데
왜 서비스는 정상적으로 동작하지 않을까?
이 질문을 이해하려면 Terraform의 성공 기준과 실제 서비스의 성공 기준이 다르다는 점을 먼저 알아야 한다.
목차
- 1. terraform apply 성공의 의미
- 2. apply 성공과 서비스 정상 동작은 다르다
- 3. Create, Ready, Attach, Activate
- 4. Ready 단계에서 발생하는 문제
- 5. Attach 단계에서 발생하는 문제
- 6. Activate 단계에서 발생하는 문제
- 7. Terraform State는 어디까지 알고 있을까?
- 8. Destroy도 같은 관점으로 봐야 한다
- 9. CI/CD에서는 어떻게 다뤄야 할까?
- 10. 마무리
1. terraform apply 성공의 의미
Terraform에서 terraform apply가 성공했다는 것은 무엇을 의미할까?
간단히 말하면 다음과 같다.
Terraform이 선언된 리소스를 생성하거나 변경했고,
그 결과를 state에 기록했다.
예를 들어 다음과 같은 코드가 있다고 하자.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
}
Terraform은 aws_subnet.public이 aws_vpc.main.id를 참조한다는 것을 알 수 있다.
따라서 내부적으로 다음 순서를 만든다.
1. VPC 생성
2. Subnet 생성
3. 생성 결과를 state에 저장
이런 경우 terraform apply 성공은 비교적 직관적이다.
리소스 생성 성공 = apply 성공
하지만 모든 리소스가 이렇게 단순하지는 않다.
2. apply 성공과 서비스 정상 동작은 다르다
Terraform을 처음 사용할 때 가장 헷갈리는 부분이 있다.
Terraform apply 성공 = 서비스 정상 동작
라고 생각하기 쉽다는 점이다.
하지만 실제로는 그렇지 않다.
Terraform의 관심사는 주로 리소스의 생성과 변경이다. 반면 서비스의 정상 동작은 그 이후 단계까지 포함한다.
Terraform 관점:
리소스가 생성되었는가?
서비스 관점:
리소스가 준비되었는가?
리소스끼리 연결되었는가?
실제로 실행 가능한가?
트래픽을 받아도 되는가?
예를 들어 RDS가 생성되었다고 해서 애플리케이션이 바로 DB에 접속할 수 있는 것은 아니다. CloudFront Distribution이 생성되었다고 해서 바로 전 세계 엣지 로케이션에 배포가 끝난 것도 아니다.
ECS Service가 생성되었다고 해서 Task가 정상적으로 뜨고 ALB Health Check를 통과했다는 의미도 아니다.
Terraform의 성공 기준과 실제 서비스의 성공 기준은 다르다.
3. Create, Ready, Attach, Activate
이 차이를 이해하기 위해 인프라 배포 흐름을 다음 네 단계로 나누어 볼 수 있다.
Create → Ready → Attach → Activate
각 단계는 서로 다른 의미를 가진다.
3.1 Create
Create는 리소스가 생성된 상태를 의미한다.
Terraform이 가장 잘 처리하는 영역이다.
terraform apply
→ AWS API 호출
→ 리소스 생성
→ state에 기록
VPC, Subnet, IAM Role, S3 Bucket 같은 리소스를 생성하는 작업은 대부분 이 단계에 해당한다.
3.2 Ready
Ready는 리소스가 실제로 사용할 수 있는 상태를 의미한다.
여기서 가장 중요한 문장은 다음이다.
created != ready
리소스가 생성되었다고 해서 바로 사용할 수 있는 것은 아니다.
대표적인 예시는 다음과 같다.
RDS → available 상태 필요
CloudFront → deployed 상태 필요
ACM → validation 완료 필요
ALB → active 상태 필요
Terraform이 apply를 끝냈더라도 실제 리소스가 완전히 준비되기까지 시간이 걸릴 수 있다.
3.3 Attach
Attach는 리소스 간 연결이 이루어지는 단계다.
인프라 문제는 이 단계에서 매우 자주 발생한다.
ECS Service → Target Group 연결
CloudFront → Origin 연결
Lambda → EventBridge 연결
WAF → CloudFront 연결
Route53 → CloudFront 또는 ALB 연결
리소스가 각각 존재하더라도 연결이 완료되지 않으면 서비스는 정상적으로 동작하지 않는다.
리소스가 존재하는 것과 리소스가 연결된 것은 다르다.
3.4 Activate
Activate는 실제 실행 또는 트래픽 유입이 시작되는 단계다.
예시는 다음과 같다.
ECS desired_count 증가
EventBridge Scheduler enable
Route53 트래픽 연결
Auto Scaling 활성화
CloudFront 실제 트래픽 유입
이 단계에서는 실제 런타임 문제가 드러난다.
예를 들어 ECS Task가 실행되었지만 환경 변수가 잘못되어 종료될 수 있다. ALB Health Check가 실패할 수도 있고, IAM 권한이 부족해서 Lambda 실행이 실패할 수도 있다.
4. Ready 단계에서 발생하는 문제
Ready 단계의 핵심은 리소스가 생성된 이후 실제 사용 가능한 상태가 되었는지를 확인하는 것이다.
Terraform은 리소스를 생성하고 state에 기록할 수 있지만, 항상 운영 관점의 ready 상태까지 보장하지는 않는다.
4.1 RDS 예시
RDS는 대표적인 Ready-sensitive 리소스다.
Terraform으로 RDS를 생성하면 AWS에서는 DB 인스턴스 생성 작업이 시작된다. 하지만 DB가 실제 접속 가능한 상태가 되기까지는 시간이 걸린다.
resource "aws_db_instance" "main" {
identifier = "app-db"
engine = "mysql"
instance_class = "db.t3.micro"
allocated_storage = 20
username = "admin"
password = "examplepassword"
}
Terraform apply가 끝난 직후 애플리케이션이 DB에 접속하려고 하면 실패할 수 있다.
운영 관점에서는 다음 상태를 확인해야 한다.
DBInstanceStatus = available
AWS CLI로 확인하면 다음과 같다.
aws rds describe-db-instances \
--db-instance-identifier app-db \
--query "DBInstances[0].DBInstanceStatus"
4.2 CloudFront 예시
CloudFront도 생성 후 바로 완전한 상태가 아니다.
Distribution 생성 이후 전 세계 엣지 로케이션에 설정이 전파되어야 한다.
aws cloudfront get-distribution \
--id DISTRIBUTION_ID \
--query "Distribution.Status"
기대하는 상태는 다음이다.
Deployed
아직 InProgress 상태라면 다음 단계에서 연결이나 트래픽 유입을 바로 진행하지 않는 것이 안전하다.
4.3 ACM 예시
ACM 인증서는 생성만으로 끝나지 않는다.
DNS 검증을 사용하는 경우 검증 레코드가 생성되고, 해당 레코드가 DNS에 정상 반영되어야 한다.
ACM Certificate 생성
→ DNS validation record 생성
→ DNS 반영
→ Certificate issued 상태
Route53을 사용하면 Terraform으로 자동화할 수 있지만, 외부 DNS를 사용한다면 수동 작업이 필요할 수 있다.
5. Attach 단계에서 발생하는 문제
Attach 단계는 리소스 간 연결이 이루어지는 단계다.
이 단계는 Terraform에서 가장 헷갈리기 쉬운 영역이다.
왜냐하면 어떤 연결은 Terraform resource 안의 block으로 표현되고, 어떤 연결은 별도의 resource로 표현되며, 어떤 연결은 CI/CD나 AWS CLI에서 처리하는 편이 더 안전할 수 있기 때문이다.
5.1 ECS Service와 Target Group
ECS Service는 Cluster와 Task Definition이 있으면 생성할 수 있다.
resource "aws_ecs_service" "app" {
name = "app-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = 0
}
하지만 외부 요청을 받으려면 Target Group과 연결되어야 한다.
load_balancer {
target_group_arn = aws_lb_target_group.app.arn
container_name = "app"
container_port = 8080
}
여기서 Target Group이 아직 준비되지 않았거나, ALB Listener 구성이 맞지 않거나, Health Check 경로가 잘못되면 ECS Service는 생성되어도 정상 서비스가 되지 않는다.
따라서 처음에는 desired_count = 0으로 두고, 연결이 끝난 뒤 CI/CD에서 scale up 하는 방식을 고려할 수 있다.
5.2 Lambda와 EventBridge
Lambda와 EventBridge도 연결이 필요하다.
EventBridge Rule이 Lambda를 호출하려면 Lambda Permission이 필요하다.
resource "aws_lambda_permission" "allow_eventbridge" {
statement_id = "AllowExecutionFromEventBridge"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.worker.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.schedule.arn
}
Lambda 함수와 EventBridge Rule이 존재하더라도, Permission이 없으면 EventBridge는 Lambda를 호출할 수 없다.
즉, 리소스 존재와 실행 가능한 연결 상태는 다르다.
5.3 WAF와 CloudFront
WAF도 CloudFront에 연결되어야 실제로 동작한다.
WAF Web ACL이 존재한다고 해서 자동으로 트래픽을 검사하는 것은 아니다. CloudFront Distribution에 연결되어야 한다.
WAF Web ACL 생성
→ CloudFront Distribution에 연결
→ 트래픽 검사 시작
삭제할 때도 반대로 진행해야 한다.
CloudFront에서 WAF 연결 해제
→ CloudFront Deployed 대기
→ WAF 삭제
6. Activate 단계에서 발생하는 문제
Activate 단계는 실제 실행이 시작되는 시점이다.
이 단계에서는 Terraform 코드만으로는 알기 어려운 런타임 문제가 드러난다.
6.1 ECS desired_count
ECS Service의 desired_count는 실행 중인 Task 수를 의미한다.
Terraform에서 바로 desired_count = 2로 설정할 수도 있다.
resource "aws_ecs_service" "app" {
name = "app-service"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = 2
}
하지만 초기 배포에서는 다음 문제가 발생할 수 있다.
이미지 pull 실패
환경 변수 오류
Secret 참조 실패
DB 연결 실패
Health Check 실패
그래서 인프라 생성 단계에서는 desired_count = 0으로 두고, 배포 파이프라인에서 정상 조건을 확인한 뒤 scale up 하는 방식을 사용할 수 있다.
aws ecs update-service \
--cluster app-cluster \
--service app-service \
--desired-count 2
6.2 Scheduler 활성화
EventBridge Scheduler나 Rule도 비슷하다.
리소스는 생성했지만, 바로 활성화하면 준비되지 않은 Lambda나 ECS Task를 호출할 수 있다.
따라서 다음 흐름이 더 안전할 수 있다.
1. Lambda 생성
2. 필요한 Secret / Parameter 준비
3. EventBridge 연결
4. Scheduler 활성화
6.3 트래픽 유입
트래픽 유입도 Activate 단계로 볼 수 있다.
예를 들어 Route53 Record를 생성해서 사용자의 요청이 ALB나 CloudFront로 들어가기 시작하면, 그때부터 실제 서비스 장애가 드러난다.
Route53 Record 생성
→ 트래픽 유입
→ ALB Health Check
→ ECS Task 응답
→ 실제 서비스 확인
즉, 트래픽 연결은 단순 DNS 설정이 아니라 서비스 활성화 단계에 가깝다.
7. Terraform State는 어디까지 알고 있을까?
Terraform State는 Terraform이 현재 인프라를 어떻게 바라보고 있는지를 저장하는 파일이다.
State에는 다음 정보가 저장된다.
리소스 ID
리소스 속성
참조 관계
Terraform이 관리하는 현재 상태
Terraform은 state를 기준으로 plan을 생성한다.
현재 코드
+ 현재 state
= 변경 계획(plan)
하지만 State가 실제 인프라의 모든 상태를 의미하지는 않는다.
State는 다음 질문에 잘 답한다.
이 리소스가 존재하는가?
이 리소스의 ID는 무엇인가?
이 리소스의 속성은 무엇인가?
어떤 리소스를 참조하는가?
하지만 다음 질문에는 약하다.
RDS에 실제 접속 가능한가?
CloudFront 배포가 끝났는가?
ECS Task가 정상적으로 실행 중인가?
ALB Target이 healthy인가?
외부 DNS가 전파되었는가?
따라서 다음과 같이 구분하는 것이 좋다.
State = Terraform이 바라보는 정적 상태
Runtime = 실제 인프라의 동적 상태
State에 리소스가 있다는 것과 서비스가 정상 동작한다는 것은 다르다.
8. Destroy도 같은 관점으로 봐야 한다
이 개념은 생성뿐 아니라 삭제에서도 중요하다.
리소스를 삭제할 때는 단순히 terraform destroy만 생각하기 쉽다.
하지만 실제로는 다음 흐름이 더 정확하다.
Deactivate → Detach → Destroy
8.1 Deactivate
먼저 실행 중인 기능을 중단한다.
ECS desired_count = 0
Scheduler disable
트래픽 차단
8.2 Detach
그 다음 연결을 해제한다.
CloudFront에서 WAF 해제
ECS Service에서 Target Group 연결 해제
Lambda Permission 정리
Route53 Record 제거
8.3 Destroy
마지막으로 리소스를 삭제한다.
이 순서를 지키지 않으면 다음과 같은 오류가 발생할 수 있다.
resource is in use
resource is associated with another resource
cannot delete because it is managed by another service
즉, 삭제에서도 핵심은 리소스 자체보다 연결 관계다.
9. CI/CD에서는 어떻게 다뤄야 할까?
Terraform만으로 모든 것을 해결하려고 하면 복잡해질 수 있다.
그래서 Terraform과 CI/CD의 역할을 나누는 것이 좋다.
Terraform → Create / Destroy
CI/CD → Ready / Attach / Activate
예를 들어 GitHub Actions에서는 다음과 같은 흐름을 만들 수 있다.
1. terraform plan
2. terraform apply
3. ready check
4. attach
5. activate
예시는 다음과 같다.
terraform apply
→ RDS available 확인
→ CloudFront deployed 확인
→ ECS Service 연결 확인
→ desired_count 증가
→ Health Check 확인
이렇게 나누면 Terraform은 인프라 구조 생성에 집중하고, CI/CD는 실제 서비스가 동작 가능한 상태인지 확인하는 역할을 담당할 수 있다.
특히 다음 설정들은 Terraform보다 CI/CD 또는 운영 자동화에서 관리하는 것이 더 자연스러울 수 있다.
ECS desired_count
Scheduler enable / disable
배포 직후 smoke test
Health check
트래픽 전환
10. 마무리
Terraform에서 apply가 성공했다는 것은 중요한 의미를 가진다.
하지만 그것이 곧 서비스가 정상 동작한다는 의미는 아니다.
실제 인프라는 다음 흐름을 거쳐 완성된다.
Create → Ready → Attach → Activate
Terraform은 주로 Create와 State 관리에 강하다. 하지만 Ready, Attach, Activate는 실제 운영과 CI/CD에서 함께 고려해야 한다.
이 차이를 이해하면 다음 문제들을 더 명확하게 바라볼 수 있다.
apply 성공 후 서비스 실패
CloudFront 배포 대기
RDS 접속 실패
ECS Health Check 실패
destroy 시 리소스 in use 오류
결국 Terraform을 제대로 사용하려면 리소스를 생성하는 것뿐 아니라, 리소스가 언제 준비되고, 언제 연결되고, 언제 실행되는지를 함께 이해해야 한다.
한 줄 정리
Terraform은 리소스를 만들지만, 시스템은 Phase를 거쳐 완성된다.
다음 글에서는 이 Phase 개념을 바탕으로, Terraform에서 자주 발생하는 순환 참조 문제를 어떻게 해결할 수 있는지 정리해본다.
'테라폼' 카테고리의 다른 글
| 3-3. 테라폼 - State는 왜 나눠야 할까? (2) | 2026.05.05 |
|---|---|
| 3-2. 테라폼 - 순환 참조는 왜 발생하고 어떻게 끊어야 할까? (0) | 2026.05.05 |
| 3-0. 테라폼 - 리소스의 분류 및 구현 (0) | 2026.05.05 |
| 2. 테라폼 - Terraform 프로젝트 구조 (0) | 2026.04.28 |
| 1. 테라폼 - 효율적인 클라우드 관리 (0) | 2026.04.22 |