【Day4】バックエンドの開発環境を整えつつ、マルチコンテナ対応のDevcontainerにする

## はじめに

勉強とアウトプットを兼ねて、Webアプリ開発の記録を記事にしてみます。

個人のメモ的な側面が強いです。
Web開発初心者すぎて至らぬところだらけだと思いますが、暖かい目で見ていただければ幸いです。

↓ これまでの内容 ↓
[【Day0】アプリが完成するまで毎日投稿](https://qiita.com/midorigame/items/f9b9a445c945b4a837b1)
[【Day1】開発環境を考える](https://qiita.com/midorigame/items/e26344599e2ffaa22033)
[【Day2】開発環境を構築する、、、はずでした](https://qiita.com/midorigame/items/3f57f2691a8e1074adb8)
[【Day3】まずはフロントだけ開発環境を構築する](https://qiita.com/midorigame/items/9de27ba72aaef504a833)


## 前回のあらすじ

前回はフロントエンド用の開発環境として、Nodeベースのコンテナを作成しました。

現在作ろうと思っているwebアプリはフロントエンドとバックエンドが必要で、バックエンドにはPythonのFast APIを使おうと思ってます。

なので、今回はバックエンド用のPythonベースの開発環境コンテナを作成します！

## 今回やったこと

今回は以下のことをやりました！

- バックエンド用のPythonコンテナを作成
- フロントエンド用のコンテナとバックエンド用のコンテナを切り替えられる仕組みを用意

## バックエンド用のPythonコンテナを作成

コンテナを作るにあたって、まずはFast APIが動作する最小構成を作成しました。

最小構成を作るのは一旦フロントエンドのコンテナ内で操作しました。

### Fast APIの実行環境を作る

フロントエンド用のコンテナ（Node）には標準でPythonは入っていましたが、pipが入ってなかったのでpipをインストールします。

[公式の推奨手順](https://packaging.python.org/ja/latest/guides/installing-using-linux-tools/)だと一緒にvenvも入れるらしい

```
$ sudo apt install python3-venv python3-pip
```

仮想環境を構築して切り替える
```
$ python3 -m venv /home/devuser/venv
$ export PATH="/home/devuser/venv/bin:$PATH"
$ /home/devuser/venv/bin/activate
```

必要なパッケージをインストール
```
pip install fastapi uvicorn[standard]
```

以下の階層になるようにbackendディレクトリとFast APIのソースを作成
```
project-root/
├── frontend/
├── backend/
│   ├── requirements.txt
│   └── app/
│       └── main.py
```

この状態で以下のコマンドを実行することでFast APIのサーバーが立ち上がりました！
```
$ cd project-root/backend
$ uvicorn app.main:app --host 0.0.0.0 --port 8000 // 仮想環境に入っている前提
```

### backend/Dockerfileを用意

これを作りました！（2025/06/06時点では公開中）

https://github.com/midorigameee/React-Image-Generator/blob/master/backend/Dockerfile

まだ不完全ですが、色々と工夫は凝らしてみました！
その工夫を書きたいけど！今は時間がない！ので！割愛させてください！！！！泣

## フロントエンド用のコンテナとバックエンド用のコンテナを切り替えられる仕組みを用意

今回はフロントエンド用のコンテナとバックエンド用のコンテナでそれぞれサーバーを構築します。

しかし、Devcontainerでは同時に２つのコンテナにリモートアクセスするのは難しそう？なので、片方のコンテナにリモートアクセスしたらもう片方のコンテナは自動的にサーバを立ち上げるようにしました。

そうすることで、リモートアクセスしたコンテナでは自分で開発して、任意のタイミングでコマンドを実行してサーバーを起動できます。
そのときにもう片方のサーバーとも疎通ができるように、リモートアクセスしていないコンテナでは自動でサーバーを起動しておきます。

### ディレクトリ構成

結論として、以下のようなディレクトリ構成になりました。

```
project-root/
├── .devcontainer/
│   ├── frontend/devcontainer.json 
│   ├── backend/devcontainer.json 
│   └── docker-compose_frontend.yml 
│   └── docker-compose_backend.yml 
├── frontend/
│   ├── Dockerfile
│   ├── package.json
│   └── (React app)
├── backend/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── app/
│       └── main.py
└── .git/
```

詳細は下記のリポジトリを参照ください。（2025/06/06時点では公開中）

https://github.com/midorigameee/React-Image-Generator

### サーバー起動を切り替える仕組み

`devcontainer.json`と`docker-compose.yml`をそれぞれのコンテナごとに用意するのがポイントです。

`frontend/devcontainer.json`では`docker-compose_frontend.yml`を読み込み、`backend/devcontainer.json`では`docker-compose_backend.yml`を読み込むようになっています。

このとき、`docker-compose.yml`の中では各コンテナに対して起動時に実行するコマンドを設定できます。
それぞれ以下のようにすることで、やりたいことを実現させました。

- docker-compose_frontend.yml
    - フロントエンド用のコンテナの実行コマンド
        - `sleep infinity`  // 何もしない
    - バックエンド用のコンテナの実行コマンド
        - `/home/devuser/venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000`
- docker-compose_backend.yml
    - フロントエンド用のコンテナの実行コマンド
        - `npm run dev`
    - バックエンド用のコンテナの実行コマンド
        - `sleep infinity`   // 何もしない


### コンテナを切り替える方法

`project-root/`のディレクトリでVS Codeを開くと、コマンドパレットでDevcontainer関連のコマンドを実行できると思います。

この時にRebuildやReopenを選択して実行すると、以下のようにどっちのdevcontainer.jsonを使うかを選択することができます！便利！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307348/4eb2439d-36ac-4353-b3f7-b94aced46415.png)


## おわりに

これでようやく開発環境の構築できました。長い道のりだった、、、

マルチコンテナの切り替えのあたりはもっと詳しく書きたいですが、今は気合と時間が足りないので、また別記事で書くかもです。

毎日更新することを優先すると説明がおざなりになる、、、難しいなぁ
拙い内容ですが、毎日書くことを今は目標にしているので暖かい目で見ていただけると嬉しいです！

明日からついに機能実装するぞ～～～～～～～～～～～