테크·11 min read
AWS 비용 최적화 완전 가이드 2026 — EC2, S3, RDS 비용 절감 실전
AWS 비용이 예상보다 많이 나오는 개발자를 위한 최적화 가이드. EC2 Reserved Instance vs Savings Plans, S3 스토리지 클래스, RDS 비용 절감, 무료 티어 한도, 비용 모니터링 설정까지 실전 방법을 정리했습니다.
AWS 비용 — 모르면 청구서가 무섭다
AWS는 사용한 만큼 과금하는 구조라 설계를 잘못하면 예상보다 10배 이상 나오기도 합니다. 사이드 프로젝트부터 스타트업까지, 비용 구조를 이해하고 최적화하면 같은 성능을 30~70% 비용으로 운영할 수 있습니다.
AWS 비용 구조 이해
과금 주요 요소
| 서비스 | 과금 기준 | 주의 사항 |
|---|---|---|
| EC2 | 인스턴스 타입 × 시간 | 중지해도 EBS 스토리지 과금 |
| RDS | 인스턴스 타입 × 시간 + 스토리지 | Multi-AZ = 2배 비용 |
| S3 | 스토리지 GB + 요청 수 + 데이터 전송 | GET 요청도 과금됨 |
| Lambda | 요청 수 + GB-초 | 월 100만 건 무료 |
| CloudFront | 데이터 전송 + 요청 수 | S3보다 저렴한 경우 많음 |
| NAT Gateway | 시간 + GB | 개발 환경의 숨은 비용 주범 |
| 데이터 전송 | 리전 간, 인터넷 아웃 | 리전 내 동일 VPC는 무료 |
무료 티어 범위 (신규 계정 12개월)
| 서비스 | 무료 한도 |
|---|---|
| EC2 | t2.micro 750시간/월 (Linux/Windows) |
| RDS | t2.micro 750시간/월 (MySQL, PostgreSQL 등) |
| S3 | 5GB 스토리지, 20,000 GET, 2,000 PUT 요청 |
| CloudFront | 1TB 데이터 전송, 10,000,000 HTTP 요청 |
| Lambda | 100만 요청/월, 400,000 GB-초 (영구 무료) |
| DynamoDB | 25GB 스토리지, 25 WCU/RCU (영구 무료) |
EC2 비용 최적화
인스턴스 구매 옵션 비교
| 옵션 | 할인율 | 조건 | 적합한 경우 |
|---|---|---|---|
| On-Demand | 0% | 언제든 중지 | 개발, 테스트 |
| Savings Plans | 최대 72% | 1~3년 약정 (유연) | 상시 운영 서버 |
| Reserved Instance | 최대 75% | 1~3년 약정 (고정) | 인스턴스 타입 변경 없을 때 |
| Spot Instance | 최대 90% | 언제든 중단 가능 | 배치 작업, CI/CD |
| Graviton (ARM) | ~20% | ARM 아키텍처 | 대부분의 워크로드 |
Savings Plans 설정
# AWS CLI로 Savings Plans 구매 권장사항 확인
aws ce get-savings-plans-purchase-recommendation \
--savings-plans-type COMPUTE_SP \
--term-in-years ONE_YEAR \
--payment-option NO_UPFRONT \
--lookback-period-in-days THIRTY_DAYS
개발 환경 인스턴스 자동 중지 (EventBridge)
# Lambda 함수: 평일 오전 9시 시작, 오후 7시 중지
import boto3
def lambda_handler(event, context):
ec2 = boto3.client('ec2', region_name='ap-northeast-2')
action = event.get('action', 'stop')
# 태그로 관리 대상 인스턴스 필터링
instances = ec2.describe_instances(
Filters=[
{'Name': 'tag:Environment', 'Values': ['dev']},
{'Name': 'tag:AutoStop', 'Values': ['true']},
]
)
instance_ids = [
i['InstanceId']
for r in instances['Reservations']
for i in r['Instances']
]
if not instance_ids:
return {'message': 'No instances found'}
if action == 'start':
ec2.start_instances(InstanceIds=instance_ids)
else:
ec2.stop_instances(InstanceIds=instance_ids)
return {'action': action, 'instances': instance_ids}
# EventBridge 스케줄 (CDK/CloudFormation)
StartDevInstances:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "cron(0 0 ? * MON-FRI *)" # UTC 00:00 = KST 09:00
Targets:
- Arn: !GetAtt AutoStopLambda.Arn
Input: '{"action": "start"}'
StopDevInstances:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: "cron(0 10 ? * MON-FRI *)" # UTC 10:00 = KST 19:00
Targets:
- Arn: !GetAtt AutoStopLambda.Arn
Input: '{"action": "stop"}'
절감 효과: 평일 10시간만 사용 → 월 최대 70% 절감 (168시간 → 50시간)
Graviton 인스턴스 전환
# 동일 성능 대비 약 20% 저렴
# x86 → ARM 전환 예시
# m5.large ($0.096/h) → m6g.large ($0.077/h)
# Amazon Linux 2023, Ubuntu 22.04+ ARM 이미지로 교체
# 대부분의 Node.js, Python, Go, Java 앱은 재컴파일 불필요
S3 비용 최적화
스토리지 클래스 비교
| 클래스 | GB당 월 비용 | 접근 패턴 | 복원 시간 |
|---|---|---|---|
| Standard | $0.023 | 자주 | 즉시 |
| Intelligent-Tiering | $0.023 (모니터링 $0.0025/객체) | 불규칙 | 즉시 |
| Standard-IA | $0.0125 | 월 1회 미만 | 즉시 |
| Glacier Instant | $0.004 | 분기 1회 미만 | 즉시 |
| Glacier Flexible | $0.0036 | 연 1~2회 | 수 시간 |
| Glacier Deep Archive | $0.00099 | 거의 없음 | 12시간+ |
Lifecycle 정책 설정 (권장)
{
"Rules": [
{
"Id": "archive-old-objects",
"Status": "Enabled",
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "GLACIER_IR"
},
{
"Days": 365,
"StorageClass": "DEEP_ARCHIVE"
}
],
"Expiration": {
"Days": 2555
}
},
{
"Id": "delete-incomplete-multipart",
"Status": "Enabled",
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
}
]
}
# AWS CLI로 Lifecycle 정책 적용
aws s3api put-bucket-lifecycle-configuration \
--bucket my-bucket \
--lifecycle-configuration file://lifecycle.json
CloudFront로 S3 요청 비용 절감
S3 직접 접근: GET 요청 $0.0004/1,000건 + 데이터 전송 $0.09/GB
CloudFront 캐싱 후: 캐시 히트 요청은 S3 과금 없음 + 전송 $0.0085/GB
정적 사이트 월 10만 GET, 10GB 전송 기준:
S3 직접: $0.04 + $0.90 = $0.94
CloudFront + S3: $0.0085 × 10 = $0.085 (캐시 히트율 80% 기준)
RDS 비용 최적화
개발 환경 Multi-AZ 제거
# Multi-AZ 비활성화 (콘솔 또는 CLI)
aws rds modify-db-instance \
--db-instance-identifier my-dev-db \
--no-multi-az \
--apply-immediately
# 비용 절감: 즉시 50% 감소
# 단, 프로덕션에서는 Multi-AZ 반드시 유지
Aurora Serverless v2 전환
# CloudFormation: Aurora Serverless v2
RDSCluster:
Type: AWS::RDS::DBCluster
Properties:
Engine: aurora-postgresql
EngineVersion: "15.4"
ServerlessV2ScalingConfiguration:
MinCapacity: 0.5 # 최소 0.5 ACU (~$0.06/h)
MaxCapacity: 4 # 최대 4 ACU (트래픽에 따라 자동 조정)
Aurora Serverless v2 vs 상시 RDS 비교:
db.t3.medium 상시 운영: $0.068/h × 730h = $49.6/월
Aurora Serverless v2 (하루 4시간 집중):
- 활성: 2 ACU × 4h × 30일 = $21.6
- 유휴: 0.5 ACU × 20h × 30일 = $18.0
= 약 $39.6/월 (20% 절감, 가변 트래픽일수록 절감 폭 증가)
RDS 스냅샷 관리
# 30일 이상 된 수동 스냅샷 목록
aws rds describe-db-snapshots \
--snapshot-type manual \
--query 'DBSnapshots[?SnapshotCreateTime<=`2026-03-01`].[DBSnapshotIdentifier,SnapshotCreateTime]' \
--output table
# 스냅샷 삭제
aws rds delete-db-snapshot \
--db-snapshot-identifier old-snapshot-id
NAT Gateway — 숨은 비용 주범
NAT Gateway는 가장 과소평가되는 비용 항목 중 하나입니다.
NAT Gateway 비용:
- 시간당 $0.059 × 730h = 약 $43/월 (고정)
- 처리 데이터 GB당 $0.059 추가
개발 환경에서 NAT Gateway 1개 = 월 $50+ 기본
대안: NAT Instance (저비용)
# NAT Instance 설정 (t4g.nano: ~$3/월)
# 커뮤니티 AMI 'amzn-ami-vpc-nat' 사용
# 소스/대상 확인 비활성화 (필수)
aws ec2 modify-instance-attribute \
--instance-id i-xxxxx \
--no-source-dest-check
# 라우팅 테이블: 0.0.0.0/0 → NAT Instance ID
대안: VPC Endpoint (S3, DynamoDB)
# S3 VPC Gateway Endpoint (무료)
# Private 서브넷에서 S3 접근 시 NAT Gateway 우회
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxxxx \
--service-name com.amazonaws.ap-northeast-2.s3 \
--route-table-ids rtb-xxxxx
비용 모니터링 설정
AWS Budgets 알림
# CLI로 월 $50 예산 설정
aws budgets create-budget \
--account-id 123456789012 \
--budget '{
"BudgetName": "monthly-cost-alert",
"BudgetLimit": {"Amount": "50", "Unit": "USD"},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}' \
--notifications-with-subscribers '[{
"Notification": {
"NotificationType": "ACTUAL",
"ComparisonOperator": "GREATER_THAN",
"Threshold": 80
},
"Subscribers": [{
"SubscriptionType": "EMAIL",
"Address": "your@email.com"
}]
}]'
Cost Anomaly Detection (이상 탐지)
# 이상 감지 모니터 생성
aws ce create-anomaly-monitor \
--anomaly-monitor '{
"MonitorName": "ServiceMonitor",
"MonitorType": "DIMENSIONAL",
"MonitorDimension": "SERVICE"
}'
# 이상 감지 구독 ($10 초과 시 이메일)
aws ce create-anomaly-subscription \
--anomaly-subscription '{
"SubscriptionName": "AlertOver10",
"MonitorArnList": ["arn:aws:ce::..."],
"Subscribers": [{
"Address": "your@email.com",
"Type": "EMAIL"
}],
"Threshold": 10,
"Frequency": "IMMEDIATE"
}'
AWS Cost Explorer 활용
# 서비스별 지난 30일 비용 조회
aws ce get-cost-and-usage \
--time-period Start=2026-03-10,End=2026-04-10 \
--granularity MONTHLY \
--metrics BlendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--query 'ResultsByTime[0].Groups[*].[Keys[0],Metrics.BlendedCost.Amount]' \
--output table
서비스별 절감 체크리스트
EC2
□ 미사용 인스턴스 중지 또는 종료
□ 개발 환경 인스턴스 자동 중지 스케줄 설정
□ 상시 운영 인스턴스 Savings Plans 또는 RI 전환
□ Graviton 인스턴스로 교체 (ARM 호환 확인)
□ 미사용 EBS 볼륨(스냅샷 포함) 삭제
□ Elastic IP 미사용 시 즉시 해제 (과금됨)
S3
□ Lifecycle 정책으로 오래된 객체 자동 이전
□ Intelligent-Tiering 적용 (불규칙 액세스 패턴)
□ Incomplete multipart upload 자동 삭제 (7일)
□ CloudFront 캐싱으로 직접 요청 감소
□ 버전 관리 활성화 버킷의 이전 버전 정리
□ S3 Server Access Logging 대상 버킷 확인
RDS
□ 개발/스테이징 환경 Multi-AZ 비활성화
□ 사용하지 않는 RDS 인스턴스 중지 또는 삭제
□ 상시 운영 DB Reserved Instance 구매 검토
□ 오래된 스냅샷 정리
□ Aurora Serverless v2 전환 검토 (가변 트래픽)
□ 스토리지 자동 확장 임계값 적절히 설정
기타
□ NAT Gateway → NAT Instance 교체 검토 (개발 환경)
□ VPC Gateway Endpoint (S3, DynamoDB) 활성화
□ CloudWatch 로그 보존 기간 설정 (기본값: 무기한)
□ 미사용 Elastic Load Balancer 삭제
□ AWS Budgets 월별 알림 설정
□ Cost Anomaly Detection 활성화
비용 최적화 효과 요약
| 방법 | 예상 절감 | 난이도 |
|---|---|---|
| 개발 환경 인스턴스 자동 중지 | 50~70% | 쉬움 |
| Savings Plans 1년 약정 | 30~40% | 쉬움 |
| Graviton 전환 | 20% | 쉬움 |
| S3 Lifecycle 정책 | 40~80% (저빈도 데이터) | 쉬움 |
| NAT Gateway → NAT Instance | $40~100/월 | 중간 |
| RDS Multi-AZ 개발 환경 제거 | 50% | 쉬움 |
| Aurora Serverless v2 전환 | 20~60% (가변 트래픽) | 중간 |
| CloudFront 캐싱 추가 | 30~70% (S3 요청) | 중간 |
관련 글: Kubernetes 입문 완전 가이드 · Docker 입문 완전 가이드 · GitHub Actions CI/CD 설정법