pile·
인프라 / DevOps·마켓컬리마켓컬리 Hello World·

DevOps팀의 Terraform 모험

컬리 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 관리·생성 순서·코드리뷰 함정의 실전 레퍼런스.
마켓컬리
마켓컬리 Hello World 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 인프라 / DevOps·cloudflare-blogCloudflare Blog·

    대규모 도그푸딩: cdnjs를 Cloudflare 개발자 플랫폼으로 이전하다

    cdnjs는 하루 90억 요청을 처리하는 오픈소스 JS/CSS CDN으로, 전 세계 웹사이트의 12%가 의존한다. 2026년 6월, Cloudflare는 6년간 GCP에서 운영하던 발행 파이프라인을 Workers, Workflows, R2, KV, Queues, Containers, Durable Objects로 완전 전환했다. 성능 문제가 아닌 관측성·유지보수성 한계가 동인이었으며, 마이그레이션 과정에서 플랫폼 한도를 직접 끌어올렸다.

    #durable-objects#workflows#cloudflare-workers+2
  2. 인프라 / DevOps·github-engGitHub Engineering·

    Dependabot 길들이기: 업데이트 묶고, 주기 늦추고, 보안은 빠르게

    GitHub의 Dependabot은 의존성 업데이트를 자동화하지만, 기본 설정에서는 10개 업데이트 = 10개 PR이 쏟아져 메인테이너가 알림을 무시하게 된다. Microsoft의 GCToolkit 사례(578개 커밋 중 92개가 Dependabot 버전 범프)를 바탕으로, 그룹핑·주기 조절·보안 업데이트 분리 3가지 설정으로 노이즈를 줄이면서 보안 속도는 유지하는 방법을 다룬다.

    #github-actions#devops#supply-chain-security+2
  3. 인프라 / DevOps·cloudflare-blogCloudflare Blog·

    Cloudflare, 프라이버시 프로토콜 디버깅 CLI pvcli 오픈소스 공개

    Cloudflare가 OHTTP(Oblivious HTTP) 등 프라이버시 보존 프로토콜 디버깅을 위한 CLI 도구 pvcli를 오픈소스(Apache-2.0)로 공개했다. 기존에는 RFC를 참조하며 바이너리를 수작업으로 파싱해야 했는데, pvcli는 curl과 유사한 문법으로 이 과정을 단일 명령으로 줄인다. Apple Private Relay·Microsoft Edge Secure Network를 구동하는 실전 규모의 경험에서 나온 도구다.

    #rust#cli#ohttp+2