AWS実践 #6 コスト最適化とダッシュボード — トラックの締めくくり

読了 10分

#1 ~ #5 でインフラ / DB / CI/CD / IaC / モニタリングまで — 運用可能なシステムが 1 つにまとまりました。最後に残ったテーマ: どれだけコストがかかっているか、そしてそのコストをどう削るか

この記事の半分は コスト最適化、もう半分は AWS トラック 27 編の振り返り

請求書がどこから漏れているか #

基礎 #3 コスト管理 で支払いアラートと Cost Explorer の基本は押さえました。今回はその上で 本番システムのコストを実際に削る 段階です。

典型的な小本番 (ECS Fargate + RDS + ALB + CloudFront + Logs) の月次請求書の比率:

リソース比率特徴
ECS Fargate (vCPU + メモリ時間)30~50%最大
RDS (インスタンス + Storage + IO)20~30%Multi-AZ なら 2 倍
NAT Gateway / Egress10~20%忘れられがち
ALB / トラフィック5~10%時間 + LCU
CloudWatch Logs / Metrics5~10%retention 抜けで暴走
S3 / ECR2~5%イメージ / オブジェクトの累積
その他5%DNS、KMS、Secrets、…

この表を見て「うちの請求書に似ている」と思えたら — 次のパターンが効きます。

1) Cost Explorer — どこからお金が出ているかをまず #

Cost Explorer が請求書をスライス / ダイスします。コンソールで:

よく使う分析
1) サービス別        — Fargate vs RDS vs Logs (一番大きい)
2) タグ別            — env=prod vs env=dev (環境別コスト)
3) 利用タイプ別       — DataTransfer-Out-Bytes vs BoxUsage など
4) リージョン別       — 寝ている別リージョンのリソース (#1 落とし穴)
5) 時系列            — 昨日から急上昇した項目

CLI でも #

今月のサービス別コスト
aws ce get-cost-and-usage \
  --time-period Start=$(date -u +%Y-%m-01),End=$(date -u +%Y-%m-%d) \
  --granularity DAILY \
  --metrics BlendedCost \
  --group-by Type=DIMENSION,Key=SERVICE

Cost Anomaly Detection #

ML ベースの異常検知。普段のパターンから外れると自動通知。

異常モニター (サービス単位)
aws ce create-anomaly-monitor \
  --anomaly-monitor '{
    "MonitorName": "blog-services",
    "MonitorType": "DIMENSIONAL",
    "MonitorDimension": "SERVICE"
  }'

基礎 #3 のコストアラートが「閾値超え」なら、Cost Anomaly は「普段と違う」 — 微妙な漏れを掴む仕組み。

2) Compute コスト — Fargate の 3 つのポイント #

A) Right Sizing — 本当に必要な分だけ #

CloudWatch Container Insights (#5) の平均 CPU / メモリ使用率を見て task サイズを調整。

Right Sizing の勘所
現状: cpu=1024, memory=2048
観測: 平均 CPU 15%、p95 35%、メモリ平均 30%
調整: cpu=512, memory=1024  → コスト 50% 削減

CPU 平均が 30~50% で回っているのが健全。20% 未満なら大きすぎ (それでも burst の余裕は残す)。

小規模では Compute Optimizer が自動で推奨してくれます — コンソールで一度オンに。

B) Fargate Spot — 70% 安い #

バッチ的 / 再起動可能な task は Fargate Spot で:

capacity provider strategy
resource "aws_ecs_service" "this" {
  capacity_provider_strategy {
    capacity_provider = "FARGATE"
    weight            = 1     # base on-demand
    base              = 2
  }

  capacity_provider_strategy {
    capacity_provider = "FARGATE_SPOT"
    weight            = 4     # 追加分は Spot 優先
  }
}

このパターン: 常に 2 個は on-demand、それ以上は 4:1 で Spot。負荷が減れば Spot から先に片付け。

中断 (interruption) が起きると ECS が新 task を立てますが ~120 秒のダウンタイムがありえます。本番トラフィックでは一部だけ Spot に — 100% Spot は大きなリスク。

C) Graviton (ARM) — 20% 安い + 20% 速い #

db.t4g.* (RDS)、Fargate ARM オプション、EC2 Graviton (m7gc7g) — AWS の ARM チップ。コンテナイメージが ARM ビルド可能なら 使わない理由がありません

Multi-arch ビルド
# ビルド
docker buildx build --platform linux/amd64,linux/arm64 \
  -t $REPO/blog-api:v1 --push .
Fargate ARM 64
resource "aws_ecs_task_definition" "this" {
  cpu          = "512"
  memory       = "1024"
  runtime_platform {
    cpu_architecture       = "ARM64"
    operating_system_family = "LINUX"
  }
}

前提: 使っているライブラリがすべて ARM 互換。Python / Node / Go パッケージは大半 OK。一部の native bindings は検証が必要。

3) Savings Plans / Reserved Capacity #

Fargate / EC2 / Lambda の約定割引。

種類割引約定
Compute Savings Plan最大 66%1 年 / 3 年、$/h を約定
EC2 Instance SP最大 72%インスタンスファミリーまで約定
RDS Reserved最大 65%インスタンスクラス + リージョン

Compute SP が最も柔軟 (Fargate / EC2 / Lambda にすべて適用)。安定運用に入った時点から検討 — 最初は絶対に約定しない (トラフィック / アーキテクチャが揺れているとき)。

ガイド
運用開始 ~ 3 ヶ月    : 約定 X (変化が速い時期)
3 ヶ月 ~ 6 ヶ月       : 利用量を分析、1 年 SP の検討開始
6 ヶ月 +              : 安定使用量の 60~70% 分を 1 年で約定

100% を約定するとトラフィックが減ったときに損。常に安全マージンを残す

4) Storage / Logs — 最も漏れやすい箇所 #

CloudWatch Logs #

#5 で強調した retention。すべてのグループに刺す:

Terraform で一括 30 日
resource "aws_cloudwatch_log_group" "ecs" {
  for_each          = toset(["/ecs/blog-api", "/ecs/blog-api-migrate"])
  name              = each.key
  retention_in_days = 30
}

S3 #

古いオブジェクトを自動的に安いクラスへ:

S3 lifecycle
resource "aws_s3_bucket_lifecycle_configuration" "logs" {
  bucket = aws_s3_bucket.logs.id
  rule {
    id     = "to-ia-then-glacier"
    status = "Enabled"
    transition { days = 30,  storage_class = "STANDARD_IA" }
    transition { days = 90,  storage_class = "GLACIER" }
    expiration { days = 365 }
  }
}

ECR #

古いイメージを自動削除:

ECR lifecycle
resource "aws_ecr_lifecycle_policy" "blog_api" {
  repository = aws_ecr_repository.blog_api.name
  policy = jsonencode({
    rules = [{
      rulePriority = 1
      description  = "直近 30 個だけ保持"
      selection    = { tagStatus = "any", countType = "imageCountMoreThan", countNumber = 30 }
      action       = { type = "expire" }
    }]
  })
}

5) Network — NAT と Egress #

本番請求書を初めて見る人が一番驚くポイント: NAT Gateway と Egress

NAT Gateway のコスト
時間   $0.045
GB     $0.045   (処理)
+ Egress $0.09/GB (インターネットへ)

小システムでも NAT 1 つで月 ~$32 + トラフィック。パターン別の節約:

パターン効果
VPC Endpoint for S3、DynamoDB完全無料、NAT トラフィックを分散
VPC Endpoint for ECR、Logs、Secrets時間 ~$0.01 + GB ~$0.01 (NAT より安い)
CloudFront を前に置くOrigin → CloudFront 無料、CloudFront → ユーザー GB ~$0.085 (地域による)
単一 NAT (開発環境)AZ 別 NAT ではなく 1 つの NAT — 可用性 ↓

Endpoint 一行 #

ECR Interface Endpoint
resource "aws_vpc_endpoint" "ecr_api" {
  vpc_id              = aws_vpc.this.id
  service_name        = "com.amazonaws.${var.region}.ecr.api"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = aws_subnet.private[*].id
  security_group_ids  = [aws_security_group.endpoints.id]
  private_dns_enabled = true
}

ECS task が ECR からイメージを取るとき NAT ではなく endpoint 経由で — NAT トラフィック / コストの両方を節約。

6) タグ — コストを分類可能に #

タグがないと請求書が 1 つの塊。タグがあれば環境 / チーム / プロジェクト別にスライス

デフォルトタグ
provider "aws" {
  default_tags {
    tags = {
      Environment = var.environment
      Project     = "blog-api"
      ManagedBy   = "terraform"
      CostCenter  = "product-blog"
    }
  }
}

providerdefault_tags全リソースに自動 適用。本番運用の核心。

Cost Allocation Tag の有効化 #

タグを入れただけではコンソールの Billing → Cost Allocation Tags で有効化しないと Cost Explorer が分類してくれません。設定 → タグを有効 → ~24h 待ち → 利用可能。

タグ強制 (SCP / IAM Condition) #

タグなしリソース作成をブロック。AWS Organizations の SCP または IAM ポリシーの Condition:

タグなしなら作成拒否
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": ["ec2:RunInstances", "rds:CreateDBInstance"],
    "Resource": "*",
    "Condition": {
      "Null": { "aws:RequestTag/Environment": "true" }
    }
  }]
}

7) 本番コストダッシュボード #

CloudWatch Dashboard に コストウィジェット をもう 1 行:

コストダッシュボードのウィジェット
[1] 今月の累積コスト (vs 先月の同時点)
[2] サービス別 (Fargate / RDS / Logs / NAT / ALB)
[3] 環境別 (env=prod vs env=staging vs env=dev)
[4] 日次推移 (90 日)
[5] Right Sizing 推奨数

週 1 回 oncall ミーティングで 30 分 — 悪化する箇所を早期に発見

分担責任 — FinOps #

大きな組織には FinOps という役割が独立してコストを見ますが、小さな組織では 開発者本人が 自分のモジュールのコストを意識する必要があります。タグが核心になる理由 — 自分のコードの請求書を自分で見られないと意識が育ちません。

落とし穴 — コストでよく出会う問題 #

1) 寝ている別リージョンのリソース #

基礎 #1 の落とし穴の再掲。AWS Resource Explorer または Cost Explorer のリージョン別コスト → 0 でないリージョンを点検。

2) terraform destroy していない PoC #

スタック / 環境を作って忘れがちなポイント。タグ + 自動掃除 Lambda パターン:

自動掃除
EventBridge schedule (毎日 9 時)
Lambda
   - tag Project=PoC AND CreatedAt < 7 days ago
   - リソース削除 / 通知

3) Free Tier の期限を知らない #

基礎 #3 の支払いアラートが第一防衛線。+ Cost Anomaly Detection で第二。

4) 100% Spot で本番ダウンタイム #

Spot interruption が一気に複数 task に当たると service が desired count を満たせない → 5xx 暴発。常に base on-demand を。

5) Multi-AZ RDS で 2 倍 #

小システムでは Multi-AZ がコスト負担。だからといって単一 AZ も困る。妥協: dev/staging は単一 AZ + prod は Multi-AZ

6) VPC Endpoint 未使用 #

NAT だけのシンプルセットアップ → トラフィックが大きいリソース (Logs、S3) が NAT を通ってコスト爆発。本番に入る時点で 必ず検討

7) 約定後にアーキテクチャ変更 #

3 年 SP を買った直後 ARM / Lambda へ移る — 約定はそのまま請求。短い (1 年) から、安定した用途だけで。


AWS トラック 27 編の振り返り #

このトラックを 1 行でまとめると:

「コンソールの 200 個のサービスから、小さなバックエンドを安全に運用するのに必要な道具箱だけを抜き出した。」

シリーズ別のまとめ #

シリーズ編数何が集まったか
基礎7アカウント / リージョン / IAM / コスト / CLI / セキュリティ / ログ — コンソールに入る前の地図
中級7EC2 / VPC / S3 / RDS / Route 53 / ALB / CloudFront — 運用の骨格
上級7ECS / ECR / Lambda / API Gateway / EventBridge / Secrets / Step Functions — モダンバックエンドの領域
実践61 つのシステムへ — Fargate / RDS / CI/CD / IaC / モニタリング / コスト

各シリーズが単独でも 1 つの領域を押さえますが、4 シリーズが 1 つのシステム に集まると別物になります — 運用可能なバックエンド。

1 つの視点から見た AWS の本質 #

AWS は サービスのカタログ ではありません。1 つのブロックの上に別のブロックを積む レゴ です。

このトラックで積まれたレイヤー
        ┌─────────────────────────────────────┐
        │ FinOps                              │   ← #6
        │ コスト / タグ / 約定                  │
        ├─────────────────────────────────────┤
        │ 可観測性                              │   ← #5
        │ Logs / Metrics / Traces             │
        ├─────────────────────────────────────┤
        │ 自動化                                │   ← #3, #4
        │ CI/CD / IaC                         │
        ├─────────────────────────────────────┤
        │ データ                                │   ← #2 + 中級 #4
        │ RDS / Secrets                       │
        ├─────────────────────────────────────┤
        │ コンピューティング                     │   ← #1 + 上級 #1~7
        │ ECS / Lambda                        │
        ├─────────────────────────────────────┤
        │ ネットワーク                           │   ← 中級 #1, 6, 7
        │ VPC / ALB / CloudFront              │
        ├─────────────────────────────────────┤
        │ コントロールプレーン                   │   ← 基礎全体
        │ アカウント / IAM / コスト / セキュリティ │
        └─────────────────────────────────────┘

このレイヤーを下から順に — コントロール → ネットワーク → コンピューティング → データ → 自動化 → 観測 → FinOps — が運用の自然な進化順序。新しいシステムを作るたびに、この流れをまた辿ることになります。

このトラックで扱わなかった領域 #

次のトラックへ自然につながるテーマたち:

  • コンテナ標準化Docker トラック が次。マルチステージビルド / スリミング / セキュリティスキャン / multi-arch — Fargate に乗るイメージ自体を深く。
  • Kubernetes — ECS の次のステップ。マルチクラスタ / GitOps / サービスメッシュ — トラフィックがさらに大きくなれば自然な進化。
  • 資格 — 同じドメインを試験の視点でもう一度見る機会。ロードマップの Cloud Practitioner / SAA / DVA シリーズ。
  • DataOps / ML — Glue / SageMaker / Athena。データが多くなればそちらへ。
  • マルチクラウド / ハイブリッド — Azure / GCP / on-prem との統合。大組織で出会うテーマ。

それぞれが別トラックで扱う価値のあるテーマ。

トラックを締めくくるにあたって #

ここまで付いてきてくれた方なら — AWS のコンソールで 何をどこで探せばいいか が手に馴染んだはずです。それがこのトラックの本当のゴールでした。新サービス / 新機能が毎年追加されますが、上のどのレイヤーに入るかが分かれば、新しい道具もすばやく定位できます。

次にお勧めしたいこと #

  1. Docker トラック — このシリーズが依存していたコンテナそのものを深く。Multi-stage / セキュリティ / multi-arch / compose まで 24 編で。
  2. 資格 — Cloud Practitioner / SAA / DVA — 同じ道具を試験の角度でもう一度。面接 / 転職 / 社内評価で効いてきます。
  3. 自分のプロジェクト — 読んだものが手に馴染む最短の道。小さなサイドプロジェクトをこのトラックのパターンで一度立ててみてください。#1 のインフラ がほぼそのままスタート地点になります。

長いトラックに付き合ってくださってありがとうございました。AWS の 200 個のサービスカタログの前で、これからは 怖くない位置 — 知らない道具が出てきても「これはコンピューティングレイヤー、これはネットワークレイヤー」という位置感覚が手にある状態 — に立っているはずです。そこからが本当の運用の始まりであり、このトラックはその出発線まで一緒に歩いた道のりでした。

以上で AWS 実践トラックを終了します。

X