はじめに
こんにちは!2026 Japan AWS Jr.champions の神谷です!
※この内容をもとに、本の執筆を予定しています。(技術書展で発売予定)
本記事は2026年8月26日時点で確認できる情報をもとにしています。AWSの料金、リージョン対応、クォータ、機能は変更される可能性があります。金額を固定値で暗記せず、導入前に対象リージョンの公式料金ページと AWS Pricing Calculator で再計算してください。
この記事は「2026 Japan AWS Jr. Champions 真夏のQiitaリレー」の27日目の記事となります。
過去の投稿(リンク集)は以下リンクからご覧ください。
【開催!】2026 Japan AWS Jr. Champions 真夏のQiitaリレー
EC2・RDS・Lambda・ECS/Fargateで請求が跳ねる10の落とし穴
AWSのコスト事故は、単に「高いインスタンスを起動した」場合だけではありません。
近年は、EC2やRDSの本体料金よりも、次のような周辺コストが請求を押し上げるケースが増えています。
- CloudWatch Logsへの大量取り込み
- S3の旧バージョンや削除マーカーの蓄積
- NAT Gatewayを通過するコンテナイメージやログ
- Fargateタスクの低い実使用率
- Lambdaのリトライ、ログ、外部サービス連携
- Availability Zoneをまたぐデータ転送
- ECRの古いイメージ
- LambdaからRDSへの接続集中
- KMSキーとAPIリクエストの積み上がり
本記事では、まず多くの現場で遭遇する定番3件を扱い、その後に「そこも課金ポイントなのか」と気づきやすい注目7件を紹介します。
単なる節約テクニックではなく、各項目を次の観点で整理します。
- どのような構成で起きるか
- なぜ見落とすか
- 何を観測するか
- どう設計・自動化するか
- やってはいけない対策は何か
まず押さえたい結論
AWSの請求を押し上げるのは、コンピュート本体だけではありません。特に見落としやすいのは次の3つです。
1. 通信するたびに増えるコスト
NAT Gateway、AZ間通信、ECRからのイメージPullなど2. 失敗するほど増えるコスト
Lambdaの再試行、SQS再配信、ECSのCrash Loopなど3. 消したつもりでも残るコスト
EBS、Snapshot、S3旧バージョン、ECRイメージ、KMSキーなど
迷ったら最初に見るところ
- EC2中心の環境: 停止中EC2ではなく、EBS・Snapshot・Public IPv4・ALB・NATも見る
- Lambda中心の環境: 実行回数だけでなく、再試行・ログ・SQS・API Gateway・DB接続を見る
- ECS/Fargate中心の環境: タスク料金だけでなく、ECR Pull・NAT・ログ・最小タスク数を見る
目次
- この記事の対象読者
- 今回取り上げる10項目
- 定番1 CloudWatch Logs
- 定番2 EC2と残存リソース
- 定番3 S3 Lifecycle
- 注目4 NAT Gateway
- 注目5 ECS/Fargate
- 注目6 Lambdaの連鎖課金
- 注目7 AZ間通信
- 注目8 ECR
- 注目9 LambdaとRDS
- 注目10 KMS
- 横断対策
- 30分チェック
- まとめ
この記事の対象読者
- EC2、RDS、VPCを使ったサーバーベース環境を設計・運用している方
- Lambda、API Gateway、EventBridge、SQSを使ったサーバーレス環境を扱う方
- ECS/Fargate、ECRを導入している、または導入予定の方
- AWSの請求を月末に確認するだけの運用から脱却したい方
- コスト最適化をIaC、監視、タグ、ガードレールまで落とし込みたい方
今回取り上げる10項目
| No. | 区分 | 危険度 | 落とし穴 | 最初に確認するもの |
|---|---|---|---|---|
| 1 | 定番 | ★★★★★ | CloudWatch Logsの取り込み増 | ロググループ別の取り込み量 |
| 2 | 定番 | ★★★★☆ | EC2停止後のリソース残存 | EBS、Snapshot、Public IPv4、ALB |
| 3 | 定番 | ★★★★☆ | S3旧バージョンの増殖 | 非現行バージョンとLifecycle |
| 4 | 注目 | ★★★★★ | NAT Gatewayの通信課金 | 送信先、処理データ量、経路 |
| 5 | 注目 | ★★★★☆ | Fargateの低使用率常時稼働 | タスク予約値と実測利用率 |
| 6 | 注目 | ★★★★★ | Lambdaの再試行と連鎖課金 | Errors、Retries、周辺サービス |
| 7 | 注目 | ★★★★☆ | AZをまたぐ通信 | AZ境界と実通信経路 |
| 8 | 注目 | ★★★☆☆ | ECRイメージの蓄積 | 世代数、サイズ、untagged |
| 9 | 注目 | ★★★★☆ | LambdaによるRDS接続集中 | 同時実行数とDB接続数 |
| 10 | 注目 | ★★★☆☆ | KMSキーとAPI利用の積み上がり | キー台帳と利用先 |
危険度は絶対的な料金ランキングではなく、発見の遅れやすさ、影響範囲、複数サービスへの波及を踏まえた本記事上の目安です。
定番1. CloudWatch Logsの保持より「取り込み」が膨らむ
ひと言でいうと: Retention設定だけでは不十分です。保存前に流れ込むログ量を減らさない限り、取り込みは増え続けます。
よくある構成
障害調査のためDEBUGログを有効化
↓
元に戻し忘れる
↓
ECSタスクがオートスケール
↓
全タスクから巨大JSONを出力
↓
保存費より先にログ取り込み量が増える
CloudWatch Logsは、EC2、Lambda、ECS、API Gateway、VPC Flow Logsなど複数サービスのログ集約先になります。保持期間だけを設定しても、投入前のログ量は減りません。
2026年8月時点では、CloudWatch LogsにはStandard、Infrequent Accessなどのログクラスがあり、さらに公式ドキュメントではアクセスパターンに応じて階層を移すIntelligent Tieringも案内されています。ただし、ストレージ階層の最適化と、不要ログを最初から送らない設計は別問題です。
見落としやすい課金ポイント
- ログの取り込み量
- 長期保存
- Logs Insightsでスキャンするデータ量
- Live Tail等の分析機能
- メトリクスフィルターやカスタムメトリクス
- Subscription Filter先のサービス料金
設計の基本
1. ログレベルを環境別に固定する
開発: DEBUGを期限付きで許可
検証: INFO以上
本番: INFO / WARN / ERRORを基本とし、DEBUGは時限開放
2. 1リクエスト当たりのログ量を測る
「1日何GB」だけでなく、次の単位で見ると原因を追いやすくなります。
bytes / request
log events / request
bytes / ECS task
bytes / Lambda invocation
3. 機密情報と巨大ペイロードを出さない
リクエスト本文やレスポンス全文をそのまま記録すると、コストだけでなく情報管理上の負担も増えます。ID、処理時間、結果コード、相関IDなど、調査に必要な項目を構造化して記録します。
4. Log Group作成時にRetentionを設定する
Terraform例です。保持日数は例であり、監査・法務要件に合わせて変更してください。
resource "aws_cloudwatch_log_group" "app" {
name = "/prod/sample-api"
retention_in_days = 30
tags = {
Environment = "prod"
Owner = "platform-team"
RetentionDays = "30"
}
}
監視するもの
- サービス別・ロググループ別の取り込み量
- 前週比、前月比で急増したログ
- DEBUG文字列や巨大メッセージの割合
- Logs Insightsのスキャン量
- Retention未設定のロググループ
やってはいけないこと
- 「S3へ転送したから安い」と考え、CloudWatch側もS3側も無期限に残す
- 本番障害時にDEBUGを有効化し、解除期限を決めない
- すべてのコンテナで同じ冗長ログを出す
- ログ量を減らす代わりに必要な監査ログまで消す
定番2. EC2を停止して安心し、周辺リソースを見落とす
ひと言でいうと: EC2の停止と、環境全体の課金停止は同じではありません。
よくある構成
検証用EC2を停止
↓
「これで課金は止まった」と思う
↓
EBS、スナップショット、Elastic IP、ロードバランサーが残る
停止中のEC2インスタンスは、実行中とは課金状態が異なります。しかし、アタッチされたEBSや残存リソースまで自動的に消えるわけではありません。「停止」と「環境全体の課金停止」は同義ではない点が重要です。
見落としやすい対象
- EBSボリューム
- EBSスナップショット
- Elastic IPやPublic IPv4関連
- Application Load Balancer / Network Load Balancer
- NAT Gateway
- AMIと関連スナップショット
- CloudWatch Agentから送られ続ける別ホストの監視データ
設計の基本
1. Scheduleではなく「有効期限」を持たせる
Owner=team-a
Environment=dev
ExpiresAt=2026-09-30
AutoStop=true
曜日ベースの停止だけでは、不要になったリソースの削除まではできません。ExpiresAtを使うと、棚卸し対象を明確にできます。
2. 停止と削除を別Runbookにする
停止Runbook
1. 対象タグ確認
2. 本番除外
3. EC2停止
4. オーナー通知
削除Runbook
1. バックアップ要否確認
2. 依存リソース確認
3. EC2終了
4. EBS / EIP / ALB / Snapshot棚卸し
5. IaCとの差分確認
3. 低利用率だけで自動停止しない
CPUが低くても、踏み台、監視、ライセンス、待機系、夜間バッチなどの役割を持つ場合があります。CPU、ネットワーク、ディスクI/O、接続数、ジョブスケジュール、環境タグを組み合わせて判定します。
すぐ使える棚卸しCLI
aws ec2 describe-instances \
--filters Name=instance-state-name,Values=running,stopped \
--query 'Reservations[].Instances[].{Id:InstanceId,State:State.Name,Type:InstanceType,Tags:Tags}'
aws ec2 describe-volumes \
--filters Name=status,Values=available \
--query 'Volumes[].{Id:VolumeId,Type:VolumeType,Size:Size,CreateTime:CreateTime}'
aws ec2 describe-addresses \
--query 'Addresses[].{AllocationId:AllocationId,PublicIp:PublicIp,InstanceId:InstanceId,AssociationId:AssociationId}'
やってはいけないこと
- 本番と検証を同じ自動停止条件にする
- Auto Scaling Group配下のEC2を直接止め、置き換えで再作成される
- インスタンスストア上の必要データを確認せず停止・終了する
- 削除済みインスタンスのAMIとスナップショットを永久保存する
定番3. S3 Lifecycle未設定で旧バージョンまで増殖する
ひと言でいうと: コンソール上で1ファイルに見えても、旧バージョンが大量に残っている場合があります。
よくある構成
Versioningを有効化
↓
アプリが同じキーへ毎日上書き
↓
見た目は常に1ファイル
↓
非現行バージョンは裏で増え続ける
S3では、現行オブジェクトだけを見て容量を判断すると実態を見誤ります。Versioning有効時の非現行バージョン、削除マーカー、未完了マルチパートアップロードも棚卸し対象です。
設計の基本
1. データを用途別に分ける
業務データ
監査ログ
一時ファイル
バックアップ
配布物
保持要件が異なるものを同じバケット・同じプレフィックスに混在させると、Lifecycle Ruleが複雑になります。
2. 現行と非現行を別々に管理する
{
"Rules": [
{
"ID": "abort-incomplete-multipart-upload",
"Status": "Enabled",
"Filter": { "Prefix": "" },
"AbortIncompleteMultipartUpload": {
"DaysAfterInitiation": 7
}
},
{
"ID": "expire-old-noncurrent-versions",
"Status": "Enabled",
"Filter": { "Prefix": "archive/" },
"NoncurrentVersionExpiration": {
"NoncurrentDays": 90,
"NewerNoncurrentVersions": 3
}
}
]
}
上記は構造例です。最低保管期間、取り出し料金、削除要件、Object Lockの有無を確認してから適用してください。
3. ストレージクラスは取り出し方まで含めて選ぶ
「安価なクラスへ移す」だけでは不十分です。アクセス頻度、復元時間、最低保管期間、取り出し費用、オブジェクトサイズを合わせて判断します。アクセスパターンを予測しにくいデータではIntelligent-Tieringも候補になります。
監視するもの
- Current / Noncurrent versionの容量
- Delete Marker数
- Incomplete Multipart Upload
- プレフィックス別容量
- 小サイズオブジェクトの大量発生
- レプリケーション先を含む総容量
やってはいけないこと
- Versioningを無効化すれば旧バージョンが消えると思う
- Glacier系へ移行後の復元要件を決めていない
- Object Lock対象に削除前提のLifecycleを設計する
- ログと業務データを同じ保持ルールにする
注目4. NAT Gatewayがコンピュートより高くなる
ひと言でいうと: Private Subnetからどこへ、何GB送るかを設計しないと、通信が主役になります。
よくある構成
Private SubnetのECSタスク
↓
起動失敗して再試行
↓
毎回ECRから大きなイメージをPull
↓
NAT Gatewayを経由
↓
短命タスクなのに通信量だけ積み上がる
NAT Gatewayは、存在時間だけでなく処理データ量も確認すべきサービスです。さらに、通信の前後で別のデータ転送料が関係する構成もあるため、「NATの行だけ」では全体像を把握できません。
見落としやすい通信
- ECS/FargateによるECRイメージPull
- S3へのアクセス
- CloudWatch Logsへの送信
- OSパッケージ更新
- Secrets Manager、SSM、KMSなどへのアクセス
- Lambdaの外部API通信
- 失敗タスクや無限再試行による反復通信
対策の考え方
1. 宛先別に経路を分解する
S3 / DynamoDB
→ Gateway Endpointを検討
ECR API / ECR DKR / CloudWatch Logs / Secrets Manager等
→ Interface VPC Endpointを検討
一般インターネット
→ NAT Gateway、プロキシ、IPv6経路等を要件に応じて比較
2. Endpointも作りすぎない
Interface VPC Endpointにも、エンドポイントの存在や処理データに関する料金があります。NAT Gatewayを避けるために全サービス分を作ると、低通信環境では逆に固定費が増える場合があります。
比較時は次の変数を置きます。
AZ数
Endpoint数
月間通信量
通信先サービス
可用性要件
運用負荷
3. Flow Logsと請求データを突き合わせる
Cost ExplorerまたはCURだけでは「どのワークロードの通信か」まで分からない場合があります。VPC Flow Logs、NAT Gatewayメトリクス、ECSのデプロイ履歴、Lambdaのエラー件数を時刻で突き合わせます。
IaC例: S3 Gateway Endpoint
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.aws_region}.s3"
vpc_endpoint_type = "Gateway"
route_table_ids = aws_route_table.private[*].id
}
やってはいけないこと
- 「Private Subnetだから安全」で経路と費用の設計を終える
- NAT Gatewayを1台に集約し、可用性やAZ間経路を無視する
- Interface Endpointを無条件に全AZ・全サービスで作る
- ECR Pullの増加原因であるCrash Loopを放置する
注目5. Fargateを「サーバーレスだから安い」で選ぶ
ひと言でいうと: Fargateは運用負荷を下げる選択肢です。常に最安になる選択肢ではありません。
よくある構成
EC2管理をなくしたい
↓
ECS on Fargateへ移行
↓
各タスクを大きめに設定
↓
常時起動、低使用率
↓
運用は楽になったが請求は増えた
Fargateの価値は、ホストOSやクラスターキャパシティの管理を減らせる点にあります。これは「必ず最安」という意味ではありません。タスクに指定したvCPU・メモリ、稼働時間、OS/CPUアーキテクチャ、追加エフェメラルストレージなど、対象料金の単位に合わせて比較します。
Fargateが向きやすい形
- 実行時間が明確なバッチ
- アイドル時間が長く、タスク数を落とせるサービス
- 小規模チームでホスト管理を減らしたい環境
- ワークロードの分離を優先する環境
- 短期間で立ち上げたいサービス
EC2 Capacity Providerも比較したい形
- 24時間稼働で利用率が安定
- 複数サービスを同一クラスターへ高密度に配置できる
- SpotやSavings Plans等を含めたキャパシティ設計を行える
- Daemon型エージェントやホストレベル制御が必要
改善ポイント
1. CPUとメモリの実測値を見る
ECSタスク定義の予約値だけではなく、コンテナ単位の利用率、ピーク、OOM、スロットリングを確認します。
2. Minimum task countを疑う
Auto Scalingが設定されていても、最小タスク数が過大ならアイドルコストは減りません。障害時容量と通常時容量を分けて考えます。
3. Fargate Spotを「雑に混ぜない」
中断を許容できるタスク、キューで再実行できる処理、冪等性があるバッチなど、退避可能な処理に限定します。
4. ARM64を検証する
依存ライブラリ、ベースイメージ、ネイティブ拡張が対応する場合は、ARM64を含む選択肢を性能試験と価格試算に入れます。
やってはいけないこと
- 開発・検証・本番で同じタスクサイズを使う
- CPU平均だけを見てメモリ不足やスパイクを無視する
- すべてをFargateまたはEC2の一択にする
- インフラ費だけを比較し、運用工数を無視する
注目6. Lambda本体以外の連鎖課金と再試行を見落とす
ひと言でいうと: 1回の失敗が、再試行、ログ、キュー、API、DBアクセスを連鎖させます。
よくある構成
EventBridgeからLambdaを起動
↓
Lambdaが失敗
↓
非同期再試行またはSQS再配信
↓
ログ、API呼び出し、DBアクセスも繰り返す
↓
障害中なのにリクエスト数と周辺課金が増える
Lambdaのコスト評価を「呼び出し回数と実行時間」だけで終えると、API Gateway、CloudWatch Logs、NAT Gateway、SQS、Step Functions、KMS、外部API、データベースなどの連鎖を見落とします。
また、AWSは2025年8月1日から、LambdaのINITフェーズに関する課金取り扱いを標準化すると案内していました。2026年8月時点の設計では、初期化処理も含めて実測し、依存関係の読み込みやハンドラー外処理を確認することが重要です。
改善策
1. 1ビジネス処理当たりで試算する
1件の注文処理
API Gateway: 1 request
Lambda: 1から複数invocations
SQS: send / receive / delete
Step Functions: state transitions
CloudWatch Logs: bytes
KMS: API requests
NAT: processed bytes
RDS: connections / load
2. 冪等性を持たせる
再試行された際に、二重課金、二重メール、二重DB更新を起こさない設計にします。イベントIDや業務キーを利用して重複処理を防ぎます。
3. 同時実行数をガードレールとして使う
Reserved Concurrencyは、下流サービスの保護や暴走範囲の制限に使えます。ただし、絞りすぎるとスロットリングと再試行を増やすため、キュー深度や処理時間と合わせて設定します。
4. DLQまたは失敗送信先を設計する
「失敗したら何度でも再試行」ではなく、再試行回数、待機、隔離、再投入、オーナー通知まで決めます。
観測項目
- Invocations / Errors / Throttles / Duration
- ConcurrentExecutions
- Init DurationとBilled Duration
- SQS ApproximateAgeOfOldestMessage
- DLQ滞留数
- 1イベント当たりのログ量
- 外部APIの失敗・タイムアウト
やってはいけないこと
- 1分ごとのポーリングを大量の関数で行う
- タイムアウトだけ長くし、外部通信のタイムアウトを設定しない
- DLQを置くだけで再処理Runbookを作らない
- メモリを下げれば必ず安くなると思う
注目7. Multi-AZを可用性だけで考え、AZ間通信を見ない
ひと言でいうと: Multi-AZは重要ですが、可用性と実際の通信経路はセットで設計します。
よくある構成
ALBは複数AZ
ECSも複数AZ
RDSもMulti-AZ
↓
可用性は高そう
↓
実際の通信経路はAZを頻繁に横断
複数AZ設計は可用性の基本ですが、データ転送の扱いまで確認する必要があります。重要なのは「Multi-AZをやめる」ことではなく、どの通信がどのAZを通り、どのサービス料金に現れるかを把握することです。
確認したい経路
- ALBからEC2/ECSターゲット
- ECS/EC2からRDSまたはAurora
- ECSノードからNAT Gateway
- PrivateLink経由通信
- Transit Gateway経由通信
- レプリケーションやバックアップ
- クロスリージョン通信
設計の基本
1. 構成図にAZ境界を描く
サービスアイコンだけでなく、サブネット、AZ、ルート、NAT、エンドポイント、DB配置を描きます。
2. 可用性と通信局所性を両立する
単純に同一AZへ固定すると障害耐性を損なう場合があります。Zone aware routing、ターゲット配置、クロスゾーン設定、フェイルオーバー時の挙動を、サービスごとの仕様に基づいて検討します。
3. 通常時と障害時を分けて試算する
通常時の通信最適化だけでなく、AZ障害時に残存AZへ集中した際の性能と費用も確認します。
やってはいけないこと
- 「同じVPC内ならデータ転送はすべて無料」と思う
- コスト削減のため単一AZ化し、可用性要件を壊す
- NAT Gatewayを別AZに置いたまま全通信を向ける
- 構成図にAZとルートを書かない
注目8. ECRのイメージと失敗デプロイが積み上がる
ひと言でいうと: 古いイメージはストレージだけでなく、再Pull時の通信や障害ループにも波及します。
よくある構成
mainへマージするたびにイメージPush
↓
コミットSHAタグを付与
↓
ロールバックのため全部保持
↓
untaggedと古いタグが増え続ける
ECRのLifecycle Policyでは、条件に合うイメージを期限切れまたはアーカイブ対象にできます。公式ドキュメントでは、ポリシー適用前にPreviewで対象を確認することが推奨されています。
設計の基本
1. タグ戦略を決める
本番デプロイ: release-* またはバージョンタグ
検証: branch-* / commit SHA
一時ビルド: untaggedになり得る
latestだけで運用すると、どのイメージが稼働中か、どれを削除してよいか判断しにくくなります。
2. 「世代数」と「経過日数」を使い分ける
{
"rules": [
{
"rulePriority": 1,
"description": "Expire untagged images",
"selection": {
"tagStatus": "untagged",
"countType": "sinceImagePushed",
"countUnit": "days",
"countNumber": 7
},
"action": { "type": "expire" }
},
{
"rulePriority": 2,
"description": "Keep recent development images",
"selection": {
"tagStatus": "tagged",
"tagPrefixList": ["dev-"],
"countType": "imageCountMoreThan",
"countNumber": 20
},
"action": { "type": "expire" }
}
]
}
3. 削除前に稼働参照を確認する
ECS Task Definition、EKSマニフェスト、デプロイ履歴、ロールバックRunbookから参照されるイメージを確認します。Digest固定を採用している場合は、タグだけで削除可否を判断しないようにします。
4. Crash Loopはストレージ以外も増やす
失敗タスクが大きなイメージを繰り返しPullすると、ECRストレージだけでなく、NAT Gateway、データ転送、ログ、Fargate実行時間にも影響します。
やってはいけないこと
- PreviewなしでLifecycle Policyを本番適用する
- 本番リリースと一時ビルドを同じ削除条件にする
-
latestのみでロールバック可能性を担保する - イメージサイズを計測せず、毎回巨大レイヤーを再作成する
注目9. LambdaからRDSへ直接つなぎ、DBを大型化する
ひと言でいうと: DBの性能不足ではなく、短時間に接続が集中しているだけかもしれません。
よくある構成
APIアクセス急増
↓
Lambda同時実行数が増加
↓
DB接続も急増
↓
RDSの接続数・メモリが逼迫
↓
DBインスタンスを大型化して回避
これは「RDSが小さい」のではなく、「接続管理がワークロード形状に合っていない」可能性があります。Lambdaは短時間で多数の実行環境が立ち上がり得るため、各実行が独立して接続を確立するとDB側の負担になります。
RDS Proxyは、アプリケーションとデータベースの間で接続をプール・共有する選択肢です。ただし追加料金、対応エンジン、認証方式、トランザクション特性、フェイルオーバー要件を確認し、「入れれば必ず安い」とは考えないようにします。
改善策
1. 先に原因を分解する
接続数不足
クエリ遅延
ロック競合
CPU不足
メモリ不足
I/O不足
Lambda側タイムアウト
2. 同時実行数とDB許容量をつなぐ
LambdaのReserved Concurrency、SQSのバッチサイズ、ワーカー数、DBの最大接続数を別々に決めず、一つの容量モデルにします。
3. 1回の実行で接続を使い回す
実行環境が再利用される場合に備え、接続生成をハンドラー外へ置く実装も検討します。ただし、切断、タイムアウト、再接続、トランザクション境界を適切に扱います。
4. 非同期化を検討する
即時応答が不要な書き込みはSQS等で平準化し、DBへの同時到達数を制御します。
観測項目
- DatabaseConnections
- CPUUtilization / FreeableMemory
- Read/WriteLatency
- ロック、遅いクエリ、接続待ち
- Lambda ConcurrentExecutions / Duration / Errors
- RDS Proxy利用時の接続関連メトリクス
やってはいけないこと
- 接続問題をインスタンスサイズの増加だけで解決する
- Lambdaごとに無制限にコネクションを生成する
- Proxy導入前後の性能と費用を比較しない
- 非同期処理で順序性や重複排除を設計しない
注目10. KMSキーとAPI利用を「ほぼ無料」と思い込む
ひと言でいうと: 暗号化を弱めるのではなく、専用キーが必要な境界を明文化します。
よくある構成
システム × 環境 × リージョンごとにCustomer managed key作成
↓
S3、EBS、ECR、Secrets Manager等で利用
↓
キー数とAPIリクエストが積み上がる
↓
どのキーを廃止できるか分からない
KMSはセキュリティ・監査上重要なサービスです。コストだけを理由に暗号化要件を弱めるべきではありません。一方で、AWS managed key、customer managed key、サービス側の暗号化方式を要件なしに混在させると、キー管理と請求の両方が複雑になります。
ECRの公式ドキュメントでは、デフォルトでS3管理キーによるサーバー側暗号化を利用し、より細かな制御が必要な場合にKMSキーを選択できると説明されています。つまり、すべてのリポジトリで機械的にcustomer managed keyを作るのではなく、制御・監査・分離要件を明文化して選ぶことが重要です。
設計の基本
1. キー作成の判断基準を持つ
- 独立したキーポリシーが必要か
- 管理者分離が必要か
- 監査証跡をキー単位で分ける必要があるか
- 外部キー管理やローテーション要件があるか
- サービスやデータ境界を分ける必要があるか
2. キー台帳を作る
Key ARN
Alias
Owner
Environment
Purpose
Connected services
Deletion policy
Review date
3. APIリクエストも観測する
S3やECRなど、利用サービスの動作に伴ってKMS APIが呼ばれることがあります。高頻度ワークロードでは、キーの月額だけでなくAPI利用もCost ExplorerやCURで確認します。
4. 削除は即断しない
キーを削除すると、暗号化済みデータを復号できなくなる可能性があります。無効化、影響調査、待機期間、バックアップ、復旧要件を含むRunbookが必要です。
やってはいけないこと
- コスト削減だけを理由に暗号化を外す
- 命名規約なしでキーを増やす
- 利用先を調べずキーを無効化・削除する
- AWS managed keyとcustomer managed keyを要件なしに混在させる
横断対策:10個の落とし穴を個別対応で終わらせない
1. コスト配賦タグを必須化する
推奨例です。
Owner
Project
Application
Environment
CostCenter
ManagedBy
ExpiresAt
DataClassification
表記揺れを防ぐため、owner、Owner、OWNERを併存させないルールにします。タグポリシーやIaC検査を利用し、作成後ではなく作成時に是正します。
2. 可視化、最適化、計画を一つのサイクルにする
可視化
Cost Explorer / CUR / Cost Anomaly Detection
↓
最適化
Cost Optimization Hub / Compute Optimizer / Trusted Advisor
↓
計画
Budgets / Pricing Calculator / Forecast
↓
実装
IaC / CI policy / EventBridge / Lambda / SSM
↓
検証
実績と見積もりの差分レビュー
3. 請求アラートを「通知だけ」で終わらせない
アラートには、最低限次を含めます。
- 所有チーム
- 増加したサービス
- 対象アカウントとリージョン
- 前日・前週との差
- 最初に見るダッシュボード
- 一次対応Runbook
- 自動停止してよい対象と、してはいけない対象
4. IaCレビューにコスト観点を入れる
Pull Requestで次を確認します。
[ ] 新しい時間課金リソースはあるか
[ ] データ処理課金はあるか
[ ] AZ・リージョンをまたぐ通信はあるか
[ ] ログの出力量と保持期間を定義したか
[ ] 最小・最大スケール値は妥当か
[ ] Lifecycle Policyはあるか
[ ] OwnerとExpiresAtがあるか
[ ] 障害時の再試行上限があるか
[ ] 削除時に残るリソースは何か
30分でできる初動チェック
EC2 / RDS環境
- 停止中EC2に残るEBSを確認
- 未アタッチEBSを確認
- 古いSnapshotとAMIを確認
- アイドルRDSを確認
- 開発RDSの稼働時間を確認
- NAT GatewayとALBの残骸を確認
- AZ間・リージョン間通信を確認
Lambda / API Gateway環境
- Invocations、Errors、Throttles、Durationを確認
- 再試行回数とDLQを確認
- INIT処理と依存ライブラリを確認
- ログのbytes/invocationを確認
- VPC接続時のNAT経路を確認
- RDS接続数を確認
- 1業務処理当たりの周辺サービス呼び出し数を確認
ECS/Fargate環境
- タスクCPU・メモリの予約値と実測値を比較
- Minimum task countを確認
- Crash Loopと再デプロイ回数を確認
- ECRイメージサイズと世代数を確認
- ECR/S3/LogsへのVPC経路を確認
- FargateとEC2 Capacity Providerを同条件で比較
- Spot適用可能なタスクを分類
まとめ
2026年のAWSコスト最適化では、EC2やRDSのサイズだけを見ても不十分です。
特に注意したいのは、次の3種類の「見えにくい増幅」です。
1. データ量の増幅
- CloudWatch Logsの取り込み
- NAT Gatewayの処理データ
- AZ間・リージョン間のデータ転送
- ECRのイメージPull
2. 再試行の増幅
- Lambdaの非同期再試行
- SQSの再配信
- ECSのCrash Loop
- DB接続失敗からのリトライ
3. 残存リソースの増幅
- EBSとSnapshot
- S3の非現行バージョン
- ECRの古いイメージ
- KMSキー
- NAT Gateway、Endpoint、ALB
大切なのは、月末に「高かったサービス」を探すことではありません。
アーキテクチャレビューの段階で課金単位を列挙し、実行回数・稼働時間・保存量・データ転送量・再試行回数を観測可能にすること。
さらに、タグ、IaC、Budgets、Cost Anomaly Detection、Cost Optimization Hub、Compute Optimizer、Trusted Advisorを継続運用へ組み込み、誰が、いつ、何を見て、どう是正するかまで決めることで、コスト最適化は一度きりの削減施策から設計品質へ変わります。