Docker Composeを使った、実践的なコンテナ管理方法【Node.js＋PostgreSQL構成】

## はじめに
前回の記事では、Windows端末にWSL2＋Dockerをインストールする方法を紹介しました。
[Windows端末にWSL2＋Dockerをインストールする【躓きポイントも解説】](https://qiita.com/n-okutomi/items/c90a5e8a5413ea50b8ff)

この記事では、その続編として、Docker Composeを使って複数のコンテナを効率的に管理する方法について、基礎的な部分も補足しながらまとめます。

## 1. そもそもDockerとは？

Dockerとは、アプリケーションを「コンテナ」という単位でまとめて、**どこでも同じように動かせる技術**です。

たとえば、
- 「Node.jsをインストール」
- 「DBをインストール」
- 「環境変数を設定」

こうした“開発環境の構築作業”をすべてDockerで定義することで、**どのマシンでも同じ動作環境**が再現できるようになります。

## 2. Dockerfileとは？

Dockerfileは、Dockerで使う「レシピ」です。  
以下のように「何のベースイメージを使って」「どうインストールして」「どこで動かすか」などを定義します。

```Dockerfile
FROM node:18
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
CMD [ "npm", "start" ]
```
これを使って`docker build`すると、アプリケーションの実行環境（イメージ）が出来上がります。

## 3. Docker Composeとは？

Docker Composeは、**複数のDockerコンテナをまとめて管理・起動できるツール**です。

たとえば、以下のような構成があったとします。
- Webアプリ（Node.js）
- データベース（PostgreSQL）


これらのコンテナを1つずつ`docker run`で起動するのは面倒ですが、それをまとめて定義して、1コマンドで立ち上げられるのが`Docker Compose`です。

### メリット
Docker Composeを使えば、以下のようなことができます。

- `docker-compose.yml`という1つのファイルに、複数サービスの設定をまとめられる
- `docker compose up`一発で、複数コンテナを一斉に起動・連携できる
- コンテナ間のネットワークは自動でつながる（dbという名前でアプリから参照できる）
- ボリュームや環境変数、起動順の管理なども柔軟に設定可能

**本番に近い構成を、ローカルで再現するための便利なツール** というイメージです。

### よく使われるシーン
- チーム内で 同じ開発環境を整備したいとき（docker-compose.yml を共有すれば、誰でも同じ環境が手に入る）
- 本番運用を見越して、本番に近い構成でテストしたいとき

## 4. 今回構築する環境（Node.js + PostgreSQL）

### 構成
今回は、以下のような2コンテナ構成のローカル開発環境を構築します。

- Node.js（Webアプリ）
- PostgreSQL（データベース）

```
.
├── app/
│   ├── Dockerfile
│   └── index.js
├── docker-compose.yml
└── .env

```
```docker-compose.yml
version: "3.9"  # Composeファイルのバージョン

services:       # ここにコンテナを並べて定義していく
  app:          # サービス名（この例では Node.js アプリ）
    build: ./app            # Dockerfileがある場所を指定
    ports:
      - "3000:3000"         # ホスト:コンテナ のポートマッピング
    depends_on:
      - db                  # dbコンテナを先に起動してからappを起動
    environment:
    - DATABASE_URL=postgres://postgres:password@db:5432/mydb  # 環境変数の定義（Node.jsアプリ用）
    volumes:
      - ./app:/usr/src/app  # ローカルとコンテナのディレクトリを同期（ホットリロード可）
    working_dir: /usr/src/app # 作業ディレクトリを指定（npmコマンドの実行場所）
    command: npm start       # コンテナ起動時に実行するコマンド

  db:           # サービス名（PostgreSQL）
    image: postgres:14       # 公式のPostgreSQLイメージを使う
    environment:
      POSTGRES_USER: postgres       # DBのユーザー名
      POSTGRES_PASSWORD: password   # DBのパスワード
      POSTGRES_DB: mydb             # 初期作成されるDB名
    volumes:
      - db-data:/var/lib/postgresql/data　 # DBデータを永続化するためのボリューム

volumes:
  db-data:                     # ボリュームの定義（上記で使ってる名前）

```
### アプリ側の構成（index.js と Dockerfile）

```app/index.js
const http = require("http");
const port = 3000;

const server = http.createServer((req, res) => {
  res.end("Hello from Docker Compose!");
});

server.listen(port, () => {
  console.log(`Server is running at http://localhost:${port}`);
});
```
```:app/Dockerfile
FROM node:18

WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

COPY . .

CMD [ "node", "index.js" ]

```

### .env（任意）
ポート番号や環境変数を外出ししたい場合は`.env`に定義して、`docker-compose.yml`から参照できます。


## 5. 起動コマンドと動作確認
以下のコマンドをターミナル（WSL2）で実行します。

```bash
docker compose up -d --build
```
- `-d`: バックグラウンドで起動
- `--build`: Dockerfileからイメージをビルド（初回は必須）

その後、ブラウザで以下にアクセス：
- http://localhost:3000

`Hello from Docker Compose!`が表示されればOK

## 6. よく使うオプションや便利なTips

### コンテナのログを見る
```bash
docker compose logs -f
```

### コンテナを停止・削除する
```bash
docker compose down
```

### コンテナを再起動する
```bash
docker compose restart
```

### ホットリロードしたい時
```yaml
volumes:
  - ./app:/usr/src/app
```
`volumes:` でローカルのコードをマウントすれば、コードを修正すると即反映されます。

## 7. WSL2環境での注意点・トラブルシューティング
| 事象                        | 原因・対処例                                            |
| ------------------------- | ------------------------------------------------ |
| DBに接続できない（`ECONNREFUSED`） | DBの起動が間に合っていない。`depends_on`に加えて、アプリにリトライ処理を入れると安定。   |
| コンテナからホストのファイルが読めない       | WSL2ではWindows側のパスとの相性問題が出ることがある。WSLパス上で操作する方が安定。 |
| ポートが競合する                  | `.env`でポートを管理しておくと柔軟に対応できる。                      |

## おわりに

Docker Composeを使えば、複数コンテナを一括管理でき、ローカルでも本番に近い環境を簡単に再現できます。

次回は、今回作成した`docker-compose.yml`をベースに、  
本番/開発環境（Amazon ECSなど）へデプロイする構成や手順についてまとめる予定です。

本記事が、Docker初学者〜中級者の最初の壁を越える助けになれば幸いです。