Docker ComposeでExpress APIとPostgreSQLを同時に起動する方法|Dockerfileからのハンズオン


はじめに

Dockerの基本操作に慣れてきたら、複数のコンテナをまとめて扱ってみましょう。Webアプリケーションの開発では、APIとデータベースを同時に起動することがあります。

この記事では、Node.jsのExpressで小さなAPIを作成し、Dockerfileでイメージにします。その後、PostgreSQLと一緒にDocker Composeで起動します。ブラウザやcurlからAPIにアクセスし、PostgreSQLにはpsqlで接続して、それぞれ動作を確認します。

今回のAPIは「Hello, World!」を返すだけです。APIからPostgreSQLへ接続する処理は含みません。 まずはアプリケーションとDBを別々のコンテナとして起動する流れをつかみましょう。

前提条件

  • DockerとDocker Composeが使えること
  • ターミナルでコマンドを実行できること
  • ホスト側の3000番ポートが空いていること

Docker Desktopを使う場合は、アプリを起動してから以下のコマンドを実行してください。バージョンが表示され、docker infoでエラーが出なければ準備完了です。

docker --version
docker compose version
docker info

ローカルPCへのNode.jsやPostgreSQLのインストールは不要です。

1. 作業用ディレクトリを作る

mkdir docker-express-postgres
cd docker-express-postgres

最終的なファイル構成は次のとおりです。

docker-express-postgres/
├── app.js
├── package.json
├── Dockerfile
└── compose.yaml

2. ExpressのAPIを作る

package.jsonを作成します。ExpressはNode.jsでAPIを作るためのパッケージです。

{
  "name": "docker-express-postgres",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "express": "^5.1.0"
  }
}

続いて、app.jsを作成します。

const express = require('express');

const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello, World!');
});

app.listen(port, '0.0.0.0', () => {
  console.log(`API is listening on port ${port}`);
});

/へアクセスすると、Hello, World!という文字列を返します。ホスト名に0.0.0.0を指定し、コンテナの外から公開ポートを通じてアクセスできるようにしています。

3. DockerfileでAPIのイメージを作る

同じディレクトリに、次の内容でDockerfileを作成します。

FROM node:24-alpine

WORKDIR /usr/src/app

COPY package.json ./
RUN npm install --omit=dev

COPY app.js ./

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

各行の役割は次のとおりです。

命令この例での役割
FROMNode.jsを使えるベースイメージを指定する
WORKDIR以降の作業ディレクトリを決める
COPYpackage.jsonとAPIのコードをイメージへコピーする
RUNイメージのビルド中にExpressをインストールする
CMDコンテナ起動時にAPIを実行する

ここでpackage.jsonを先にコピーして依存パッケージをインストールし、その後でapp.jsをコピーしています。

まずはDocker Composeを使わず、API単体で動作を確認します。

docker build -t my-express-api .
docker run --rm --name my-express-api -p 3000:3000 my-express-api

-p 3000:3000は、PCの3000番ポートとコンテナの3000番ポートを接続する指定です。--rmを付けると、コンテナの終了時にそのコンテナを削除します。

別のターミナルを開いて、次のコマンドを実行してください。

curl http://localhost:3000/

次の結果が表示されれば、APIをコンテナ内で起動できています。

Hello, World!

元のターミナルでControl + Cを押し、APIを停止してから次へ進みます。同じポートを使うため、単体起動のコンテナを動かしたままにしないでください。

4. ComposeファイルにAPIとDBを定義する

compose.yamlを作成します。

services:
  api:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db

  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: examplepassword
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

apiサービスは同じディレクトリのDockerfileからイメージをビルドします。dbサービスは既存のPostgreSQLイメージを使います。POSTGRES_PASSWORDは、このローカル実習で使うDB管理ユーザーのパスワードです。公開環境でこの値をそのまま使わないでください。

depends_onはdbを先に起動する指定です。ただし、DBへの接続準備が完了するまで待つ設定ではありません。今回のAPIはDBに接続しないため、起動順序を確認する例として記載しています。

pgdataはPostgreSQLのデータを保存する名前付きボリュームです。DBの5432番ポートはPCへ公開していません。今回はコンテナ内のpsqlからDBを操作します。

5. 2つのコンテナを起動する

compose.yamlがあるディレクトリで実行します。

docker compose up --build -d

--buildを付けるとAPIのイメージをビルドしてから起動します。-dはバックグラウンドで実行する指定です。

起動状態を確認しましょう。

docker compose ps

apiとdbの両方が実行中であれば成功です。APIにもアクセスします。

curl http://localhost:3000/
Hello, World!

APIが起動しない場合は、次のコマンドでログを確認できます。

docker compose logs api

6. PostgreSQLにも接続してみる

起動中のDBコンテナでpsqlを実行します。

docker compose exec db psql -U postgres -d postgres

postgres=#という表示になったら、次のSQLを入力してください。

SELECT current_database();

postgresと表示されれば、DBに接続できています。終了するには次を入力します。

\q

ここまでで、ExpressのAPIとPostgreSQLをDocker Composeで同時に起動し、両方の動作を確認できました。APIがDBへ問い合わせたわけではない点は区別しておきましょう。

7. コンテナを停止する

実習が終わったら、Composeで作成したコンテナとネットワークを停止・削除します。

docker compose down

このコマンドでは、名前付きボリュームpgdataは残ります。実習用のDBデータも含めて削除したい場合だけ、次のコマンドを使用してください。

docker compose down -v

-vを付けるとボリューム内のデータも削除されます。

まとめ

この記事では、ExpressでAPIを作り、Dockerfileでイメージをビルドしました。さらにDocker ComposeでPostgreSQLと同時に起動し、APIへのHTTPアクセスとpsqlによるDB接続を確認しました。

  • Dockerfileのbuild: .で、自作APIのイメージを使える
  • ComposeのservicesにAPIとDBを並べて定義できる
  • docker compose up --build -dで両方を起動できる
  • docker compose execで起動中のDBコンテナ内のコマンドを実行できる

この構成は「APIとDBを同時に起動する」ところまでの入門例です。APIからDBを読み書きする処理は、ここでは実装していません。

参考記事

, ,

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です