AWS請求を月3万円下げた実体験:見落としがちなNAT Gateway/EBS/未使用EIPの掃除手順
結論
個人開発のAWSアカウントで毎月「使ってないのに」発生していた約3万円のうち、その大半は NAT Gateway・放置EBSボリューム・未アタッチEIP の3つでした。コンピュート費用ではなく「立てっぱなしのネットワーク/ストレージ資源」が真犯人です。先に内訳を晒すと以下のとおり。
| 項目 | 月額 | 原因 |
|---|---|---|
| NAT Gateway × 2 | 約13,000円 | 検証用VPCに残存 |
| 未使用EBS (gp2 合計400GB) | 約4,800円 | 削除済EC2のルートボリューム |
| 未アタッチEIP × 5 | 約2,600円 | 旧構成のIP |
| 旧スナップショット 300GB | 約1,500円 | 自動取得の放置 |
合計で月3万円弱。一度の棚卸しで恒久的に消えるコストなので、費用対効果は抜群です。
根拠:なぜ気づきにくいか
NAT Gatewayは 起動しているだけで時間課金(東京 約$0.062/h ≒ 月4,500円)+ データ処理料 が発生します。トラフィックがゼロでも請求は止まりません。EBSも同様で、EC2を消してもルートボリュームが「Delete on Termination=false」だと残骸として課金され続けます。EIPは どこにもアタッチされていないと課金(アタッチ中は無料)という直感に反する仕様です。Cost Explorerの円グラフでは「EC2-Other」に丸められて埋もれるため、見落とします。
手順:CLIで一掃する
1. 未アタッチEIPを洗い出して解放
aws ec2 describe-addresses \
--query "Addresses[?AssociationId==null].[PublicIp,AllocationId]" \
--output table
# 確認後に解放(AllocationIdを指定)
aws ec2 release-address --allocation-id eipalloc-xxxxxxxx
2. 未アタッチEBSボリュームを削除
# status=available が「どこにも繋がっていない」ボリューム
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query "Volumes[].[VolumeId,Size,VolumeType]" --output table
aws ec2 delete-volume --volume-id vol-xxxxxxxx
3. NAT Gatewayの要否を判断して削除
本当にプライベートサブネットから外向き通信が要るか確認します。検証環境なら多くの場合不要です。
aws ec2 describe-nat-gateways \
--filter Name=state,Values=available \
--query "NatGateways[].[NatGatewayId,VpcId]" --output table
aws ec2 delete-nat-gateway --nat-gateway-id nat-xxxxxxxx
削除後、関連EIPも上記手順1で解放するのを忘れずに。常時必要なら、複数AZで冗長化せず1台に集約するか、VPCエンドポイント(S3/DynamoDBはGateway型で無料)に逃がすとデータ処理料を削れます。
4. 古いスナップショットの掃除
aws ec2 describe-snapshots --owner-ids self \
--query "Snapshots[?StartTime<='2025-12-01'].[SnapshotId,VolumeSize,StartTime]" \
--output table
aws ec2 delete-snapshot --snapshot-id snap-xxxxxxxx
再発防止
掃除して終わりにせず、再発を止めます。
- AWS Budgets で月額アラートを設定(例:5,000円超でメール通知)。
- 月初に上記4コマンドを回す棚卸しを習慣化。スクリプト化してcronに載せると確実です。
- EC2作成時はルートボリュームの Delete on Termination=true を徹底。
このネットワーク/ストレージの棚卸しは、コードを1行も変えずに固定費を月3万円圧縮できる、個人開発でいちばん割のいい作業でした。
関連リンク
※一部にアフィリエイトリンク・自社商品を含みます。