- Published on
Terraform apply 멈춤 - AzureRM 120초 타임아웃
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
Terraform로 Azure 리소스를 배포하다 보면 terraform apply가 특정 단계에서 멈춘 것처럼 보이는 순간이 있습니다. CPU도 거의 안 쓰고, 출력도 안 나오고, 몇 분이 지나도 진행이 없는 상태. 그런데 자세히 보면 완전히 멈춘 게 아니라 AzureRM Provider가 Azure API 호출을 기다리거나 재시도하는 중인 경우가 많습니다.
특히 체감상 자주 등장하는 패턴이 **“120초(2분) 단위로 타임아웃/재시도”**가 반복되며 apply가 길어지는 상황입니다. 이 글에서는 다음을 목표로 합니다.
- 120초 타임아웃이 “어디서” 발생하는지(네트워크/인증/리소스별 Polling)
- Terraform/AzureRM Provider에서 타임아웃이 어떻게 구성되는지
- 재현과 진단(로그, Azure CLI, 네트워크 경로)
- 실전 해결책(타임아웃 조정, 기능 플래그, 네트워크/프록시, state 분리)
타임아웃 문제는 Azure뿐 아니라 네트워크/엔드포인트 의존성이 얽히면 어디서든 비슷한 양상으로 나타납니다. 스트리밍/HTTP 타임아웃을 체계적으로 추적하는 방법론은 OpenAI Responses API 스트리밍 끊김 타임아웃 완전 복구 가이드에서도 유사하게 적용할 수 있습니다.
증상: “멈춤”처럼 보이는 대표 로그 패턴
대개 아래 중 하나로 보입니다.
- 특정 리소스에서
Still creating...가 오래 지속 - 출력이 아예 멈추고, 일정 시간이 지나면 갑자기 진행
context deadline exceeded/i/o timeout/read: connection reset같은 네트워크성 에러- CI에서만 재현(로컬은 됨)
문제는 Terraform 출력만으로는 원인을 분리하기 어렵다는 점입니다. 그래서 첫 단계는 “진짜로 멈춘 게 맞는지(Deadlock)” vs “Azure API 호출 대기/재시도인지”를 구분하는 것입니다.
120초 타임아웃이 생기는 지점 3가지
AzureRM Provider의 동작은 크게 다음 흐름을 탑니다.
- Azure Resource Manager(관리 plane) API 호출
- 장기 작업(Long-running operation) Polling
- 결과를 읽고 state에 반영(Read)
여기서 120초는 보통 아래 케이스에서 체감됩니다.
1) HTTP 클라이언트/프록시/방화벽에서 120초에 끊김
회사 프록시, 방화벽, NAT 게이트웨이, L7 프록시가 idle timeout을 120초로 설정해두면, Azure API 응답이 느릴 때 연결이 끊기며 재시도가 발생합니다.
- CI 러너가 사설망에 있고 outbound가 제한적
- HTTPS inspection(SSL 가로채기)로 인해 TLS 핸드셰이크/세션이 불안정
- DNS가 간헐적으로 실패해 재시도(체감상 주기적)
Kubernetes에서도 비슷하게 “외부로 나가는 경로(NAT/PrivateLink/DNS)”가 꼬이면 STS 호출이 타임아웃나는 것처럼, AzureRM도 결국은 외부 API 의존입니다. 네트워크 경로 점검 관점은 EKS Pod STS AssumeRole 타임아웃 - NAT·PrivateLink·DNS의 체크리스트가 그대로 도움이 됩니다.
2) Azure API 자체 지연 + Provider Polling이 길어짐
Azure 리소스 중 일부는 생성/갱신이 오래 걸립니다.
azurerm_kubernetes_cluster(AKS)azurerm_private_endpointazurerm_firewall,azurerm_application_gatewayazurerm_role_assignment(권한 전파 지연)
이 경우 Terraform은 “멈춤”이 아니라 Azure가 완료될 때까지 Polling합니다. 다만 중간에 Read가 느리거나, Azure가 InProgress 상태를 오래 유지하면 체감이 큽니다.
3) 인증 토큰/권한/테넌트 문제로 재시도 루프
서비스 프린시플(SP)이나 OIDC Workload Identity로 인증할 때,
- 권한이 부족해 403이 나지만 메시지가 늦게 표출
- 테넌트/구독이 꼬여서 재시도
- Managed Identity 엔드포인트 접근 문제(특히 VM/Runner 환경)
이런 케이스는 TF_LOG=DEBUG에서 토큰 발급/ARM 호출이 어디서 막히는지 확인해야 합니다.
1단계: Terraform 로그로 “어디서” 120초가 도는지 찾기
가장 먼저 할 일은 로그를 켜서 막히는 리소스와 API 호출 종류를 특정하는 것입니다.
로컬에서 로그 활성화
export TF_LOG=INFO
export TF_LOG_PATH=./tf.log
terraform apply
더 깊게 보려면:
export TF_LOG=DEBUG
export TF_LOG_PATH=./tf-debug.log
terraform apply
로그에서 확인할 포인트:
- 어떤 리소스에서 멈추는지(리소스 주소)
HTTP Request/HTTP Response가 반복되는지context deadline exceeded가 어느 호출에서 나는지Retrying/Backoff가 있는지
> 팁: DEBUG는 민감정보가 포함될 수 있으니 CI 아티팩트로 올릴 때 마스킹/보관정책을 꼭 확인하세요.
2단계: Azure API 상태/리소스별 병목 진단
Azure CLI로 같은 작업이 느린지 확인
Terraform이 느린 게 아니라 Azure가 느린지 분리하려면 Azure CLI로 동일 리소스 조회가 지연되는지 확인합니다.
az account show
az group show -n <rg-name>
az resource list -g <rg-name> --query "[].{name:name,type:type}" -o table
AKS나 Private Endpoint처럼 오래 걸리는 리소스는 프로비저닝 상태를 직접 확인합니다.
az aks show -g <rg> -n <aks> --query "provisioningState" -o tsv
Azure Activity Log 확인
Azure Portal 또는 CLI로 Activity Log를 보면 “실제로 Azure가 작업을 진행 중인지”가 드러납니다.
az monitor activity-log list \
--resource-group <rg> \
--max-events 20 \
-o table
Activity Log에 이벤트가 쌓이고 있는데 Terraform만 멈춘 것처럼 보이면 Polling/Read 지연 가능성이 큽니다.
3단계: 네트워크(프록시/DNS/방화벽) 점검 체크리스트
120초 주기의 끊김은 네트워크 장비/프록시의 idle timeout에서 자주 나옵니다. 아래를 확인하세요.
필수 엔드포인트 접근
AzureRM Provider는 주로 다음으로 나갑니다.
https://management.azure.com/(ARM)https://login.microsoftonline.com/(AAD)
사설망 러너라면 DNS 해석/라우팅/방화벽에서 이 도메인이 안정적으로 나가는지 확인합니다.
# DNS 확인
nslookup management.azure.com
nslookup login.microsoftonline.com
# TLS/연결 지연 확인
curl -v https://management.azure.com/ 2>&1 | head -n 30
curl -v https://login.microsoftonline.com/ 2>&1 | head -n 30
프록시 환경 변수
조직 환경에서는 HTTPS_PROXY가 설정되어 있고, Terraform/Go HTTP 클라이언트가 이를 타는 경우가 많습니다.
env | egrep -i 'http_proxy|https_proxy|no_proxy'
- 프록시가 120초 idle timeout이면 장기 요청이 끊길 수 있음
NO_PROXY에management.azure.com등을 넣어 우회(가능한 경우)
해결책 1: 리소스별 timeouts로 생성/읽기 시간 늘리기
AzureRM Provider는 다수 리소스에서 timeouts 블록을 지원합니다. “120초”가 실제로 리소스별 타임아웃이라면 이게 가장 정공법입니다.
예: Private Endpoint가 느릴 때
resource "azurerm_private_endpoint" "pe" {
name = "pe-example"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
subnet_id = azurerm_subnet.snet.id
private_service_connection {
name = "psc"
private_connection_resource_id = azurerm_storage_account.sa.id
subresource_names = ["blob"]
is_manual_connection = false
}
timeouts {
create = "60m"
read = "10m"
update = "60m"
delete = "60m"
}
}
예: Role Assignment 전파 지연이 잦을 때
resource "azurerm_role_assignment" "ra" {
scope = azurerm_resource_group.rg.id
role_definition_name = "Reader"
principal_id = azuread_service_principal.sp.object_id
timeouts {
create = "30m"
}
}
핵심은 “apply가 멈춘 지점”이 어떤 리소스인지를 먼저 특정하고, 그 리소스에만 timeouts를 늘리는 것입니다.
해결책 2: Provider/Backend 버전 고정과 업그레이드 전략
AzureRM Provider는 버전에 따라 Polling/Retry 로직이 달라지거나 특정 리소스에서 타임아웃 버그가 수정되기도 합니다.
terraform {
required_version = ">= 1.6.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.110" # 예시: 팀에서 검증된 버전으로 고정
}
}
}
provider "azurerm" {
features {}
}
- 무작정 최신으로 올리기보다: 현재 버전 → 릴리즈 노트 확인 → 스테이징에서 apply 검증
- CI/로컬에서 버전이 다르면 재현이 어려우니
.terraform.lock.hcl을 커밋하고 동일하게 맞추세요.
해결책 3: “멈춤” 리소스를 분리 적용(의존성/병렬성 제어)
Azure에서 특정 리소스가 오래 걸리면 전체 그래프가 대기합니다. 특히 네트워크/권한/AKS 같은 큰 리소스는 별도 단계로 분리하면 장애 반경이 줄어듭니다.
- 네트워크(Subnet/NSG/Route) → Private Endpoint/DNS → AKS 순으로 분리
-target은 응급처치로만 사용하고, 장기적으로는 모듈/워크스페이스 분리 권장
예: 모듈 분리
module "network" {
source = "./modules/network"
}
module "aks" {
source = "./modules/aks"
subnet_id = module.network.aks_subnet_id
depends_on = [module.network]
}
해결책 4: CI 러너 환경(특히 사설망)에서 자주 놓치는 것
시간 동기화/CA 번들/SSL inspection
- 러너의 시간이 틀어지면 AAD 토큰/HTTPS 검증이 불안정해질 수 있음
- 사내 CA가 필요한데 러너 이미지에 CA가 없으면 TLS 에러/재시도
DNS 품질
간헐적인 DNS 실패는 “가끔 2분씩 멈춤” 같은 형태로 나타납니다. 쿠버네티스에서 CoreDNS 이슈가 업스트림 타임아웃으로 번지는 것처럼, 기본 DNS가 불안정하면 모든 외부 API가 흔들립니다. 비슷한 진단 관점은 EKS CoreDNS CrashLoopBackOff - upstream 타임아웃 해결도 참고할 만합니다.
실전 디버깅 루틴(재현 가능한 체크리스트)
아래 순서대로 하면 “감”이 아니라 “증거”로 원인을 좁힐 수 있습니다.
TF_LOG=INFO로 멈추는 리소스 주소 특정TF_LOG=DEBUG로 실제 막히는 API 호출/재시도 확인- 같은 시점에 Azure Activity Log로 Azure 작업 진행 여부 확인
- 러너/로컬에서
curl/nslookup로management.azure.com,login.microsoftonline.com경로 확인 - 프록시/방화벽/NO_PROXY 정책 확인(특히 120초 idle timeout)
- 해당 리소스에
timeouts추가(필요 최소로) - Provider 버전 고정/업데이트로 알려진 이슈 회피
- 큰 리소스(네트워크/AKS/PE/권한)를 모듈로 분리해 apply 단위를 줄임
결론
Terraform apply가 120초 단위로 멈춘 것처럼 보이면, 대개는 다음 중 하나입니다.
- 네트워크(프록시/방화벽/NAT/DNS)에서 120초 idle timeout으로 연결이 끊겨 재시도
- Azure의 장기 작업이 느려 Polling이 길어짐(특정 리소스에서 두드러짐)
- 인증/권한 문제로 ARM/AAD 호출이 지연되거나 재시도
가장 중요한 건 “어느 리소스의 어느 호출이 120초에 걸리는지”를 로그로 특정하는 것입니다. 그 다음에야 timeouts 조정, 네트워크 경로 개선, provider 버전 전략 같은 처방이 정확해집니다.
원하시면 실제 TF_LOG 일부(민감정보 제거)와 멈추는 리소스 종류(AKS/Private Endpoint/Role Assignment 등)를 알려주시면, 그 케이스에 맞춰 timeouts 값과 네트워크 점검 포인트를 더 구체적으로 제안하겠습니다.