このアプリでは、ローカルで動くものを作るだけでなく、
公開後も自分で把握しやすく、修正しやすく、再現しやすい構成にすることを強く意識しました。
個人開発では、画面や機能の実装に集中しやすく、
デプロイやインフラは最後にまとめて何とかしようと考えがちです。
自分も以前はそうでした。
しかし実際には、公開構成を後回しにすると、
ローカルでは動くのに本番では動かない、
どこで問題が起きているのか分からない、
修正のたびに手順がぶれる、
といった問題が起きやすくなります。
そのため今回は、
デプロイを単なる最後の作業として扱うのではなく、
アプリ全体の設計の一部として考えるようにしました。
特に意識したのは、
「同じ手順で何度でも公開できること」と、
「どの責務をどこに置いているかを説明できること」です。
まず、実行環境の再現性を高めるために Docker を使いました。
ローカル環境では動いていたとしても、
本番環境では OS、依存関係、ネットワーク、環境変数の違いで簡単に崩れます。
その差をできるだけ小さくするために、
アプリケーションの実行単位をコンテナで揃える方針を取りました。
この判断には大きな意味がありました。
単に動作環境を揃えるだけでなく、
フロントエンド、バックエンド、管理用の構成などを
それぞれ分けて扱いやすくなったからです。
すべてを一つの塊として考えるのではなく、
どのコンテナが何を担当しているのかを明確にすると、
問題が起きたときに切り分けやすくなります。
さらに、デプロイ手順を毎回人間の記憶に頼らないようにするため、
GitHub Actions を使って CI/CD の流れも整えました。
ここで重視したのは自動化そのものではなく、
「公開のたびに同じ流れを通せるようにすること」でした。
個人開発では、一度うまくいった手順を手作業で繰り返しがちですが、
それでは小さな設定漏れや順番の違いで簡単に再現性が失われます。
そのため、コードの更新からデプロイまでの流れをある程度固定し、
できる限り曖昧さを減らすようにしました。
この考え方は、チーム開発を意識したというより、
むしろ自分一人でも後から迷わないようにするために重要でした。
数週間後の自分が見ても理解できる形にしておくことは、
個人開発でもかなり大切だと感じています。
公開構成を考える上では、AWS の各サービスを役割ごとに整理しました。
ここで強く意識したのは、
サービス名を並べることではなく、
どの責務をどこに置くかを明確にすることでした。
まず EC2 は、アプリケーションを実際に動かす場所として使います。
Rails API や Next.js、必要に応じて管理画面やリバースプロキシなど、
リクエストを受けて処理を返す実行部分はここに置く考え方です。
ただし、EC2 を「全部入りの箱」として扱うのではなく、
あくまでアプリケーション実行の土台として整理しました。
データベースには RDS を使う前提で構成を考えました。
これもかなり重要な判断でした。
アプリケーションサーバーとデータベースを同じ場所に載せてしまうと、
更新や管理の責務が混ざりやすくなります。
一方で、データの保存を RDS に分離すると、
アプリケーションの更新とデータ管理を切り離して考えやすくなります。
この分離はインフラ上の都合だけでなく、
データベース設計の考え方ともつながっています。
今回のアプリでは、
商品、取引、会話、お気に入り、配送先、記事など、
それぞれの情報を責務ごとに分けてスキーマを組み立てています。
つまりデータベースの中でも、
何をどこが持つべきかを意識して設計しています。
インフラでも同じように、
何をどこに置くべきかを分けて考えることで、
全体の見通しがかなり良くなりました。
画像や添付ファイルについては、S3 に逃がす前提で考えました。
画像をアプリケーション本体と同じ場所で抱え続けると、
デプロイやサーバー差し替えのたびに管理が複雑になります。
そのため、静的ファイルは S3 に寄せ、
アプリ側は URL や参照情報を扱う形にしたほうが運用しやすいと判断しました。
この考え方は、記事機能や画像管理とも相性が良いです。
最初は URL ベースで素早く回しつつ、
将来的にはストレージ管理や添付ファイル運用まで広げやすくなります。
つまり S3 を使うという判断は、
ファイル保存先を変えるだけではなく、
将来の運用方法まで見据えた設計でもありました。
外部からの入口としては Nginx を置くことを前提に整理しました。
ブラウザからのアクセスをまず Nginx で受け、
ドメインやパスに応じて Next.js や Rails API に振り分ける形です。
この層を分けておくと、
アプリケーション自体が直接すべての公開入口を抱え込まずに済みます。
また、HTTPS やリバースプロキシの設定、公開 URL の整理もしやすくなります。
実際にフロントエンドとバックエンドを分離した構成では、
URL の考え方を曖昧にしないことが特に重要でした。
ブラウザからアクセスする公開 URL と、
コンテナ内部で通信するときの URL は同じではありません。
この違いを意識しないまま実装すると、
ローカルでは動くのに本番で API 通信が失敗する、
あるいはサーバー側だけで通る URL をブラウザ側でも使ってしまう、
といった問題が起きやすくなります。
今回はそこをかなり意識して整理しました。
公開用の URL と内部通信用の URL は役割が違うものとして扱い、
server 側と client 側で接続先の考え方を分けました。
この切り分けは、見た目には地味ですが、
フロントと API を分けた構成では非常に重要な基礎だと感じました。
ドメイン管理には Route 53 を使う前提で考えました。
開発中は IP アドレスで確認できても、
実際の公開ではドメイン設計が構成の一部になります。
どのドメインをどこへ向けるのか、
API 用のサブドメインをどう切るのか、
HTTPS の前提をどう揃えるのか。
こうした点を整理しておくことで、
公開後の構成がかなり理解しやすくなります。
また、スキーマ設計の観点から見ても、
インフラとデータ設計は分けて考えつつ連動している必要があると感じました。
今回のアプリでは、
items は出品、
orders は取引、
messages は取引中の会話、
favorites はユーザーの関心、
addresses は配送先、
posts は発信と記録、
というように責務を分けています。
こうしてデータの責務を整理しているからこそ、
それを保存・配信・公開するインフラ側でも役割分担を考えやすくなります。
逆に、DB 設計が曖昧なままインフラだけ整えても、
何をどう公開し、どこに保存し、どこに責務を置くべきかが見えにくくなります。
今回はデータベースと公開構成を別々の話として切り離すのではなく、
「責務分離」という同じ考え方の延長で見ていました。
アプリ内部で責務を混ぜないことと、
公開構成の中で責務を混ぜないことは、
実はかなり近いと感じています。
この開発を通して学んだのは、
デプロイは最後の仕上げではなく、
最初から設計に含めるべき領域だということです。
何がどこで動き、
どこに保存され、
どこから入ってきて、
どう再現されるのか。
そこまで含めて初めて、
「公開して運用できるアプリ」になるのだと感じました。
以前の自分は、
まずローカルで完成させてから本番を考えればよいと思うことが多くありました。
しかし実際には、本番を後回しにすると、
ローカルだけに閉じた前提がどんどん積み上がっていきます。
その結果、最後に一気に無理が出ます。
今回はその反省から、
Docker、CI/CD、AWS、ドメイン、URL 設計、データ保存先まで含めて、
最初から再現できる形を目指しました。
この構成で一番伝えたいのは、
単に AWS のサービスを使ったことではありません。
むしろ、
デプロイ手順を固定し、
インフラの責務を分け、
データベース設計ともつながる形で全体を整理しようとしたことです。
個人開発であっても、
ただ公開するだけではなく、
何度でも説明できて、何度でも再現できる構成にしておくことが大きな価値になると考えています。
Archive
再現できるデプロイと公開構成をどう設計したか
Docker / CI/CD / AWS / DB設計を切り離して考えるのではなく、公開後も運用しやすい一つの構成として整理した記録。