はじめに
勉強とアウトプットを兼ねて、Webアプリ開発の記録を記事にしてみます。
個人のメモ的な側面が強いです。
Web開発初心者すぎて至らぬところだらけだと思いますが、暖かい目で見ていただければ幸いです。
↓ これまでの内容 ↓
【Day0】アプリが完成するまで毎日投稿
【Day1】開発環境を考える
【Day2】開発環境を構築する、、、はずでした
【Day3】まずはフロントだけ開発環境を構築する
【Day4】バックエンドの開発環境を整えつつ、マルチコンテナ対応のDevcontainerにする
【Day5】お試し実装!ファイルをアップロードしてバックエンドで処理する
【Day6】Docker Desktopが起動しなくなり泣きながら原因調査する
【Day7】画像にフレームとExif情報を付けてみる
【Day8】フロントに表示する画像のサイズを小さくする
【Day9】フロントエンドとバックエンドをそれぞれデプロイする
前回やったこと
ついに開発環境からサーバーへデプロイしました!
外部公開したことでスマホなどからアクセスして操作できるの楽しい!
今回やったこと
【Day4】でわざわざ苦労してNodeとPythonでそれぞれコンテナを作ってマルチコンテナ開発環境にしたのですが、、、結局NodeもPythonも1つのコンテナにまとめることにしました。
1つのコンテナにまとめた理由
シンプルにコンテナの切り替えがめんどくさかったです。笑
当初の思想としては、
フロントの開発はNodeのコンテナで、バックの開発はPythonのコンテナで
というようにそれぞれ明確に開発環境を分けるつもりでした。
それに伴い、以下のようにコンテナの挙動を制御してました。
- フロントのコンテナにリモートアクセスして開発するとき
- フロント:何もしない
- バック:起動時にバックエンドのサーバーを起動する
- バックのコンテナにリモートアクセスして開発するとき
- フロント:起動時にフロントエンドのサーバーを起動する
- バック:何もしない
でも結局フロントの挙動を変えつつ、バックも挙動を変えたい、みたいなことが多発してしまい、、、もう1つのコンテナで全部やろうよ!!!ってなりました。
もっと大規模かつ複数人で実装範囲を分担するときはマルチコンテナでよかったと思いますが、個人で開発する分には全部1つのコンテナにまとまってる方が便利でした。
マルチコンテナ開発の構成
.
├── .devcontainer
│ ├── backend
│ │ └── devcontainer.json
│ ├── frontend
│ │ └── devcontainer.json
│ ├── docker-compose_backend.yml
│ └── docker-compose_frontend.yml
│
├── backend
│ ├── app
│ └── Dockerfile
│
└── frontend
├── node_modules
├── src
└── Dockerfile
上記のようにフロントとバックにそれぞれdevcontainer.json
, docker-compose.yml
, Dockerfile
を用意してました。
個人的にここで肝になるのがdocker-compose.yml
を2つ分けたことです。
フロント用とバック用のどちらのdocker-compose.yml
を読み込んでも、呼び出すDockerfileは同じです。
しかし、それぞれのDockerfileに対して最終的に実行させるコマンドが異なります。
開発対象のサーバーのコンテナではcommand: ["sleep", "infinity"]
を指定してサーバーを起動させず、もう片方のコンテナではそれぞれサーバー起動のコマンドを指定しています。
Dockerfileだけではここまで柔軟に対応しきれませんでした。(もしかしたらもっといい方法があるかもしれないですが、現時点の私ではこれしか思いつきませんでした。)
version: "3.8"
services:
frontend:
build:
context: ..
dockerfile: frontend/Dockerfile
volumes:
- ..:/home/devuser/workspace
- node_modules:/home/devuser/workspace/frontend/node_modules
working_dir: /home/devuser/workspace/frontend
ports:
- "3000:3000"
command: ["sleep", "infinity"] # フロントはサーバーを起動しない
backend:
build:
context: ..
dockerfile: backend/Dockerfile
volumes:
- ..:/home/devuser/workspace
working_dir: /home/devuser/workspace/backend
ports:
- "8000:8000"
command: ["/home/devuser/venv/bin/uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] # FastAPIのサーバーを起動する
volumes:
node_modules:
version: "3.8"
services:
frontend:
build:
context: ..
dockerfile: frontend/Dockerfile
volumes:
- ..:/home/devuser/workspace
- node_modules:/home/devuser/workspace/frontend/node_modules
working_dir: /home/devuser/workspace/frontend
ports:
- "3000:3000"
command: ["npm", "run", "dev"] # Reactのサーバーを起動する
backend:
build:
context: ..
dockerfile: backend/Dockerfile
volumes:
- ..:/home/devuser/workspace
working_dir: /home/devuser/workspace/backend
ports:
- "8000:8000"
command: ["sleep", "infinity"] # バックはサーバーを起動しない
volumes:
node_modules:
Dockerfileとdevcontainer.jsonについては説明は省略します。気になる方はリポジトリを参照ください。(2025/06/12時点では公開中)
シングルコンテナ開発の構成
結論からというと以下のようにしました。
.
├── .devcontainer
│ └── develop
│ ├── devcontainer.json
│ └── docker-compose.yml
│
├── backend
│ └── app
│
├── frontend
│ ├── node_modules
│ └── src
│
└── Dockerfile
正直、わざわざdevelopフォルダを作って、そこにdevcontainer.json
とdocker-compose.yml
を入れる必要はないんですが、現在のリポジトリはマルチコンテナ用の各種設定ファイルも共存しているため、このような形になっています。
シングルコンテナだけなら.devcontainer直下に置いていいと思います。
この構成で個人的に肝になっているのはDockerfileがルート直下にあることです。
理由としては、Dockerfile内でbackendとfrontendを操作するときに、操作対象が下位のディレクトリにあった方が直観的にコマンドを記述できるからです。
最初は.devcontainer/developにDockerfileもまとめていたのですが、相対パスでのディレクトリ操作で頭がごちゃごちゃになるので止めました。
「backendはカレントディレクトリ(.devcontainer/develop)の2個上の1個下だから、../../backend
で、、、」って考えるのが大変でした。笑
また、docker-compose.ymlでは何もサーバーが起動しないようにcommand: ["sleep", "infinity"]
を指定しています。
シングルコンテナの場合、Dockerfileでsleep infinity
を実行すればいいのかなと思いましたが、そうするとDockerfileのビルドが永遠に終わりませんでした。(冷静に考えたら当たり前)
version: "3.8"
services:
fullstack:
build:
context: ../../
dockerfile: Dockerfile
volumes:
- ../../:/home/devuser/workspace
- ../../frontend/node_modules:/home/devuser/workspace/frontend/node_modules
working_dir: /home/devuser/workspace
ports:
- "3000:3000"
- "8000:8000"
command: ["sleep", "infinity"]
volumes:
node_modules:
Dockerfileとdevcontainer.jsonについては説明は省略します。気になる方はリポジトリを参照ください。(2025/06/12時点では公開中)
おわりに
開発環境構築ほんとうに難しいです。(n回目)
実装はChat GPTに聞けばだいたい解決するけど、開発環境はなかなか上手くはいかない。
複数の言語で同時に開発するときのベストプラクティスとかもっと調べればよかったかも。というよりあるのかな?
これからも色々試行錯誤しながら自分的にしっくりくる構成を探していきたいですね。
Dockerfileとdocker-compose.ymlとdevcontaier.jsonの立ち位置やコマンドの実行順があいまいになってきたので、どこかで一度まとめたい。。。