はじめに
現在、プログラミングスクールでJava(Spring Boot)を中心にWebエンジニアへの転職に向けて学習をしています。
今回、作成しているWebアプリケーション(学習記録を可視化するアプリ)の画像アップロード機能を実装するにあたり、インフラ構成と技術選定について深く考える機会がありました。
最初はアプリ開発に重点を置きRenderの無料プランにアプリをデプロイしていたのですが、ローカル環境では動いていた画像アップロード機能が、デプロイした途端に動かなくなるという問題に直面しました。
結果として、外部ストレージである**AWS S3(エススリー)**を導入することで解決し、実務を見据えた良い技術選定(疎結合な設計)に繋がったので、その背景と、結果を忘備録も兼ねてまとめます。
1. 直面した課題:ローカルでは動くのにデプロイすると表示できない?
プログラムと同じフォルダ(static フォルダなど)に画像をアップロードして保存する設計にしていたところ、Renderにデプロイした環境で以下の問題が発生しました。
- アップロードした直後から画像が表示されない(404エラー)
- (調べていくと)時間が経つと保存した画像そのものが消えてしまう
原因を紐解くと、Spring Bootの仕様とRender無料プランの特性という2つの壁がありました。
①:Spring Bootは「起動時」のファイルしか見ない
Spring Bootは、アプリが起動した瞬間に存在していた静的ファイル(staticフォルダ内など)しか認識しないというルールがあります。ローカル開発時はIDEの再起動などでファイルが再読み込みされますが、デプロイ環境では新しくアップロードされたファイルをサーバー(Spring Boot)が認識できず、直後から表示エラーになっていました。
②:Renderの「エフェメラルファイルシステム」
Renderの無料プラン(Freeプラン)のサーバーは、再起動(1日1回以上、またはスリープ復帰時)のたびに、コンテナ内のファイルシステムが初期化される仕組み(エフェメラルファイルシステム)を持っています。そのため、仮に画像が保存できていたとしても、時間が経つと跡形もなく消え去ってしまう状態でした。
2. 解決策:AWS S3の導入と「疎結合」な設計
この2つの問題を根本から解決するため、画像ファイルをWebサーバー(Render)内部に保存するのをやめ、外部の専用ストレージである**AWS S3(Simple Storage Service)**へ保存する設計へと切り替えました。
S3を選定した理由(技術的メリット)
単に「画像が表示できるようにする」だけであれば、他にも選択肢(CloudinaryやSupabase Storageなど)がありましたが、あえてAWS S3を選んだのには、将来を見据えた3つの明確な理由があります。
① アプリケーションとストレージの「疎結合化(分離)」
Render(Webサーバー)はプログラムの実行だけに集中させ、画像などの静的ファイルはAWS S3という独立した場所に保管する構成にしました。
このようにサーバーとストレージを切り離して**「疎結合」**にしておくことで、将来的にWebサーバー側の引っ越し(RenderからAWS環境への完全移行など)が必要になっても、画像データ側には一切影響が出ない柔軟性を持たせることができます。
② 将来的なサービスの拡張(スケールアウト)を見据えた設計
このアプリは「エラーと格闘した日」や「読書した日」の軌跡も画像(スクリーンショットなど)を交えて記録できるサービスを目指しています。将来的にユーザー数が増え、画像データが膨大になったとしても、大量の静的ファイルを高速かつ安価に配信できるS3に任せておけば、Webサーバーが容量パンクでダウンするリスクを回避できます。
③ クラウドインフラの学習ロードマップとしての最適性
将来的にバックエンドだけでなく、インフラ(AWS)の知識も兼ね備えたエンジニアになりたいと考えています。実務のWeb開発において最も標準的に使われているオブジェクトストレージである「S3」に今の段階から触れておくことは、自分にとって大きな意味があると考えました。
実際にS3バケットの作成や、IAMを用いた最小権限(S3の読み書きのみ)の設定を自分で行ったことで、セキュリティやクラウド運用の基本を体感することができました。
3. 実装の概要(イメージ)
大まかな処理の流れは以下の通りです。
- アップロード: フロントエンドから画像が送信される。
- S3へ転送: バックエンド(Spring Boot)がAWS SDKを使い、画像をS3へアップロード。
- URLの保存: S3から発行された「画像のアクセスURL」を、データベースのテーブルに文字列として保存。
-
画面表示: 画面を描画するときは、DBからURLを取得して
<img src="保存したURL">として表示。
画像はSpring Bootのフォルダ外(S3)にあるため、「起動時のファイルしか見ない」というルールに縛られることなく、アップロードした次の瞬間から世界中どこからでも画像が表示できるようになりました!
まとめと今後の展望
今回の経験を通じて、単に「コードを書いて動かす」だけでなく、**「デプロイ先(インフラ)の特性やフレームワークの仕様を理解して、それに適したシステム構造(アーキテクチャ)を設計する」**という、バックエンドエンジニアとして非常に重要な視点を得ることができました。
最初は手軽なRender×S3の構成でMVP(最小限の製品)として開発を進めていますが、今後はさらにインフラの勉強を進め、バックエンド自体もAWS(EC2やECSなど)へ移行させ、より本格的な構築に挑戦したいと考えています。
何もしなかったように思える「エラーと格闘した日」も自分の財産になる。そんな学習記録アプリを、しっかり形にしていきたいです。
最後までお読みいただきありがとうございました。