인프라 자동화를 위한 Terraform 도입기

2025. 8. 1. 23:01·YAPP

IaC, 그리고 왜 Terraform이었을까?

YAPP 26기에 합류하면서 새로운 프로젝트를 진행하게 되었습니다.
인프라 환경을 새롭게 구성해야 하는 상황에서, 기존의 AWS 콘솔 기반 관리 방식에서 벗어나
처음부터 IaC를 이용하여 인프라를 구성하기로 결정했습니다.


기존 인프라 운영의 문제점

변경 이력 추적의 어려움

이전 프로젝트들에서는 AWS 콘솔을 통해 직접 인프라를 구축하고 운영했습니다. 처음에는 익숙한 UI 덕분에 빠르게 리소스를 만들 수 있었지만, 프로젝트 규모가 커지고 팀원이 늘어날수록 여러 가지 문제점이 드러났습니다.

가장 큰 문제는 인프라 변경 사항이 추적되지 않는다는 점이었습니다. 콘솔에서 수동으로 수정한 내용은 콘솔 작업도 CloudTrail에 기록되지만, 변경 목적이나 맥락은 담기지 않아 팀원 간 공유나 리뷰가 어려웠습니다. 인프라 이슈가 발생했을 때도, 제가 직접 확인하지 않으면 원인을 파악하기 힘들었고, 팀원들도 문제 해결 과정을 이해하거나 재현하기 어려웠습니다.

인프라 구축 순서를 사람 머릿속에 의존

리소스 구성에 있어서 선후 관계를 사람이 직접 머릿속으로 관리해야 한다는 점도 부담이었습니다. 예를 들어, EC2 인스턴스를 생성하기 위해서는 먼저 VPC, 서브넷, 보안 그룹 등을 순서대로 준비해야 하는데, 이런 흐름은 익숙한 사람이 아니면 실수하기 쉽습니다. 반복적으로 입력해야 하는 리소스 태그나 환경 변수 등을 깜빡하기도 했고, 이를 나중에 수정하는 과정에서 오히려 더 많은 시간이 소요되기도 했습니다.

코드와 인프라의 단절

더 큰 문제는 인프라와 프로젝트 코드가 전혀 연결되어 있지 않다는 점이었습니다. 콘솔로 생성된 리소스들은 코드와 별도로 존재하다 보니, 어떤 기능에서 어떤 리소스를 사용하는지 명확히 파악하기 어려웠고, 리소스를 실수로 변경하거나 삭제하는 위험도 있었습니다. 기능들이 많아질수록 관리 범위는 커졌고, 인프라의 일관성을 유지하기가 점점 어려워졌습니다.

반복되는 수작업, 마이그레이션의 고통

마지막으로, 비용 최적화를 위해 인프라를 일시적으로 내렸다가 다시 올리는 작업이 매우 번거롭다는 점도 문제였습니다. 수동으로 삭제한 리소스를 다시 정확히 구성하려면 처음부터 다시 클릭하고 설정해야 했고, 이 과정에서 누락이나 실수가 자주 발생했습니다. 특히 MVP 단계의 프로젝트처럼 빠르게 만들고 자주 바뀌는 구조에서는 수작업 관리가 점점 부담이 됐습니다.


이제는 미룰수 없는 IaC

이전 프로젝트에서 반복적으로 겪은 문제들을 통해 하나의 결론에 도달했습니다.
이제는 인프라도 코드로 관리하지 않으면 안 된다는 것이었습니다.

GitOps 기반 통합 운영

IaC를 적용하면 인프라 변경 역시 Git으로 관리할 수 있습니다.
누가, 언제, 어떤 변경을 했는지 이력이 남고, 잘못된 변경은 되돌릴 수 있으며, PR 기반의 코드 리뷰도 가능합니다.

terraform plan을 통해 변경 내역을 사전에 검토할 수 있고, GitHub Actions 등을 통해 테스트와 배포까지 자동화할 수 있습니다.
PR을 기준으로 인프라를 생성하고, merge 기준으로 배포가 이루어지는 구조를 통해
명확한 승인 절차와 운영 일관성을 확보할 수 있습니다.

환경별 구성 분리와 재사용성 확보

IaC는 개발, 스테이징, 운영 등 환경별 인프라 구성을 템플릿처럼 쉽게 분리할 수 있도록 도와줍니다.
코드의 변수만 바꾸면 동일한 구조를 다양한 환경에 복제할 수 있고, 하나의 변경 사항을 여러 환경에 손쉽게 반영할 수도 있습니다.


Terraform을 선택한 이유

IaC 도구로는 AWS CloudFormation, Pulumi, Terraform 등 여러 가지가 있지만,
CloudFormation은 AWS에 종속적이고, Pulumi는 레퍼런스가 적어 도입에 부담이 있었습니다.
Terraform은 레퍼런스도 풍부하고, 가장 무난한 선택지였습니다.

선언형 구성과 예측 가능한 리소스 관리

Terraform은 선언형 문법을 사용하며, 리소스 간 의존 관계를 자동으로 해석해 생성 순서를 조율합니다.
VPC → Subnet → SG → EC2 같은 흐름을 직접 순서에 맞춰 작성할 필요 없이, 코드만 정리하면 Terraform이 대부분 조율해줍니다.
복잡한 구조에서는 depends_on으로 우선순위를 지정해 주어야 하지만, 콘솔 수작업에 비해 훨씬 예측 가능하고 안정적인 구성 방식입니다.

AWS 의존성 탈피와 확장 가능성

Terraform은 단일 클라우드 벤더에 종속되지 않고, AWS 외에도 다양한 클라우드와 시스템을 지원합니다.
장기적으로 Kubernetes나 다른 클라우드 인프라로의 이전을 고려할 때, Terraform의 멀티 프로바이더 구조는 확장성과 유연성 측면에서 매력적인 선택지였습니다.


목표

1. 가능한 모든 것을 자동화한다.

PR 한 번으로 인프라 구성부터 수정, CI, CD까지 이어지는 자동화 구조를 만들고자 했습니다.
Terraform과 GitHub Actions 워크플로를 조합해, 수동 개입 없이도 코드가 병합되면 인프라가 자동으로 반영되고, 어플리케이션이 배포되는 흐름을 지향했습니다.

2. 관리 포인트를 줄이고 명확하게 만든다.

각종 시크릿 값들(환경변수, 워크플로 내 시크릿, 외부 API 키, DB 사용자/비밀번호 등)이 여기저기 흩어져 있던
구조는 찾기 어렵고, 분실하거나 잘못 관리될 가능성도 높다고 판단했습니다.
이를 명확한 기준 아래 통합하고, 등록 가능한 값은 자동화되도록 구성해
찾기 쉬운 구조와 신뢰할 수 있는 자동 주입을 목표로 했습니다.
 
자동화율을 높이고 관리 포인트를 줄이면, 결국 장애가 발생했을 때
확인해야 하는 지점이 명확해지고, 복구 속도도 훨씬 빨라집니다.


인프라 아키텍처

 
MVP 단계에서 서비스를 검증해야 했기에, 월 3만 5천 원 내에서 운영 가능한 인프라를 목표로 설계했습니다.
이에 따라 개발과 운영 환경이 동일한 인프라 리소스를 최대한 공유하는 구조로 구성했습니다.

 
CI 단계
PR 내 Terraform 관련 변경이 감지되면,
terraform plan 결과를 자동으로 생성해 PR 코멘트에 남깁니다.
팀원들은 이를 코드 리뷰와 함께 검토하고 승인합니다.
 
CD 단계
PR이 병합되면 terraform apply -auto-appove가 실행되어 실제 인프라 변경이 반영됩니다.
이 과정이 성공적으로 완료되어야만 서비스 배포 단계가 진행됩니다.
 
또한 CI/CD 파이프라인에서 사용되는 시크릿 값을 명확히 분리해 관리 포인트를 줄였습니다.

  • CI/CD 단계(GitHub Actions)
    필요한 AWS 액세스 키와 시크릿 키는 GitHub Secrets에 저장하여 워크플로 실행 시 사용되도록 구성했습니다.
  • 어플리케이션 런타임(운영 환경)
    서비스에서 사용하는 DB 비밀번호, 외부 API 키 등 어플리케이션 레벨 시크릿은 모두 AWS Parameter Store로 이전하고, 런타임 시 주입되도록 설정했습니다.
  • 인프라 리소스 자동 참조
    Terraform에서 주요 리소스 값을 output으로 노출하고, 이를 CD 워크플로 내에서 참조하도록 구성했습니다.
    이로 인해 리소스가 변경되어도 별도 수정 없이 자동으로 최신 값이 반영되도록 했습니다.


테라폼 아키텍처

인프라 아키텍처를 바탕으로 Terraform 모듈화를 적용했습니다.

 
전체 구조는 크게 세 계층으로 나뉩니다.
 

  1. bootstrap에서는 Terraform의 state 파일과 DynamoDB의 락을 활용해 동시성을 제어했고 여러 환경에서 공통으로 사용하는 ECR 이미지 저장소를 이곳에 따로 분리해 관리했습니다.
  2. common에서는 VPC, IAM, 시큐리티 그룹등 여러 환경에서 공통으로 사용하는 리소스를 정의했습니다.
  3. 실제 배포 환경별로는 dev, prod 모듈을 분리해 환경에 따라 다른 변수만 주입되도록 구성했습니다.

이때 각 모듈은 tfvars와 locals로 연결되며,
각 환경이 서로 다른 값을 가지더라도, 설정값을 각 모듈에서 책임지도록 하여
중복을 줄이고 재사용성이 높은 인프라 관리가 가능하게 되었습니다.


트러블 슈팅

 
배포 과정에서 트러블 슈팅 사례를 공유드리려 합니다.
처음에는 Terraform으로 ECS의 Task Definition까지 정의하도록 구성했는데,
이 리소스는 필수로 기동할 이미지 URL을 포함해야 합니다.
 
그런데 초기 배포 시점에는 실제 이미지가 없기 때문에 무조건 배포가 실패하는 상황이 발생했습니다.
이를 우회하기 위해, Task Definition 생성시 placeholer URL을 임시로 넣는 방식을 사용했습니다.
 
그런데 문제는, 이후 배포 과정에서도
ECS 서비스가 계속 플레이스홀더 이미지로 배포를 시도하면서 실패가 누적 된다는 점이었습니다.
실제 이미지를 포함한 Task Definition은 CD 워크플로에서 나중에 생성되지만,
그 전까지는 잘못된 이미지를 기준으로 ECS가 반복해서 배포를 시도하는 구조였습니다.
 
이 문제를 임시로 막기 위해
ECS 서비스에 ignore_changes 옵션을 주어 Terraform이 Task Definition 변경을 무시하도록 설정했습니다.
덕분에 불필요한 배포 시도는 줄일 수 있었지만,최초 배포 시 실제 이미지가 없어서 실패하는 문제는 여전히 남아 있었습니다.
 
이 문제는 결국,
Terraform이 정적인 리소스 정의와 배포 실행을 동시에 책임지려 했기 때문에 생긴 구조적 충돌이라고 생각했습니다.
그래서 Terraform은 정적인 리소스만 정의하고
 
GitHub Actions 워크플로는 동적인 리소스인 ECS 서비스와 Task Definition 등을 전담하는 구조로 전환할 계획입니다.


언제나 정답일까?

 
Terraform을 도입하면서 반복적인 리소스 생성과 설정 작업에서 확실히 자유로워졌습니다.
하지만 예상하지 못한 어려움도 꽤나 많았는데요
 
처음 본격적으로 Terraform을 사용하다 보니, HCL 문법에 익숙해지는 데 시간이 걸렸고,
모듈화를 진행하면서 구조가 복잡해져 디버깅에도 꽤 애를 먹었습니다.
 
또한 프로젝트 기간이 길지 않았던 만큼, Terraform으로 리소스를 선언하고 테스트하는 작업이
생각보다 많은 시간을 차지했습니다. 인프라가 먼저 완성되어야 서버 개발을 시작할 수 있었기 때문에,
초반 일정이 특히 촉박하게 느껴졌습니다.
 
인프라 100% 자동화를 목표로 하기도 했지만, 직접 해보니 모든 걸 자동화하는 게
현실적으로 쉽지도 않고, 꼭 필요한 일만은 아니라는 걸 알게 됐습니다.

예를 들어 EC2 인스턴스 키 생성과 할당을 자동화할 수는 있지만,
이 키를 권한이 있는 사람만 접근할 수 있도록 별도로 관리하는 작업까지 포함되면
오히려 수동 관리보다 더 복잡하고 부담이 되는 경우도 있었습니다.

 

물론 대규모 트래픽을 처리하고 수만 대의 서버를 관리해야 하는 환경에서는 100% 자동화가 필수적이라고 생각합니다.

하지만 소규모 프로젝트에서는 완벽한 자동화 인프라를 구축하는 데 투입되는 리소스 대비 실제 활용도가 높지 않아, 그 시간과 노력을 다른 핵심 기능 개발에 집중하는 것이 더 효율적이라는 판단이 들었습니다.

 

최근 시니어 SRE 엔지니어분과의 대화에서 완전 자동화를 위해서는 CMDB 등을 구축해 모든 인프라 데이터를 체계적으로 관리해야 한다는 이야기를 들었는데, 언젠가는 그런 수준의 인프라 운영에도 도전해보고 싶다는 생각이 들었습니다.

 
그럼에도 이번 경험을 통해 GitOps 기반 인프라 운영을 위한 기반을 다졌다고 생각하고,
앞으로도 조금씩 방향을 잡아가며 개선해 나갈 계획입니다.

저작자표시 비영리 변경금지 (새창열림)

'YAPP' 카테고리의 다른 글

Datadog을 활용한 SLI/SLO 모니터링 및 Burn Rate 알람 적용기  (0) 2025.09.18
격리된 Prod 복제 환경에서 안전하게 DB 마이그레이션 수행하기  (2) 2025.08.29
API Latency Postmortem - 2 : 이미지 업로드 아키텍처 개선으로 주요 API 레이턴시 단축  (3) 2025.08.28
Dev/Prod 환경 로그 & DB 백업 자동화 적용하기  (0) 2025.08.13
API Latency Postmortem – 1 : AWS t2.micro 환경에서의 병목 분석과 최적화  (8) 2025.08.12
'YAPP' 카테고리의 다른 글
  • 격리된 Prod 복제 환경에서 안전하게 DB 마이그레이션 수행하기
  • API Latency Postmortem - 2 : 이미지 업로드 아키텍처 개선으로 주요 API 레이턴시 단축
  • Dev/Prod 환경 로그 & DB 백업 자동화 적용하기
  • API Latency Postmortem – 1 : AWS t2.micro 환경에서의 병목 분석과 최적화
로승리
로승리
  • 로승리
    Roy's Blog
    로승리
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Issuefy
      • Language
      • Spring
      • Kubernetes
      • AWS
      • YAPP
      • 코드스쿼드
      • 코딩 테스트
      • 국비지원
      • 회고
      • 컨퍼런스, 세미나
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
로승리
인프라 자동화를 위한 Terraform 도입기
상단으로

티스토리툴바