NAT Gateway egress 비용 폭탄 맞고 깨달은 것들
지난달 AWS 청구서를 보고 멘탈이 나갔다. NAT Gateway 한 줄에 $4,200. 평소의 3배다. 우리 팀 인프라 전체 비용에서 NAT Gateway가 차지하는 비중이 갑자기 28%까지 치솟았다는 뜻이다.
처음엔 누가 큰 데이터셋이라도 외부에 올렸나 싶었다. 근데 트래픽 패턴을 까보니 그게 아니었다. 범인은 ECR이었다. 정확히는, 우리가 6개월 전에 추가한 워커 노드 그룹이 ECR public 이미지를 NAT Gateway 통해서 매번 끌어다 쓰고 있었던 것.
처음 본 게 다가 아니었다
처음엔 VPC Flow Logs를 켜고 NAT EIP의 destination port를 분석했다. 결과를 보고 좀 당황했는데, 443 트래픽이 전체의 87%를 차지했다. 어디로 가는지 좀 더 파보려고 했더니, Flow Logs 만으로는 도메인까지는 안 잡혔다. AWS 서비스 IP 대역으로 가는 트래픽이 압도적으로 많았다.
# CloudWatch Logs Insights 쿼리
fields srcaddr, dstaddr, bytes
| filter action = "ACCEPT" and dstport = 443
| stats sum(bytes) as totalBytes by dstaddr
| sort totalBytes desc
| limit 20
dstaddr를 reverse lookup 해보니 절반이 ECR endpoint, 나머지 상당수는 S3와 CloudWatch Logs였다. 그러니까 우리는 AWS 자기네 서비스를 호출하면서 외부 인터넷 가는 것처럼 NAT Gateway에 GB당 $0.045을 꼬박꼬박 내고 있었던 거다.
좀 더 자세히 따져보니 이렇게 됐다:
- ECR 이미지 풀: 월 38TB → $1,710
- S3 (앱 로그 적재): 월 22TB → $990
- CloudWatch Logs: 월 8TB → $360
- 나머지 외부 트래픽: 월 26TB → $1,170
합치면 청구서 숫자가 거의 맞는다. AWS 내부로 가는 트래픽이 NAT Gateway 비용의 60% 넘게 먹고 있었던 셈이다.
VPC Endpoint으로 갈아끼우기
해결책은 단순했다. AWS 서비스 트래픽은 VPC Endpoint로 빼야 한다. 근데 막상 작업해보니 함정이 좀 있었다.
Gateway Endpoint vs Interface Endpoint
S3와 DynamoDB만 Gateway Endpoint를 쓸 수 있다. 그것도 정확하게는 같은 리전 내 S3만. 다른 모든 AWS 서비스는 Interface Endpoint(PrivateLink)인데, 이건 시간당 $0.01 곱하기 AZ 수, 그리고 처리 데이터 GB당 $0.01이 추가된다.
ECR의 경우 Interface Endpoint를 두 개 만들어야 한다. com.amazonaws.region.ecr.api(인증)랑 com.amazonaws.region.ecr.dkr(레이어 다운로드). 둘 다 만들어야 동작한다. 한 쪽만 만들고 왜 안 되는지 30분 헤맸다.
resource "aws_vpc_endpoint" "ecr_api" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.ap-northeast-2.ecr.api"
vpc_endpoint_type = "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpce.id]
private_dns_enabled = true
}
resource "aws_vpc_endpoint" "ecr_dkr" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.ap-northeast-2.ecr.dkr"
vpc_endpoint_type = "Interface"
subnet_ids = aws_subnet.private[*].id
security_group_ids = [aws_security_group.vpce.id]
private_dns_enabled = true
}
# S3는 Gateway Endpoint. ECR 레이어가 결국 S3에 있어서 이것도 필수
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.ap-northeast-2.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = aws_route_table.private[*].id
}
ECR 작업하면서 알게 된 건데, ECR이 실제 이미지 레이어는 S3에 저장한다. 그래서 ECR Interface Endpoint만 만들고 S3 Gateway Endpoint를 안 만들면 레이어 다운로드가 다시 NAT Gateway로 새어 나간다. 이거 진짜 모르고 지나치기 쉽다.
손익분기점 계산
Interface Endpoint도 공짜는 아니다. AZ 하나당 $7.20/월(시간당 $0.01 × 720시간)이 기본으로 깔린다. AZ 3개면 $21.60/월. 데이터 처리는 GB당 $0.01.
NAT Gateway는 GB당 $0.045. 차이가 GB당 $0.035다. 그럼 손익분기점은:
$21.60 / $0.035 = 약 617GB/월
월 617GB 이상이면 Interface Endpoint가 이득. 우리는 ECR만 월 38TB였으니 압도적으로 이득이었다. 근데 트래픽이 적은 서비스라면 굳이 Interface Endpoint를 만들 필요가 없다는 뜻이기도 하다. 무작정 다 만들면 오히려 비용이 늘 수도 있다.
옮긴 다음 검증
VPC Endpoint를 추가하고 끝이 아니다. 라우팅이 실제로 endpoint로 가는지 확인해야 한다.
# 노드에서 직접 확인
kubectl debug node/ip-10-0-1-23 -it --image=nicolaka/netshoot
# ECR endpoint resolution 확인
dig +short api.ecr.ap-northeast-2.amazonaws.com
# 결과가 vpce-xxx.api.ecr.ap-northeast-2.vpce.amazonaws.com 으로 떨어지면 OK
# 만약 public IP가 나오면 private DNS가 안 켜진 것
# 실제 패킷 경로
traceroute api.ecr.ap-northeast-2.amazonaws.com
private_dns_enabled = true를 빠뜨리면 DNS는 여전히 public IP로 resolve된다. 그리고 VPC 자체의 enable_dns_hostnames와 enable_dns_support가 둘 다 켜져 있어야 한다. 우리 dev 계정에는 후자가 꺼져 있어서 한참 헤맸다.
변경 후 청구서
다음 달 청구서가 떨어졌다. NAT Gateway 비용 $4,200 → $1,580. VPC Endpoint 추가 비용은 $310 정도. 순감소 $2,310. 1년이면 $27,720.
전체적으로 보면 트래픽의 60% 정도가 VPC Endpoint로 빠졌고, 나머지는 정말 외부로 나가야 하는 트래픽(서드파티 API, public DNS 등)이라 NAT Gateway에 남았다. 이 잔여 트래픽은 fck-nat 같은 NAT instance로 더 줄일 수 있는지 검토 중이다. 다만 운영 부담을 생각하면 dev 환경에만 적용하는 게 맞을 것 같다.
회고
이 사건에서 제일 부끄러운 건, 우리 팀이 매월 Cost Explorer를 보긴 했다는 거다. 근데 "NAT Gateway"가 한 줄로 묶여있다 보니 그 안에 뭐가 있는지 파보질 않았다. 비용 anomaly detection도 켜놨지만 trend가 완만하게 올라서 알람이 안 떴다.
배운 점:
- NAT Gateway 비용이 인프라 비용의 5% 넘으면 무조건 VPC Flow Logs로 destination 분석부터
- Interface Endpoint는 트래픽 양에 따라 손익이 갈리므로 무작정 만들지 말 것
- ECR은 반드시 ecr.api, ecr.dkr, s3 endpoint 세 개 세트로
- private_dns_enabled 빠뜨리면 비용 절감 효과 0
다음에는 IPv6 egress-only internet gateway로 어디까지 줄일 수 있는지도 한번 정리해보려고 한다.
'IT > AWS' 카테고리의 다른 글
| Karpenter NodeOverlay로 GPU spot 가격 흔들림 잡아보다 (alpha 도입 보류한 이야기) (0) | 2026.05.29 |
|---|---|
| EKS Pod Identity로 IRSA 마이그레이션, 이렇게 한다 (0) | 2026.05.29 |
| EKS Auto Mode 6개월, 한 번 더 같은 선택을 할까 (0) | 2026.05.28 |
| EKS CoreDNS, 노드 늘리기 전에 이거 먼저 보자 (0) | 2026.05.26 |
| NAT Gateway 청구서, VPC Endpoint로 줄이는 법 (0) | 2026.05.23 |