키도 문서도 없는 AWS 계정, 월 $1,650은 어떻게 $400이 됐나

시작 상태는 이랬다. 서버에 접속할 PEM 키는 분실됐고, 인프라 문서는 없었다. 계정은 결제 대행사의 페이어 계정에 묶인 멤버 계정이라 Cost Explorer도 비활성이었다. 서버에 들어갈 수 없고 비용 그래프도 볼 수 없는 상태에서, 청구서만 매달 도착하고 있었다. 인수인계가 끊긴 계정에서 흔히 보는 조합이다.
다행히 모든 인스턴스에 SSM 에이전트가 살아 있었다. Session Manager로 키 없이 셸을 열 수 있었고, 이 통로가 이후 모든 검증 작업의 기반이 됐다.

청구서 대신 API로 재고 조사를 했다
비용 콘솔이 막혀 있으니 개별 서비스 API로 인벤토리를 만들었다. EC2, RDS, EBS, 스냅샷, EIP, 로드밸런서를 전부 나열하고 서울 리전 온디맨드 단가를 붙였다. 나온 그림은 이렇다.
- 웹서버 c5.2xlarge 2대. 트래픽 규모 대비 과대 사양이고, 크론·배치 검증 결과 한 대는 고유 워크로드가 없었다.
- Aurora MySQL 5.7 클러스터에 r5.large 라이터와 리더 각 1대. 애플리케이션 설정은 클러스터(라이터) 엔드포인트만 바라보고 있어서 리더로는 트래픽이 가지 않았다. 대기만 하는 인스턴스가 월 $255를 쓰고 있었다.
- MySQL 5.7은 표준 지원이 끝난 버전이라 RDS Extended Support 요금이 월 $350 수준으로 조용히 청구되고 있었다.1
- 개발 서버와 bastion이 상시 가동 중이었다. 개발 서버의 2주치 접근 로그를 열어 보니 실사용은 없고 봇·스캐너 트래픽뿐이었다.
사이징 판단은 추정이 아니라 실측으로 했다. 최근 7일 지표에서 DB의 CPU 최대치는 17~24%, 동시 연결은 최대 4~5개였다. 스키마 전체를 합친 실제 데이터는 약 700MB였다. 16GB 메모리의 r5.large가 감당하던 작업 셋이 4GB 인스턴스의 버퍼 풀에도 통째로 올라가는 크기다.
계획: 큰 덩어리부터, 되돌릴 수 있게
절감 후보를 금액순으로 정렬하니 상위 세 건이 전부 데이터베이스였다. 리더 제거, Extended Support 탈출, 라이터 다운사이징을 합치면 월 $793으로 전체 절감의 3분의 2다. 실행 원칙은 세 가지로 잡았다.
- 파괴적 작업 전에 복구 지점을 만든다. 인스턴스 종료 전 AMI, 클러스터 변경 전 스냅샷.
- 플랫폼의 무중단 수단을 먼저 쓴다. EC2 교체는 ASG 인스턴스 리프레시, DB 메이저 업그레이드는 Blue/Green 배포.2
- 삭제는 마지막에 한다. 중지 상태로 관찰 기간을 두고, 문제가 없을 때 최종 스냅샷을 남기고 지운다.
실행 1 — EC2: 종료는 검증 뒤에 온다
"안 쓰는 서버 같다"와 "안 쓰는 서버다" 사이에는 검증이 있어야 한다. 웹서버 2대의 crontab, systemd 타이머, 프로세스 목록을 SSM으로 훑어 숨은 배치가 없음을 확인한 뒤에야 한 대를 종료했다. AMI 백업을 먼저 만들었고, 남은 한 대는 ASG 인스턴스 리프레시로 c5.2xlarge에서 c7i.xlarge로 무중단 교체했다.3 두 세대 뒤의 인스턴스로 바꾸면서 성능은 오히려 여유가 생겼다.
개발 서버와 bastion은 삭제하지 않고 중지했다. bastion은 SSM 접속 체계가 자리 잡으면 존재 이유가 없어지는 자원이라 폐기 후보로 두었다.
실행 2 — Aurora: 가장 큰 세 덩어리
리더 제거는 간단했다. 문제는 5.7에서 8.0으로 가는 메이저 업그레이드였다. Blue/Green 배포로 8.0 환경(green)을 옆에 세우고 복제 동기화가 끝나면 전환하는 계획이었는데, 첫 시도가 프리체크에서 실패했다.
{"level": "Error", "dbObject": "all",
"description": "Your Master User on host '%' has been dropped.
To proceed with the upgrade, recreate the master user `admin` on default host '%'"}
과거 누군가 애플리케이션 전용 계정을 만들면서 마스터 유저를 삭제해 뒀다. 5.7을 운영하는 동안에는 아무 증상이 없다가, 메이저 업그레이드라는 이벤트에서 6년 묵은 결정이 갑자기 청구서를 들고 나타났다. RDS는 마스터 비밀번호를 재설정하면 마스터 유저를 재생성하므로 복구 자체는 한 번의 API 호출이었다.4 재생성한 자격 증명은 Secrets Manager로 옮겼다.
두 번째 시도에서 green 환경이 정상적으로 올라왔다. 전환 전에 green에 직접 접속해 버전, 타임존, 핵심 테이블의 행 수가 운영과 일치하는지 확인했다. 회원 테이블 14만 행이 양쪽에서 같은 숫자로 나오는 것을 보고 스위치오버를 실행했다. AWS가 엔드포인트 이름을 맞바꿔 주기 때문에 애플리케이션 설정 변경은 0건이었고, 순단은 1분 안팎이었다.
마지막으로 라이터를 r5.large에서 t4g.medium으로 내렸다. 이 전환의 순단 동안 웹 ASG가 헬스체크 실패를 감지하고 인스턴스를 새로 띄웠다. 장애가 아니라 설계한 자가 복구가 작동한 결과였다. 전환 후 ALB 타깃이 다시 healthy로 돌아온 것까지 확인했다. 구 5.7 클러스터는 최종 스냅샷을 남기고 삭제해 Extended Support 과금을 끝냈다.
강평: 무엇이 얼마를 만들었나
| 항목 | 조치 | 월 절감 (서울 온디맨드 추정) |
|---|---|---|
| 웹서버 1대 종료 | c5.2xlarge, AMI 백업 후 | ~$280 |
| 웹서버 세대 교체 | c5.2xlarge → c7i.xlarge | ~$133 |
| Aurora 리더 제거 | 무트래픽 r5.large | ~$255 |
| Extended Support 종료 | 5.7 → 8.0 업그레이드 | ~$350 |
| Aurora 라이터 다운사이징 | r5.large → t4g.medium | ~$188 |
| dev·bastion 중지 | 상시 가동 해제 | ~$41 |
| 스토리지·스냅샷 정리 | gp2 → gp3, 고아 스냅샷 삭제 | ~$10 |
합계는 월 $1,250 안팎, 기존 비용의 76% 절감이다. RI나 Savings Plan이 있는 계정이라면 절대 금액은 달라진다.
돌아보면 기술적으로 어려운 일은 없었다. Blue/Green도 인스턴스 리프레시도 SSM도 AWS가 제공하는 표준 수단이다. 어려웠던 쪽은 판단의 근거를 만드는 일이었다. 거기서 얻은 교훈을 남긴다.
- 비용 문제는 대부분 소유권 문제다. r5.large 리더도 Extended Support도 기술적 장애가 아니라 "지켜보는 사람이 없다"는 상태의 가격이었다. 이 주제는 재구축과 오너십 공백에서 따로 다뤘다.
- 실측 없이 사이징 없다. CPU 17
24%, 연결 45개, 데이터 700MB라는 숫자가 있었기 때문에 t4g.medium 결정을 불안 없이 내릴 수 있었다. - Extended Support는 결정을 미룬 비용이다. 업그레이드를 미루는 동안 매달 $350씩, 아무 기능도 사지 않는 돈이 나간다.
- 롤백 경로는 만들고, 쓰지 않았을 때 지운다. 스냅샷과 AMI를 먼저 만들고, 관찰 기간이 끝난 뒤 정리했다. 복구 지점이 있으면 실행 속도가 오히려 빨라진다.
방치된 계정의 청구서에는 보통 이런 항목이 숨어 있다. 어디서 새는지 짚는 일반론은 AWS 보이지 않는 비용에 정리했고, 이 글 같은 재조정 작업은 클라우드 & 인프라 서비스로 진행한다.
참고 자료
출처와 각주4개펼치기접기
Footnotes
-
Amazon RDS Extended Support 개요와 vCPU-시간당 과금 구조. Amazon RDS Extended Support ↩
-
Aurora Blue/Green 배포 문서. green 환경 생성, 복제, 스위치오버 시 엔드포인트 교체를 다룬다. Blue/Green Deployments ↩
-
ASG 인스턴스 리프레시로 실행 중 서비스의 인스턴스를 점진 교체하는 방법. Use an instance refresh ↩
-
Aurora MySQL 8.0 메이저 업그레이드 절차와 프리체크 트러블슈팅. 삭제된 마스터 유저 등 업그레이드를 막는 조건이 정리돼 있다. Upgrading to Aurora MySQL version 3 ↩


