컬리 DevOps팀이 급증한 성능 테스트·스테이지 환경을 관리하기 위해 Terraform으로 IaC를 도입하며 겪은 시행착오를 정리한다. Module/Environment 코드 분리부터 tfstate 관리의 중요성을 뒤늦게 깨달은 과정, 리소스 의존성으로 인한 Cycle Error까지 다룬다.
핵심 포인트- 서비스 급증으로 Stage·QA 환경 반복 작업이 늘고 작은 실수가 잦아 Terraform을 도입, Stage/QA 먼저 적용 후 운영에 확대하는 전략
- best practice의 large 구조를 참고해 env(dev/qa/stg)와 modules(compute/database/network 등)로 코드를 나눔
- 반복 코드를 Module Code로, 실제 provision을 Environment Code로 분리하고 locals·merge·dynamic block으로 리팩토링
- tfstate가 코드-실제 리소스 매핑·의존성 메타데이터·캐시·sync 역할을 한다는 걸 뒤늦게 이해하고 DevOps팀이 직접 관리로 선회
- 리소스 의존성을 지키지 않으면 순환 참조(Cycle Error)가 나므로 생성 순서를 명시
상세 정리- 도입 계기: Stage·QA 환경이 비대해지며 인프라·CI/CD 구성의 단순 반복 작업과 실수가 늘어, 작년 8월부터 IaC로 Terraform을 도입했다.
- 학습: 경험이 부족해 Terraform Standard Module Structure와 Anton Babenko 예제로 기초부터 공부하고, 여러 AWS 계정·운영 확장을 염두에 두고 large 방식을 응용했다.
- 초기 구조: env 아래 dev/qa/stg, modules 아래 acm·compute(alb/asg/efs/lb_listener/lt/nlb/sg)·database·iam·mq·network로 구성했다.
- 코드 관리: GitHub private repo로 코드를, Infra 계정 S3 버킷에 tfstate를 두고, 콘솔 수정을 막고 Terraform AccessKey로만 수정 가능하게 bucket policy를 걸었다.
- 코드 분리 원칙: Module Code는 Environment 변경에 영향받지 않고 환경을 생성할 수 있어야 하고, Environment Code는 Module Code를 자유롭게 쓸 수 있어야 한다.
- 리팩토링: 변수가 너무 많아 부담스러워 locals로 반복 태그를 묶고 merge·format·upper·lower로 태그 값을 자동 생성했다.
- dynamic block: block_device_mappings 같은 반복 블록을 for_each 기반 dynamic block과 lookup으로 바꿔 중복을 줄였다.
- 큰 착각: 처음엔 환경 생성에만 집중해 tfstate의 중요성을 간과했는데, tfstate가 리소스 매핑·의존성 메타데이터·캐시·코드와 환경 sync 역할을 한다는 걸 알고 DevOps팀이 코드와 tfstate를 직접 관리하도록 방향을 바꿨다.
- 원칙 1: IAM 권한은 수동 관리, Security Group은 코드화하되 파편화하지 않고 Global하게 써서 수동 1차 수정 후 코드에만 반영(replaced 방지)하도록 분리했다.
- 원칙 2 (생성 순서): MQ·ElastiCache에서 시작해 Route53/도메인 후 ACM, 그다음 ALB·SG, Launch Template·Target Group 후 ASG, 마지막으로 CodeDeploy·CodePipeline 순으로 의존성을 지켜 Cycle Error를 피했다.
- 함정: Environment Code가 길어 리뷰 때 plan 결과를 안 믿고 코드만 봐 apply 시 must be replaced가 50개 이상 발생하거나, 수동으로 먼저 만든 Route53 도메인이 already exists 에러를 내는 등의 문제를 겪었다.
- 후기: Terraform은 진입장벽이 높고 자신의 환경을 정확히 이해해야 자동화가 가능하며 결국 AWS를 잘 알아야 한다고 정리했다.
왜 읽나Terraform으로 다계정·다환경 인프라를 코드화하려는 DevOps/SRE에게 모듈 분리·tfstate 관리·생성 순서·코드리뷰 함정의 실전 레퍼런스.