terraform provider 공유 캐시 - 7GB가 44KB가 되기까지
맥북 용량이 부족해서 du -sh로 /projects 아래를 한 칸씩 내려가 봤다.
node_modules가 범인일 줄 알았다.
그런데 제일 큰 게 전부 terraform 디렉토리였다.
1. 뭐가 이렇게 클까?
.terraform 디렉토리를 모아서 재 봤다.
763M ****/infra-serving/.terraform
648M ****/terraform/.terraform
782M ****/infra/.terraform
826M ****/infra/shared/.terraform
791M ****/infra/envs/prod/.terraform
1.5G ****/infra/envs/dev/.terraform
774M ****/infra/modules/secrets/.terraform
774M ****/infra/modules/ecs/.terraform
...
한 개에 800MB 가까이 된다.
안을 파 보니 거의 전부 파일 하나였다.
.terraform/providers/registry.terraform.io/hashicorp/aws/6.47.0/darwin_arm64/
terraform-provider-aws_v6.47.0_x5 782M
AWS provider 바이너리다.
왜 이렇게 클까?
provider는 Go로 빌드한 단일 바이너리다.
AWS provider는 수백 개 AWS 서비스의 SDK 클라이언트를 전부 정적 링크해서 들고 있다.
ECS 하나만 쓰든 S3 하나만 쓰든 상관없다. 통째로 받는다.
그리고 디렉토리마다 따로 받는다
terraform init은 기본적으로 그 디렉토리의 .terraform/ 안에 provider를 내려받는다.
공유하지 않는다.
그래서 레포 하나에 같은 aws 6.45.0이 다섯 벌 있었다.
infra/sharedinfra/envs/prodinfra/envs/devinfra/modules/ecs← 모듈인데?infra/modules/secrets← 이것도?
모듈 디렉토리 둘은 backend도 없는 그냥 모듈이다.
언젠가 거기서 init을 한 번 쳐서 생긴 흔적 같다.
envs/dev가 1.5GB인 건 aws가 두 버전(6.45.0, 6.53.0) 있어서였다.
lock 파일엔 6.45.0만 있다. 6.53.0은 올렸다가 되돌린 잔재였던 것 같다...
.terraform/은 캐시다. 지워도init으로 다시 만들어진다.
그런데 캐시가 디렉토리 수만큼 복제되고 있었다.
2. pnpm 같은 게 있다?
terraform에도 전역 캐시 설정이 있다. 몰랐다.
# ~/.terraformrc
plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"
이걸 켜면 이렇게 바뀐다.
~/.terraform.d/plugin-cache/
registry.terraform.io/hashicorp/aws/6.45.0/darwin_arm64/ ← 실제 파일 (한 벌)
****/infra/envs/dev/.terraform/providers/.../aws/6.45.0/
darwin_arm64 -> ~/.terraform.d/plugin-cache/.../aws/6.45.0/darwin_arm64 ← 링크
전역 저장소에 버전별로 한 벌 두고, 프로젝트엔 링크만 건다.
pnpm의 content-addressable store랑 같은 발상이다.
(pnpm은 하드링크, terraform은 버전 디렉토리 단위 심볼릭 링크라는 차이는 있다.)
주의할 점이 둘 있다.
- 캐시 디렉토리는 직접 만들어야 한다. 없으면 terraform이 만들어 주지 않는다.
mkdir -p먼저. - 이미 받아 둔
.terraform에는 소급 적용되지 않는다. 지우고 다시init해야 링크로 바뀐다.
그리고 lock 파일과의 관계.
Terraform 1.4부터는 .terraform.lock.hcl에 그 provider의 해시가 이미 있을 때만 캐시를 쓴다고 알고 있다.
lock에 없는 새 provider를 추가하면 그때 한 번은 평소처럼 받는다.
(문서에서 이 부분을 직접 찾진 못했다. 우리 레포들은 lock이 전부 커밋되어 있어서 걸릴 일이 없었다.)
3. 적용
대상은 내가 terraform을 직접 만지는 쪽 셋으로 좁혔다.
순서는 이렇게 잡았다.
~/.terraformrc생성 + 캐시 디렉토리 생성- 루트 모듈 6곳에서
.terraform/providers/만 삭제- backend 설정이 든
.terraform/terraform.tfstate,modules/는 남긴다
- backend 설정이 든
- 각 루트에서
terraform init -lockfile=readonly-lockfile=readonly: lock 파일이 바뀌지 않게 막는다. git diff가 안 생긴다
- 모듈 디렉토리 두 곳은
.terraform/통째로 삭제, 다시 init 안 함
3-1. 첫 번째 실수 - zsh는 단어를 안 쪼갠다
ROOTS="a/infra b/infra c/infra"
for p in $ROOTS; do ... done
루프가 한 번만 돌았다.
bash라면 $ROOTS가 공백으로 쪼개지는데, zsh는 기본적으로 안 쪼갠다."a/infra b/infra c/infra"라는 존재하지 않는 경로 하나로 돌았고, 다행히 아무것도 안 지워졌다.
ROOTS=(a/infra b/infra c/infra) # 배열로
rm -rf가 들어간 루프에서 이러면 식은땀이 난다.
zsh에서 목록은 배열로 쓴다.
3-2. 두 번째 실수 - -backend=false는 backend를 안 보는 게 아니었다
처음엔 -backend=false를 붙였다.
provider만 다시 받으면 되니까, S3에 접속할 필요가 없을 거라고 생각했다.
Error: Error refreshing state: Unable to access object
"envs/dev/terraform.tfstate" in S3 bucket "...":
operation error S3: HeadObject, https response error StatusCode: 403
6곳 전부 403.
-backend=false는 "backend를 새로 초기화하지 않는다"는 뜻이었다.
이미 init된 디렉토리에서는 .terraform/terraform.tfstate에 저장된 backend 설정을 그대로 불러오고,
state를 읽으려고 S3에 간다.
4. 결과
init 출력이 이렇게 바뀌었다.
===== ****/infra
- Installing hashicorp/aws v6.47.0... ← 처음 한 번만 다운로드
===== ****/infra/shared
- Using hashicorp/aws v6.47.0 from the shared cache directory
===== ****/infra/shared
- Installing hashicorp/aws v6.45.0... ← 버전이 달라서 한 번
===== ****/infra/envs/prod
- Using hashicorp/aws v6.45.0 from the shared cache directory
===== ****/infra/envs/dev
- Using hashicorp/aws v6.45.0 from the shared cache directory
from the shared cache directory가 보이면 성공이다.
$ ls -l .../aws/6.45.0/
darwin_arm64 -> /Users/eunoh/.terraform.d/plugin-cache/.../aws/6.45.0/darwin_arm64
| 전 | 후 | |
|---|---|---|
세 레포의 .terraform 합계 |
6.9GB | 44KB |
| 공유 캐시 | - | 1.6GB |
| 실제 확보 | 약 5.3GB |
캐시에 남은 건 aws 6.45.0, 6.47.0 한 벌씩과 random, archive 정도다.
dev에 굴러다니던 6.53.0, shared의 tls 두 버전 같은 잔재는 lock에 없어서 다시 안 받아졌다.
정리하면서 청소까지 된 셈이다.
세 레포 모두 git status는 변경 0건. lock 파일은 그대로다.
5. 정리
.terraform/providers는 node_modules다. 그리고 terraform에도 pnpm store가 있다.
- AWS provider는 원래 크다. 한 벌에 700~800MB.
- 기본 설정에서는
init한 디렉토리마다 한 벌씩 받는다. envs·shared·modules로 쪼갠 레포일수록 불어난다. ~/.terraformrc의plugin_cache_dir한 줄이면 버전당 한 벌로 줄어든다.- 캐시는 자동 정리가 없다. 안 쓰는 옛 버전이 쌓이면 캐시 폴더에서 버전 디렉토리를 직접 지운다.
그리고 덤으로 배운 두 가지.
- zsh에서
for p in $STR은 쪼개지지 않는다. 목록은 배열로. init -backend=false도 저장된 backend의 state는 읽으러 간다. 자격증명이 필요하다.
이 맥에서 이제 새로 init하는 terraform 디렉토리는 전부 캐시를 탄다.
data-serving, thesmc-apps에 남은 1.4GB는 다음에 거기서 작업할 때 지우고 다시 받으면 된다.
'TIL' 카테고리의 다른 글
| [261004 TIL] 우리들의 추억 2편 - 체크포인트 1 (1) | 2026.10.04 |
|---|---|
| [260930 TIL] vgpu로 블랙홀 세 번째 시도 (0) | 2026.09.30 |
| [260917 TIL] ANALYZE는 왜 한 시간이 걸렸나 (0) | 2026.09.17 |
| [260913 TIL] Next 16 캐시컴포넌트 - 이게 좋은건지... (1) | 2026.09.13 |
| [260830 TIL] 배럴 export 와 실행 환경 경계 (0) | 2026.08.30 |