무경보 실서비스를 관측·CI/CD·FinOps까지 코드로
서버 다운 알람 하나뿐이던 AWS 실서비스에 Terraform으로 관측 체계를 세우고, 배포를 반으로, 고정비를 무중단으로 줄였다.
- 역할
- DevOps · SRE · 인프라 재분석과 구축, 출시 환경까지 전담
- 기술
- AWS (EC2 Graviton · ALB · RDS Multi-AZ · ElastiCache · DynamoDB · NAT · SSM · SES) · CloudWatch · Logs Insights · SNS · EventBridge · Lambda · Terraform · GitHub Actions (OIDC) · ECR · Docker · k6
- 22.6만
- 표면화한 누적 에러 (근본원인 65% 규명)
- 10×
- 트래픽 급증을 에러율 0.05% 이하로
- 16→8분
- 배포 시간 (SSM 수동 → ECR CI/CD)
- −$78/월
- 고정비 무중단 절감
합류 당시 알림은 서버가 죽었는지 알리는 경보 하나였고, 문서상 다이어그램과 실제 리소스가 달랐습니다. 관측 체계를 Terraform으로 먼저 세워 잠복해 있던 에러 22.6만 건을 드러냈고, 배포·비용·보안을 차례로 손봐 마케팅발 트래픽 10배 급증을 에러율 0.05% 이하로 받아냈습니다.
상황
실서비스는 도쿄 리전에 main·release 두 환경으로 떠 있었지만, 문서상 다이어그램과 실제 운영 구조가 달랐고 옵저버빌리티가 없어 장애와 에러가 표면화되지 않았습니다. 알림은 서버 다운 경보 1개가 전부였습니다.
release용 EC2가 퍼블릭 서브넷에 공인 IP로 직접 노출돼 있었고, 한 AZ의 NAT Gateway는 아무도 쓰지 않으면서 과금되고 있었습니다. main Redis는 트래픽 대비 과한 다중 노드였고, 배포는 SSM으로 인스턴스 위에서 직접 빌드하는 수동 방식이라 16분이 걸렸습니다.
한 일
- 01
재분석: 다이어그램과 실제 리소스를 1:1로 대조
main/release 환경 분리, 서브넷·NAT·RDS(Multi-AZ와 Single-AZ)·Redis 노드 구성·egress 경로를 라이브로 검증해 운영 구조를 다시 그렸습니다. 이 도식이 이후 모든 변경의 기준 문서가 됐습니다.
- 02
관측 체계를 Terraform으로 전면 코드화
CloudWatch 알람·메트릭 필터 39개와 대시보드 12개를 Terraform으로 구축하고 SNS로 라우팅했습니다. 복합 알람 2개가 하위 알람 18개를 롤업하도록 설계해 알람 피로를 억제했고, EventBridge → Lambda → Logs Insights → SNS 서버리스 리포트로 매시간 쏟아지던 알림을 일 1회 다이제스트로 바꿨습니다.
- 03
침묵 장애 발굴
체계가 서자마자 무경보로 쌓여 있던 누적 ERROR 226,012건과 자율 세션 크래시 스톰 76건이 드러났습니다. 분류해 보니 단일 근본원인(DB 연결 타임아웃 → 세션 크래시)이 65%였습니다. SSM State Manager로 CloudWatch Agent 상태를 주기적으로 교정해 관측 공백(최대 1일)을 1시간 이내로 줄였습니다.
- 04
배포: SSM 수동 빌드에서 ECR 이미지 CI/CD로
QEMU 에뮬레이션으로 6시간씩 멈추던 빌드를 arm64 네이티브 러너로 바꿔 당일 해소했고, 배포 시간은 16분에서 8분이 됐습니다. /v1/ready 딥 헬스체크, 무중단 instance refresh(MinHealthy 100 · AutoRollback), preflight 5가드로 이미지 부재발 배포 death-loop(약 9분 outage)를 구조적으로 차단했습니다.
- 05
FinOps: 실측 → import → 2게이트 sign-off → apply
유휴 NAT 삭제(−$45/월)와 main Redis 2노드 → 단일 노드 온라인 변경(−$33/월)으로 월 −$78을 무중단 절감했습니다. 프로덕션의 파괴적 변경은 terraform import로 실물을 코드에 들인 뒤 2게이트 sign-off를 거쳐서만 apply했고, NAT를 경유하던 불필요한 외부 LLM 호출도 제거해 비용 누수를 막았습니다. 3개월 연속 비용 하강을 Cost Explorer로 확인했습니다.
- 06
보안·가용성과 스테이징 환경 전체 구축
release EC2의 공인 IP를 제거하고 ALB origin을 엣지(CDN) 대역만 허용해 우회 직타를 막았습니다. 스테이징은 3-tier VPC·Multi-AZ, GitHub Actions OIDC(장기 자격증명 0), ECR lifecycle, 이중 예산 가드, 최소권한 IAM까지 Terraform 900줄로 단독 설계·구축했습니다.
- 07
출시(prod) 환경을 모듈로
스테이징에서 검증한 구성을 공용 플랫폼 모듈로 추출해 prod 환경(리소스 165개)을 코드로 세웠습니다. RDS Multi-AZ와 PITR 14일, 빈 DB에서 마이그레이션 전체를 적용하는 부트스트랩 CodeBuild, 수동 릴리스 스크립트, 배포 순단 중 점검 응답, 엔진 세션 상주 상한(60)과 30분 유휴 종료(유휴 51세션이 코어의 29%를 쓰던 것을 실측)까지 포함합니다. 출시 전 k6 부하 스모크 기준은 p95 800ms 미만·실패율 1% 미만으로 정했습니다.
- 08
부하 실측으로 사이징 근거 확보
k6로 동시성 한계를 실측(20VU p95 90ms · 실패율 0.18%, 50VU 붕괴점)해 인스턴스 사이징과 오토스케일 기준을 정했습니다. 이 기준으로 구성한 ASG가 8월 마케팅 트래픽 때 1대에서 3대로 늘어나며 급증을 흡수했습니다.
결과
- 트래픽 10배 급증(일 5~8천 → 최대 70,762 요청)을 에러율 0.008~0.05%, 응답 p95 0.3초로 무장애 수용. 개선 전 나쁜 날 에러율 최대 2.9% 대비 30배 이상.
- 누적 ERROR 226,012건 표면화와 단일 근본원인 65% 규명, 추적·해소 기반 확보.
- 배포 16분 → 8분, 배포 death-loop(약 9분 outage) 재발 0.
- 월 고정비 −$78 무중단 절감, 3개월 연속 비용 하강.
- 관측 공백 최대 1일 → 1시간, 알람 매시간 → 일 1회 다이제스트.
- release EC2 공인 IP 제거와 엣지 대역 화이트리스트로 공격 표면 축소. ALB 2AZ·RDS Multi-AZ failover 유지.
- prod 환경 리소스 165개를 플랫폼 모듈로 코드화, 출시 릴리스 절차와 부하 스모크 기준 확보.
정직하게 적어 두는 것
- 대시보드 캡처는 계정 정보가 노출돼 공개하지 않습니다. 수치 출처는 CloudWatch, CloudTrail, GitHub Actions 실행 로그, Cost Explorer입니다.
- 회사명과 제품명, 계정·리소스 ID는 익명화했습니다.
구조
Mermaid로 작성
① 재분석: 실제 운영 구조
문서상 다이어그램과 실제 리소스를 대조해 다시 그린 운영 구조. main/release 환경, AZ 1a·1c, NAT·RDS·Redis 구성과 egress 경로를 실측했습니다.
② 발견한 문제
환경을 분리해 보니 드러난 것: release EC2의 공인 IP 직접 노출, 아무도 쓰지 않는 idle NAT-a, 트래픽 대비 과한 main Redis 2노드.
③ 응급처치 + 관측 + FinOps 이후
idle NAT와 중복 Redis 제거(월 −$78), release egress를 NAT-c로 통합. CloudWatch 알람·필터·대시보드를 Terraform으로 코드화하고 복합 알람 롤업, SSM 자가치유, 서버리스 리포트를 얹었습니다. ALB 2AZ·RDS Multi-AZ failover는 유지.