はじめに
本記事では、これまでEC2内のDockerコンテナで運用していたAPIの本番環境を、AWS App Runnerに移行した際の構成・判断理由・得られた知見をまとめます。
今回の移行を行ったのは、ハッカソンプラットフォームCraftStadiumにおける主要なバックエンドリソースです。
私はチームのバックエンド・インフラ領域を担当しており、日常的にバックエンド開発や、AWS・Terraform・GitHub Actionsを用いた改善・運用に携わっています。サービス規模の拡大に伴い、既存構成の運用コストや作業負荷を見直す必要があったことから、今回のApp Runnerへの移行を進めました。
同様の構成を運用している方、あるいは EC2 ベースのアプリをよりシンプルな形へ移行したい方の参考になれば幸いです。
移行前の構成と課題
GitHub ActionsのWorkflowよる最低限の自動化は行っており、EC2にSSH接続してデプロイスクリプトを実行するフローを構築していました。
また、migration用のWorkflowも存在していましたが、環境差異等により失敗することがありました。というか直近半年は殆ど失敗していました。
APIの環境変数やシークレットはGitHub Actions Secretsで管理・保存し、Workflowでデプロイ実行時にEC2 内の.envファイルに展開していました。
この環境の問題点としては、
- sql-migrate でのマイグレーションの実行が手動
- 環境変数の管理が煩雑で、更新時に手動対応が複数箇所で必要
- ログ確認の際にはEC2に直接接続して Dockerコンテナを操作しなければならない
ということが挙げられます。また、EC2のストレージ管理や、EC2にSSHして作業を行うのはリスクが高いということもあります。
運用はできていたものの、日々の小さな手間が積み重なっており、どこかで限界が来るだろうと感じていました。特にログ調査やSecrets更新のたびにEC2へ接続する運用は、長期的には避けるべきだと判断しました。
余談ですが、私が所属する大学でも大学統合に伴うシステム再編が話題になることが多く、“シンプルで余計な手間なく保守しやすい構成”の価値は高いのだな〜と感じています。
検討の方向性
筆者はAWS CDKやTerraformを用いたAWSリソース構築の経験があり、本番環境をより管理しやすい形に整理することを目的としてApp Runnerへの移行を検討しました。
個人的には ECS のオペレーションを理解しているとはいえ、今回のサービス規模に対しては構成が大きすぎる(オーバースペック)と感じていました。また、運用コストを適切に抑えるためにも、App Runnerが提供する抽象度の高さが丁度良いと判断しました。
AppRunnerは複雑な設定なくリクエストに応じた自動スケーリング機能があるうえ、ALB など追加コンポーネントも不要です。また、App Runnerリリース当初はVPCへのアクセスに制限がありましたが、現在ではVPC Connectorを使うことでアウトバウンドトラフィックをVPC内に向けることができます。
もちろん、ECSのほうがApp Runnerより詳細なスペックやスケールをカスタマイズできますが、今回は必要ないと判断しました。
(前任者の方がECSへの移行を検討後、複雑さや要件的にAppRunnerで良いのでは、という話になっていたのが大きいですが)
今回の主な目標は次の3点です。
- デプロイや環境更新を自動化し、手動操作を減らす
- Secrets の管理を AWS 上に統一する
- ネットワーク構成を簡素化し、障害調査を容易にする
もともとアプリケーションはDocker化されていたため、ECR へのビルド・プッシュ自体は大きな手間なく進めることができました。
構成概要と移行手順
構成概要
移行にあたっては、いきなりIaC化するのではなく、まず手動で構築・検証し、構成を確認しながら進めました。
その後全体の動作が確認できたのちに、Terraform管理されたリソースに再構築しています。
NAT Gateway 採用の判断
App RunnerでVPC内のリソースへ接続する際はVPC Connectorを介する必要があります。
その場合、全ての通信がVPC Connectorを経由することになります。
しかし、Auth0は公開鍵で署名検証するためにJSON Web Key Setsを連携する必要があり、SendGridはメール送信APIを叩くために外部通信が必要でした。
これを解決するためにはNAT Gatewayを使用するのが王道ですが、NAT Gatewayはコストが高く、App Runner の API(VPC内)から外部への通信だけににNAT Gatewayを使用するのは勿体ないと感じ、その他の回避策を模索しました。
具体的には、当初はそれぞれSQS / Lambdaを使用しての非同期処理などでもビジネス的な要件は満たせるため、検証を進めました。しかし実際に試算すると、関数管理やログ監視などの運用工数が増えるだけで大きなコスト削減には繋がらず、長期運用を考えると採用すべきではないと判断しました。
そのため、構成の単純さと運用性を優先し、NAT Gatewayを利用することにしました。
App Runner → VPC Connector → Private Subnet → RDS
│
└(外部通信)→ NAT Gateway → Internet → Auth0 / SendGrid
CloudWatch によるデバッグ
EC2 時代と異なり、App Runner ではインスタンスに直接入ってログを確認することはできません。移行後はCloudWatch Logsを用いて確認することになります。
App Runner はトラブル発生時に実行環境へアクセスできないため、CloudWatch ログを中心としたモニタリング体制を整備しておくことが必須だと感じました。
Secrets 管理の一元化
Secrets はこれまで GitHub Actions Secrets に保存していましたが、
App Runner では AWS Systems Manager Parameter Store を利用する形に移行しました。
aws ssm put-parameter \
--name "/copalette/production/DATABASE_URL" \
--value "postgres://xxxx" \
--type "SecureString"
App Runner 側で Parameter Store を参照することで、
Secrets の更新やローテーションが AWS 内で完結します。
また、環境変数の参照範囲が明確になり、管理が容易になりました。
ドメイン設定とデプロイ統合
ドメインや CI/CD の統合も並行して実施しました。
デプロイフロー
GitHub Actions → ECR → App Runner への自動反映フローを整備したことで、EC2を経由せずとも GitHub Actions の実行のみで本番環境への反映が完結するようになりました。
GitHub
↓ releaseブランチにmerge
GitHub Actions
↓ Docker Imageをbuild & push
ECR
↓ deployトリガー
App Runner
マイグレーションフロー
管理や運用の手間を減らすため、マイグレーション処理もGitHub Actions内に統合する方針としました。その際、ワークフローをVPC内で実行できるよう、GitHub Actions RunnerをAWS CodeBuildで動かす構成に変更しています。
これにより、マイグレーション処理はこれまで通りGitHubで管理しつつ、実行自体はVPC内で完結できます。RDSへの接続も容易になり、接続情報はParameter Storeから安全に取得できるため、Secrets管理と運用の手間をまとめて削減することができました。
GitHub
↓ releaseブランチにmerge
GitHub Actions on VPC CodeBuild Project
↓ migration
RDS
Before / After
| 項目 | Before(EC2) | After(App Runner) |
|---|---|---|
| デプロイ | GitHub Actions → EC2にSSH | GitHub Actions → ECR → App Runner |
| migration | 不安定・SSHして手動で実施 | 安定化(CI/CD内で完結) |
| Secrets | Actions Secrets → EC2内に展開 | Parameter Store に統一 |
| ネットワーク | ALB + NAT + EC2 | NAT + VPC Connector |
| ログ | EC2にSSH → Dockerのログを確認 | CloudWatch Logs |
| 運用コスト | 高い(ALB・EC2維持) | 低い |
| 運用負荷 | SSH・手動監視 | 自動化 + CloudWatch 監視 |
得られた知見
- 既にアプリケーションがDockerizeされていたので、App Runner への移行が比較的容易だった
- 将来的にスケールさせる場合も、ECSやApp Runnerなど柔軟に検討できる
- NAT Gateway はコストよりも管理負荷削減の観点で選定すべき (とはいえお高い…)
- Secrets を Parameter Store に統一することで、環境ごとの整合性と可視性が向上した
- CloudWatch Logs を中心とした監視構成により、運用時の再現性が高まった
- 移行を一気に自動化せず、手動検証を挟んだことが安定化に繋がった
今後の課題
現在は以下に注意しつつ運用中です。
- NAT Gateway コスト最適化(NAT インスタンス等の再評価)
- App Runner のスケーリング挙動とモニタリング強化
- CloudWatch Logs のメトリクス化・通知整備
まとめ
本移行では、運用負荷を減らすことを主眼に構成を見直しました。
App RunnerはECSに比べて設定項目が少ない反面、挙動がブラックボックスに近い側面もありますが、適切に CloudWatch と Parameter Store を組み合わせることで、現時点では最も最適な構成に整理するできたと感じています。
今回の移行を通じて、構成は小さく維持したほうが運用は長く安定すること改めて実感しました。
その点で、EC2 上で Docker 運用を行っている方や、Terraform 管理の範囲を縮小したい方(特にECSはオーバースペックな環境の場合)にとって、App Runnerは有力な選択肢になり得ると感じています。
サービス紹介
「創るたびに、強くなる。」
CraftStadiumは、ハッカソンを通じてエンジニアやクリエイターが成長し続けるためのプラットフォームです。
プレイヤーは、ハッカソンプラットフォームで簡単に自分に合ったハッカソンを探せ、主催者は効果的なハッカソンを主催できます。

