광고
~ / posts / developer
smith@lab:~/posts$ cat developer/terraform-parallelism-depends-on-create-before-destroy-guide.md

테라폼 parallelism 값 고르는 법, depends_on·create_before_destroy 판단표

terraform apply가 느려서 -parallelism=50을 붙여 볼지, 순서가 불안해서 depends_on을 여기저기 걸어 둘지 고민될 때가 있어요. 결론부터 말하면 parallelism은 기본값 10을 그대로 두고, 느리면 먼저 그래프가 긴 사슬인지 보고, 순서는 속성 참조로 드러내고 depends_on은 값이 오가지 않는 숨은 의존에만 써요. 교체 때 끊김이 문제라면 create_before_destroy를 켜되, 이 설정이 의존 대상 리소스에도 번진다는 점을 먼저 따져요.

이 글은 그래프가 어떻게 걸리는지보다 "그래서 어떤 값을 언제 고르나"를 다뤄요. 테라폼 1.9.8에서 네트워크를 쓰지 않는 내장 리소스 terraform_data로 직접 잰 실행 시간, 설정별 판단표, 운영에서 자주 나는 문제의 확인 순서를 정리했어요.

광고

parallelism 값 판단표 — 언제 바꾸나

terraform apply 명령 문서에 적힌 -parallelism=n의 뜻은 "그래프를 걸을 때 동시에 진행하는 작업 수 제한, 기본 10"이에요. 이 값은 리소스 종류별이 아니라 실행 한 번 전체에 걸려요. 상황별로 고르면 이래요.

지금 상황고를 값이렇게 고르는 이유
특별한 문제 없음지정하지 않음(10)문서가 일반 사용에는 필요 없다고 해요
로그가 뒤섞여 어디서 멈췄는지 모르겠음일시적으로 1한 번에 한 노드만 돌아 로그가 한 줄로 서요. 순서는 그대로예요
서로 기대지 않는 리소스가 수백 개이고 느림20~30 정도로 올려 재 보기넓은 그래프에서만 효과가 있어요. 올린 뒤 스로틀링 오류가 늘면 되돌려요
Throttling·Rate exceeded가 남10 유지, 프로바이더 재시도 설정 조정문서가 속도 제한은 프로바이더 API 클라이언트가 처리한다고 적어요
실행 머신 CPU·메모리가 빠듯함10보다 낮게세마포어의 원래 목적이 실행 머신 보호예요
apply가 느린데 리소스가 줄줄이 이어짐값 대신 그래프 손보기사슬은 값을 올려도 안 빨라져요(아래 측정)

Resource Graph 문서는 동시 처리 수를 세마포어로 묶는 이유를 "테라폼을 돌리는 머신의 자원을 압도하지 않으려고"라고 설명해요. 그리고 AWS 같은 프로바이더는 더 아래 단계에서 물러섰다 다시 시도하는 방식으로 속도 제한을 다루므로, 테라폼은 이 기능을 속도 제한 해결에 직접 쓰지 않는다고 덧붙여요. AWS 프로바이더라면 프로바이더 설정 문서의 max_retries(스로틀링·일시 오류 때 재시도 횟수)와 retry_mode를 먼저 봐요.

CI에서 값을 고정하고 싶다면 명령마다 붙이는 대신 환경 변수 문서의 TF_CLI_ARGS_apply="-parallelism=20"처럼 명령별 변수에 넣을 수 있어요.

숫자로 보는 parallelism 효과 — 넓은 그래프

값을 바꿨을 때 실제로 얼마나 달라지는지 쟀어요. 서로 의존하지 않는 terraform_data 30개에 각각 sleep 1을 거는 프로비저너를 달아, API 호출 하나가 1초 걸리는 상황을 흉내 냈어요. Apple Silicon 맥, 테라폼 1.9.8에서 값마다 두 번씩 apply한 평균이에요.

독립 리소스 30개(각 1초) apply 시간 — parallelism 값별
측정값이론 하한
0102030401 · 측정값 37.2초1 · 이론 하한 30초15 · 측정값 7.8초5 · 이론 하한 6초510 · 측정값 4.1초10 · 이론 하한 3초1015 · 측정값 3초15 · 이론 하한 2초1520 · 측정값 3초20 · 이론 하한 2초2030 · 측정값 1.9초30 · 이론 하한 1초30

15와 20이 같은 것은 둘 다 두 묶음(15+15, 20+10)이 필요해서예요. 나머지 1초 안팎은 테라폼 자체 처리 시간이에요.

단위: 초 · 자료: 테라폼 1.9.8 · terraform_data + local-exec sleep 1 · 두 번 실행 평균으로 직접 측정. 이론 하한은 ⌈30 ÷ 값⌉ × 1초
표로 보기
구분측정값이론 하한
137.230
57.86
104.13
1532
2032
301.91

읽을 점이 두 가지예요. 첫째, 이론 하한은 ⌈리소스 수 ÷ 값⌉ × 한 작업 시간이라 값을 올릴수록 효과가 계단식으로 줄어요. 둘째, 10에서 30으로 올려 아낀 시간은 2.2초인데 같은 순간 API 요청은 세 배가 돼요. 실제 클라우드에서는 이 요청 폭이 속도 제한에 먼저 닿아요.

같은 순간 나가는 요청 수는 어림할 수 있어요. 한 작업이 평균 L초 동안 요청을 하나씩 낸다면 초당 요청 수의 상한은 대략 값 ÷ L이에요. 생성 요청 하나에 0.2초가 걸린다면 10은 초당 50건, 30은 초당 150건이에요. 이 계산은 예시이고 실제 한도는 클라우드 서비스마다 달라요.

긴 사슬은 parallelism으로 못 줄여요

이번엔 리소스 6개를 c1 → c2 → … → c6처럼 앞 리소스의 id를 참조하게 이어서 같은 실험을 했어요.

6단 사슬 vs 독립 30개 — parallelism 값별 apply 시간
6단 사슬(각 1초)독립 30개(각 1초)
010203040parallelism 1 · 6단 사슬(각 1초) 7.7초parallelism 1 · 독립 30개(각 1초) 37.2초parallelism 1parallelism 10 · 6단 사슬(각 1초) 7.7초parallelism 10 · 독립 30개(각 1초) 4.1초parallelism 10parallelism 30 · 6단 사슬(각 1초) 7.7초parallelism 30 · 독립 30개(각 1초) 1.9초parallelism 30

사슬은 값과 상관없이 6초 + 처리 시간이 걸렸어요. 앞 노드가 끝나야 다음이 시작되니 동시에 돌 노드가 늘 하나뿐이에요.

단위: 초 · 자료: 테라폼 1.9.8 · terraform_data + local-exec sleep 1 · 두 번 실행 평균으로 직접 측정
표로 보기
구분6단 사슬(각 1초)독립 30개(각 1초)
parallelism 17.737.2
parallelism 107.74.1
parallelism 307.71.9

apply 전체 시간의 하한은 가장 긴 의존 경로(임계 경로)에 놓인 작업 시간의 합이에요. 실무에서 흔한 사슬은 이래요. VPC → 서브넷 → 데이터베이스 서브넷 그룹 → 데이터베이스 인스턴스 → 읽기 전용 복제본 → DNS 레코드. 데이터베이스처럼 한 단계에 몇 분씩 걸리는 리소스가 사슬 중간에 있으면 parallelism을 아무리 올려도 그 몇 분은 그대로 남아요.

사슬을 짧게 만드는 방법은 두 가지예요.

terraform graph로 DOT 출력을 뽑아 보면 사슬 길이를 눈으로 확인할 수 있어요. terraform graph 명령 문서에 따르면 옵션 없이 돌리면 리소스만 남긴 단순한 그래프가 나와요.

depends_on을 걸지 말지 — 판단표

의존성을 어떻게 표현할지 고르는 순서도. 다른 리소스의 값을 쓰면 속성 참조, 값은 안 쓰지만 동작에 기대면 그 리소스 하나에만 depends_on, 모듈 전체에 거는 depends_on은 가장 마지막, 순서가 아니라 함께 교체가 목적이면 replace_triggered_by로 간다
위에서부터 물어보고 처음 '예'가 나오는 칸을 골라요

depends_on 문서는 이 기능을 최후의 수단으로 쓰라고 적어요. 테라폼이 위쪽 객체에 어떤 변화가 생길지 확신하지 못해 더 많은 값을 (known after apply)로 두고, 그래서 필요보다 많은 리소스를 교체하는 보수적인 계획을 만들 수 있다는 이유예요. 모듈에 걸 때 특히 그렇다고 해요.

이게 실제로 어떻게 보이는지 확인했어요. upstream 리소스가 교체되는 상황에서, 그와 값으로는 상관없는 데이터 소스에 depends_on = [terraform_data.upstream]을 걸고 그 데이터 소스 값을 app이 쓰게 했어요.

데이터 소스 설정plan 결과
depends_on 있음데이터 소스가 "read during apply"로 밀리고, app도 값이 unknown이 돼 교체. 2 to add, 2 to destroy
depends_on 없음upstream만 교체. 1 to add, 1 to destroy

같은 코드에서 한 줄 차이로 교체 대상이 둘로 늘었어요. 두 plan 출력을 텍스트 비교 도구에 나란히 붙이면 depends_on을 넣고 뺐을 때 늘어난 줄을 바로 찾을 수 있어요.

그래서 남기는 기준은 이래요.

상황판단
IAM 정책이 붙어야 인스턴스 안 프로그램이 동작함(값은 안 읽음)depends_on 유지. 문서가 드는 대표적인 숨은 의존이에요
다른 리소스의 ID·이름을 실제로 씀지우기. 참조가 이미 순서를 만들어요
"혹시 몰라서" 걸어 둠지우고 plan 비교. 순서 오류가 나면 그때 그 리소스 하나에만 다시 걸어요
모듈 블록에 걸어 둠모듈 안 리소스 하나에 걸거나, 필요한 출력을 참조로 바꿔요
다른 리소스가 바뀔 때 이것도 새로 만들어야 함depends_on이 아니라 lifecycle의 replace_triggered_by

create_before_destroy 켤지 말지

교체가 필요한 변경에서 기본 순서는 옛 객체를 지운 뒤 새 객체를 만드는 거예요. lifecycle 문서의 create_before_destroy를 켜면 새 객체를 먼저 만들고 옛 객체를 나중에 지워요. 문서는 이 설정이 의존 대상 리소스 전체에 전파된다고 적어요. A가 B에 기대고 A에만 켰어도 B가 교체될 때 B 역시 먼저 만들고 나중에 지워요. B에 false를 적어 끌 수도 없어요.

직접 확인한 결과도 같았어요. A에만 켜고 B를 교체하자 plan 머리말이 +/- create replacement and then destroy로 나왔고, apply 순서는 B 생성 → A 생성 → A의 옛 객체(deposed) 삭제 → B의 옛 객체 삭제였어요.

리소스 성격판단확인할 것
이름을 자동 생성(name_prefix 지원)켜기 좋음name 대신 name_prefix를 써서 두 벌이 공존할 수 있게 해요
이름·도메인·포트처럼 유일해야 하는 값 고정그대로 켜면 충돌이름에 버전·랜덤 접미사를 넣거나 켜지 않아요
교체 중 잠깐 끊겨도 되는 개발 환경기본값 유지리소스가 두 벌 생기는 비용이 없어요
앞단에 트래픽을 받는 리소스(인증서·시작 템플릿 등)켜는 쪽 검토이 리소스가 기대는 리소스까지 전부 공존 가능한지 봐요
삭제 때 실행하는 프로비저너가 있음켜면 그 프로비저너가 안 돌아요문서에 적힌 제약이에요. 정리 작업을 다른 방법으로 옮겨요

전파 때문에 생기는 문제는 대개 켠 리소스가 아니라 그 아래 리소스에서 나요. 켜기 전에 terraform graph로 그 리소스가 기대는 리소스 목록을 뽑고, 각각이 이름 충돌 없이 두 벌 존재할 수 있는지 하나씩 확인해요.

광고
광고

운영에서 자주 나는 문제와 확인 순서

apply 중 오류 뒤 일부만 생성됨, Cycle 오류, 교체 시 이름 이미 존재 오류, 스로틀링 오류, apply가 늘 느림, 바뀔 이유 없는 리소스 교체 여섯 증상별로 먼저 볼 것과 조치를 정리한 점검표
증상 줄을 찾아 가운데 칸부터 확인해요

1. apply가 오류로 끝났는데 일부 리소스는 만들어졌어요. 정상 동작이에요. 실패한 노드에 기대는 노드만 건너뛰고, 상관없는 가지는 끝까지 진행돼요. 리소스 둘 중 하나의 프로비저너를 실패시켜 본 실험에서 성공한 쪽과 그 아래 3개는 만들어졌고, 실패한 쪽 아래 리소스만 생기지 않았어요. 실패한 리소스는 상태에 남되 tainted로 표시돼 다음 plan에서 is tainted, so must be replaced로 다시 만들어져요. 그러니 오류가 나면 콘솔에서 손으로 지우지 말고, 원인을 고친 뒤 plan으로 남은 작업만 확인하고 다시 apply해요.

2. Error: Cycle: A, B가 나요. 두 리소스가 서로의 값을 참조하는 경우예요. 대표 예는 보안 그룹 두 개가 인라인 규칙으로 서로를 가리키는 경우예요. 규칙을 별도 리소스로 빼면 그룹 둘이 먼저 만들어지고 규칙이 나중에 붙어 고리가 끊겨요. 고리를 그림으로 보려면 terraform graph -type=plan -draw-cycles를 써요. graph 문서에 따르면 -draw-cycles는 -type과 함께 써야 해요.

3. 교체할 때 "이미 존재합니다" 오류가 나요. create_before_destroy가 직접 켜졌거나 전파돼서 새 객체를 옛 객체와 같은 이름으로 만들려는 거예요. plan 머리말이 +/-인지 확인하고, 이름 고정 리소스에 접두사·접미사를 넣어요.

4. 스로틀링 오류가 나요. 먼저 프로바이더의 재시도 설정을 늘려요. 그래도 나면 parallelism을 낮추되, 같은 계정·리전에 동시에 도는 다른 파이프라인이 있는지도 봐요. 한도는 계정 단위로 걸리는 경우가 많아서 파이프라인 두 개가 각자 10이면 실제로는 20이에요.

5. apply가 늘 느려요. parallelism을 1로 한 번 돌려 노드별 Creation complete after Ns 시간을 모으고, 가장 긴 사슬 위에 오래 걸리는 리소스가 있는지 봐요. 사슬이 원인이면 값을 올려도 소용없어요.

6. 바꾼 적 없는 리소스가 교체 계획에 올라와요. 그 리소스 쪽 줄에 (known after apply)와 # forces replacement가 있는지 보고, 그 값이 어느 데이터 소스나 모듈에서 오는지 거슬러 올라가요. 중간에 depends_on이 걸려 있으면 위 판단표로 지울 수 있는지 따져요.

도입 전에 따질 것

테라폼을 여러 팀이 같이 쓰기 전에 그래프와 병렬 실행 관점에서 정해 둘 것들이에요.

광고
광고

자주 묻는 질문

parallelism을 100으로 올리면 apply가 10배 빨라지나요?

독립 리소스가 100개 이상이고 각각 오래 걸릴 때만 그 근처까지 빨라져요. 측정에서 30개를 10에서 30으로 올리자 4.1초가 1.9초가 됐지만, 6단 사슬은 1이든 30이든 7.7초였어요. 실제 클라우드에서는 요청이 몰려 스로틀링 재시도가 늘면서 오히려 느려질 수도 있어요.

count로 만든 리소스 100개는 parallelism을 하나만 쓰나요?

아니에요. 인스턴스마다 노드가 따로 생기고 각자 자리 하나씩을 써요. 기본값 10이면 100개가 열 개씩 진행돼요. 그래서 큰 count나 for_each가 있는 설정에서 값의 효과가 가장 크게 보여요.

depends_on을 지웠다가 순서가 틀어지면 어떻게 알 수 있나요?

값을 참조하는 의존은 지워도 순서가 유지되니 plan 결과가 같아요. 순서가 정말 필요한 숨은 의존이었다면 apply 중 "권한 없음"이나 "찾을 수 없음" 같은 오류로 드러나요. 스테이징에서 먼저 확인하고, 그 리소스 하나에만 다시 걸어요.

create_before_destroy는 한번 켰다 끄면 바로 원래대로 돌아가나요?

lifecycle 문서에 따르면 lifecycle 규칙 가운데 create_before_destroy만 상태에 기록돼요. 테라폼 1.9.8에서 위 실험의 lifecycle 줄을 지우고 다시 교체하자 plan 머리말이 곧바로 -/+ destroy and then create replacement로 바뀌었어요. 다만 그 리소스에 기대는 다른 리소스에 이 설정이 켜져 있으면 전파 때문에 계속 먼저 만들어지니, 끈 뒤 첫 교체는 머리말을 확인하고 적용해요.

정리

더 깊이 읽기

이 글은 실무에서 판단할 때 필요한 것 위주로 정리했어요. 같은 주제의 내부 동작 원리는 devboi 기술 블로그의 테라폼 의존성 그래프와 병렬 실행 원리 — parallelism에서 도식과 코드로 단계별로 풀었어요.

참고한 자료

#terraform parallelism#테라폼 병렬 실행#depends_on 언제 쓰나#create_before_destroy#known after apply#테라폼 apply 느림#테라폼 의존성#Cycle 오류
← 이전 글tar 압축 해제 보안, 경로 순회·링크 탈출·파서 해석 차이 막는 법다음 글 →Testcontainers 수명 고르는 법, CI 시간과 커넥션 한도 계산
광고

더 둘러보기

💻 개발자 다른 도구

🔥 많이 찾는 도구

🔮 재미로 한 번 더

📝 읽어 볼 만한 글

글 전체 보기 →