はじめに
プロ野球の投手 × 打者の対戦成績検索サービス Pitcher-vs-Batter を Heroku から AWS に移行し、月額インフラ費を約 95% 削減しました。
本記事は 「コスト削減」だけ にフォーカスします。
以下のトピックは 別記事で個別に深掘り しています:
- DB移行(MySQL → PostgreSQL の書き換え地獄)
- Lambda化(Lambda Web Adapter で Spring Boot をそのまま載せる)
- ✅ Lambda を実質常時稼働させる工夫(warmup 10並列でコールドスタート回避)
- Secrets Manager 統合(EnvironmentPostProcessor で起動時注入)
- Terraform で全 IaC 化 / GitHub Actions OIDC
- ✅ Vue.js SPA で SEO を本気でやった話(noscript + JSON-LD + FAQPage)
TL;DR
| 項目 | Before(Heroku) | After(AWS) |
|---|---|---|
| App | Heroku Basic Dyno(常時稼働 $7) | Lambda + Lambda Web Adapter(無料枠内 $0) |
| DB | RDS for MySQL t2.micro($15〜) | Neon Free($0) |
| 静的配信 | Dyno 内 Spring Boot(同梱) | S3 + CloudFront($0 無料枠) |
| Scheduler | Heroku Scheduler($0) | EventBridge Scheduler($0) |
| シークレット管理 | Config Vars($0) | Secrets Manager($0.40) |
| その他 | - | ECR + CloudWatch Logs(〜$1) |
| 月額合計 | $22〜$30 | $1〜$2 |
→ 約 95% のコスト削減。
今回の構成図
コスト最適化のために組んだ AWS サーバレス構成はこちら。
全体像(サマリ)
主要コンポーネントだけを抜粋した俯瞰図です。
詳細版
各コンポーネントの役割・IAM 境界・データフロー・Step Functions のワークフローまで含めた詳細図です。
※ 各コンポーネントの設計意図・Lambda の常時稼働工夫・SEO 対策は 別記事で深掘り しています。
なぜ Heroku は高くついていたか
1. Dyno は「リクエスト 0」でも課金される
Basic Dyno($7/月)は常時起動が前提。個人開発サービスのアクセスは深夜帯ほぼ 0 なのに、24/365 で料金が発生していました。
「アイドル時間 = 純粋なコスト垂れ流し」 になっていたのが一番痛かったポイント。
2. RDS が想像以上に高い
db.t2.micro でも 約 $15/月(ストレージ含む)。Heroku Postgres の Mini プランも以前は $5 でしたが、最低 $9 に値上げ。
DB だけで App の倍以上のコストになっていました。
3. 無料枠廃止後の Heroku は個人開発に厳しい
2022 年の無料枠廃止以降、最小構成でも $15〜$20 スタート。
「ちょっと動くもの作って公開する」用途には割に合わなくなっていました。
AWS 側で削減できたポイント
1. App:Dyno(常時稼働) → Lambda(従量)
Spring Boot をそのまま Lambda に載せて、リクエストがある瞬間だけ課金 に切り替え。
- Lambda 無料枠:月 100 万リクエスト + 40 万 GB 秒
- 個人開発レベルのアクセスでは余裕で枠内
- 実費:$0
Lambda Web Adapter でコードはほぼそのまま
「Spring Boot を Lambda に載せる」と聞くと書き直しが大変そうですが、AWS Lambda Web Adapter を使うとアプリ側のコードはほぼ変えずに済みました。
- 通常の HTTP サーバ(Spring Boot / Express / FastAPI など)の前段に乗る 拡張機能(Extension)
- Lambda の invoke イベントを内部で HTTP リクエストに変換 → アプリの
localhost:8080に流す - アプリ側からは「普通の HTTP サーバとして動いてる」状態のままで OK
Dockerfile に 1 行追加するだけで導入できます:
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:1.0.0 \
/lambda-adapter /opt/extensions/lambda-adapter
つまり 「Spring Boot を Lambda 用に書き直すコスト = ほぼ 0」 で、コードはそのままに課金モデルだけ常時稼働 → 従量に切り替えられた、というのが今回のコスト削減の肝でした。
※ 細かい導入手順・コールドスタート対策は 別記事 で書いています。
2. DB:RDS MySQL → Neon Free
最大の削減ポイント。$15 → $0。
- Neon Free 枠:0.5 GB ストレージ + 月 191.9 時間 compute
- サーバレス PostgreSQL なのでアイドル時は自動停止 → 課金 0
- 個人開発レベルのデータ量(〜64 万行)なら無料枠で十分
※ MySQL → PostgreSQL の書き換えで苦労した話は別記事で書きます。
3. 静的配信:Dyno 同梱 → S3 + CloudFront
Spring Boot に静的ファイルを同梱する構成をやめ、フロントを S3 に切り出し。
CloudFront の永続無料枠(1 TB データ転送 + 1,000 万リクエスト/月)で実費 0。
4. Scheduler:Heroku Scheduler → EventBridge Scheduler
日次スクレイピング用のジョブも EventBridge Scheduler に移行。
実費 0(月 1,400 万呼び出しまで無料)。
5. シークレット管理:Config Vars → Secrets Manager
唯一「ちょっとだけ増えた」コスト。
1 シークレット = $0.40/月。
平文の Config Vars と引き換えに、暗号化された KMS 管理に乗せられました。
コスト比較(実測)
| サービス | Heroku 時代 | AWS 移行後 |
|---|---|---|
| App | $7(Basic Dyno) | $0(Lambda 無料枠) |
| DB | $15〜(RDS MySQL t2.micro) | $0(Neon Free) |
| 静的配信 | $0(同 Dyno) | $0(CloudFront 無料枠) |
| API Gateway | - | $0(無料枠) |
| Secrets Manager | - | $0.40 |
| ECR | - | $0.5 |
| CloudWatch Logs | - | 〜$0.5 |
| 合計 | $22〜$30 | $1〜$2 |
EventBridge × 10並列 のウォームアップを入れて Lambda を実質常時稼働させていますが、Lambda 無料枠(月 100 万リクエスト + 40 万 GB 秒)にギリギリ収まっています(詳細は コールドスタート対策編 参照)。
コスト削減の引き換えに発生したコト
無料枠ベースで構成したぶん、いくつかトレードオフはありました(詳細は別記事で書きます):
- コールドスタート:Spring Boot on Lambda は初回起動 25〜40 秒。warmup の仕組みで実用ラインに乗せた → 別記事で深掘り
- DB のアイドル停止:Neon Free は無アクセス時にコンピュートが落ちる。初回アクセスがちょい遅い。
- 学習コスト:Terraform / Lambda / CloudFront / OIDC など、Heroku の数倍はハマる場所が多い。
- SPA だと SEO 不利:noscript + JSON-LD で対策 → 別記事で深掘り
ただし 月 $25 → $1.5 のリターン を考えたら全部許容範囲でした。
まとめ
- 個人開発サービスでも Heroku → AWS で 95% コスト削減は現実的
- 最大の効きどころは DB($15 → $0)と App($7 → $0)
- Lambda Web Adapter のおかげで Spring Boot のコードはほぼ書き換えずに Lambda 化できた
- warmup の 10並列化 で Lambda を実質常時稼働させて UX を保った(→ 別記事)
- noscript + JSON-LD で SPA でも SEO 流入を取りに行った(→ 別記事)
- 唯一の増分は Secrets Manager の $0.40 のみ
- ただし「無料枠運用」はトレードオフ(コールドスタート等)がある
参考になったら LGTM・ストックお願いします 🙏
サービス: Pitcher-vs-Batter
前回の記事: 初の個人開発 #Vue.js
続編:

