|

Spring BootのDocker Compose連携:ローカル開発環境を自動起動する

はじめに

Spring BootでWebアプリケーションを開発していると、ローカル開発用にMySQL、PostgreSQL、Redis、RabbitMQ、ElasticsearchなどをDocker Composeで起動することがよくあります。

従来は、開発を始める前に次のようなコマンドを手動で実行していた人も多いと思います。

docker compose up -d

そして、開発が終わったら以下のように停止します。

docker compose down

この運用でも問題はありませんが、プロジェクトが増えてくると少し面倒です。

・Docker Composeを起動し忘れる
・どのcompose.ymlを使うのか迷う
・ポート番号が環境ごとにずれる
・READMEに手順を書いても新人が詰まる
・アプリは起動したのにDBがまだ起動中で接続エラーになる

Spring Bootには、開発時の外部サービスを扱うための仕組みとして Docker Compose連携 が用意されています。Spring Boot公式ドキュメントでは、開発時サービスとしてDocker ComposeとTestcontainersのサポートが提供されていると説明されています。

この記事では、既存の手動Docker Compose運用から、Spring BootのDocker Compose連携へ移行する人に向けて、仕組み、導入手順、compose.ymlapplication.yml、よくあるエラーをやさしく解説します。


Spring BootのDocker Compose連携とは

Spring BootのDocker Compose連携は、アプリケーション起動時にDocker Composeで定義された外部サービスを自動で起動してくれる機能です。

通常のDocker Compose運用では、次のような流れになります。

1. docker compose up -d を実行する
2. DBやRedisなどが起動する
3. Spring Bootアプリを起動する
4. 開発が終わったら docker compose down / stop を実行する

Spring BootのDocker Compose連携を使うと、開発者の作業は基本的にこうなります。

1. Spring Bootアプリを起動する
2. Spring Bootがcompose.ymlを見つける
3. 必要なコンテナを起動する
4. コンテナの接続情報をSpring Boot側に自動で渡す
5. アプリ終了時にコンテナを停止する

公式ドキュメントによると、spring-boot-docker-compose を依存関係に追加すると、Spring Bootは作業ディレクトリから compose.yml などの一般的なComposeファイル名を探し、見つかったComposeファイルに対して docker compose up を呼び出し、サポート対象コンテナのサービス接続情報を作成し、アプリ終了時に docker compose stop を呼び出します。

つまり、ローカル開発に必要なDBやRedisを、アプリケーション起動とセットで立ち上げられるということです。


何がうれしいのか

一番大きなメリットは、ローカル開発の手順を減らせることです。

Before:

docker compose up -d
./gradlew bootRun

After:

./gradlew bootRun

開発者はSpring Bootアプリを起動するだけでよくなります。

特にチーム開発では、この差が地味に効きます。

・READMEの手順が短くなる
・初回セットアップが簡単になる
・DBやRedisの起動忘れが減る
・ローカル環境差分を減らしやすい
・アプリ側の接続先設定をシンプルにできる

移行作業中の人にとっても、「既存の compose.yml をいきなり捨てる」のではなく、今あるDocker Compose定義をSpring Bootから起動できるようにするイメージなので、比較的導入しやすいです。


前提条件

Spring BootのDocker Compose連携を使うには、ローカル環境にDockerとDocker Composeが必要です。

公式ドキュメントでは、dockerdocker compose、または docker-compose CLIがパス上に存在している必要があり、サポートされるDocker Composeの最小バージョンは 2.2.0 とされています。

確認コマンドは以下です。

docker --version
docker compose version

Windows環境の場合は、Docker Desktopが起動していることも確認してください。


build.gradleに依存関係を追加する

Gradleプロジェクトの場合、build.gradle に以下を追加します。

dependencies {
    developmentOnly("org.springframework.boot:spring-boot-docker-compose")
}

公式ドキュメントでも、Gradleでは developmentOnly("org.springframework.boot:spring-boot-docker-compose") を追加する例が示されています。

ポイントは implementation ではなく developmentOnly にすることです。

Docker Compose連携は、基本的にローカル開発時に使う機能です。本番環境のアプリケーションに含めたいものではないため、developmentOnly として扱うのが自然です。

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    runtimeOnly("com.mysql:mysql-connector-j")

    developmentOnly("org.springframework.boot:spring-boot-docker-compose")
}

compose.ymlを作成する

次に、プロジェクト直下に compose.yml を作成します。

例として、MySQLを起動する構成にしてみます。

services:
  mysql:
    image: mysql:8.4
    ports:
      - "3306"
    environment:
      MYSQL_DATABASE: sample_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: app_password
      MYSQL_ROOT_PASSWORD: root_password
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot_password"]
      interval: 10s
      timeout: 5s
      retries: 10

ここで重要なのは、ポート指定を次のようにしている点です。

ports:
  - "3306"

"3306:3306" のように固定でホスト側ポートを指定しても動きますが、複数プロジェクトを同時に動かす場合はポート競合しやすくなります。

Spring BootのDocker Compose連携では、コンテナのマッピング済みポートを使ってサービス接続を確立します。公式ドキュメントでも、コンテナ内ではPostgreSQLが5432で起動していても、ローカル側では別のポートにマッピングされることがあり、Spring Bootのサービス接続はローカルにマッピングされたポートを検出して利用すると説明されています。

そのため、ローカル側ポートを固定しなくても、Spring Boot側が接続先を見つけてくれます。


application.ymlはどう書く?

Docker Compose連携を使う場合、対応しているサービスであれば接続情報をSpring Bootが自動で作ってくれるため、ローカル開発用の spring.datasource.url を細かく書かなくて済むケースがあります。

例えば、従来は以下のように書いていたかもしれません。

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/sample_db
    username: app_user
    password: app_password

Docker Compose連携を使う場合は、まずはDB接続情報を書かずに起動してみるのがおすすめです。

spring:
  application:
    name: docker-compose-sample

Spring Bootのサービス接続では、接続情報が通常の設定プロパティよりも優先されます。公式ドキュメントでも、Spring Bootの自動構成はサービス接続情報を利用でき、利用する場合は通常の接続設定プロパティよりも優先されると説明されています。

ただし、プロジェクトによっては明示的な設定が必要な場合もあります。まずは自動接続で動かし、うまくいかない場合だけ application-local.yml などに接続情報を寄せるのが移行しやすいです。


実行してみる

準備ができたら、Spring Bootアプリを起動します。

./gradlew bootRun

WindowsでGradle Wrapperを使う場合は以下です。

gradlew.bat bootRun

起動時に、Spring Bootが compose.yml を検出し、必要に応じて docker compose up を呼び出します。

イメージとしては、ログに以下のような流れが出ます。

Docker Compose file found in project directory
Starting Docker Compose services...
Container mysql started
Established service connection to MySQL
Started DemoApplication

実際のログ表現はバージョンや環境によって異なりますが、見るべきポイントは次の3つです。

・compose.ymlを検出しているか
・MySQLなどのコンテナが起動しているか
・アプリがDB接続に成功しているか

既存のdocker-compose.ymlから移行する場合

既に docker-compose.yml を使っているプロジェクトでは、いきなりファイルを大きく変更する必要はありません。

まずは以下の順番で移行するのがおすすめです。

1. build.gradle に spring-boot-docker-compose を追加する
2. 既存の docker-compose.yml をプロジェクト直下に置く
3. アプリを起動して、Spring BootがComposeファイルを見つけるか確認する
4. DB接続設定を少しずつ削って、自動接続できるか確認する
5. ポート固定が不要なら ports を "3306" のように変更する
6. healthcheck を追加する

最初から完璧にする必要はありません。

特に移行作業では、次のように段階的に切り替えると安全です。

第1段階:今まで通り docker compose up でも動く状態を維持する
第2段階:Spring Boot起動時に自動でComposeを起動できるようにする
第3段階:DB接続情報を自動接続へ寄せる
第4段階:READMEや新人向け手順を簡略化する

いきなり application.yml から全接続情報を消すと、原因調査が難しくなる場合があります。まずは小さく導入しましょう。


composeファイルの場所を変えたい場合

Composeファイルがプロジェクト直下にない場合や、ファイル名を変えたい場合は、application.yml で明示できます。

spring:
  docker:
    compose:
      file: ../docker/compose-local.yml

公式ドキュメントでも、Composeファイルがアプリケーションと同じディレクトリにない場合や名前が異なる場合、spring.docker.compose.file を使って指定できると説明されています。

例えば、以下のような構成にしたい場合です。

project-root/
  app/
    build.gradle
    src/
  docker/
    compose-local.yml

この場合、app/src/main/resources/application.yml に次のように書きます。

spring:
  docker:
    compose:
      file: ../docker/compose-local.yml

コンテナの起動完了を待つ

Docker ComposeでDBを起動した直後は、コンテナは起動していても、DBがまだ接続可能になっていないことがあります。

この状態でSpring BootアプリがDBへ接続しようとすると、以下のようなエラーになることがあります。

Communications link failure
Connection refused
The connection attempt failed

この対策として、compose.ymlhealthcheck を書くのがおすすめです。

services:
  mysql:
    image: mysql:8.4
    ports:
      - "3306"
    environment:
      MYSQL_DATABASE: sample_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: app_password
      MYSQL_ROOT_PASSWORD: root_password
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot_password"]
      interval: 10s
      timeout: 5s
      retries: 10

公式ドキュメントでも、Docker Composeで起動したコンテナが完全に準備できるまで時間がかかることがあり、準備状態の確認には healthcheck の追加が推奨されています。healthcheck がない場合でも、Spring Bootはマッピング済みポートにTCP接続できるかで準備状態を確認します。

起動が遅いサービスの場合は、application.yml 側でタイムアウトを調整できます。

spring:
  docker:
    compose:
      readiness:
        tcp:
          connect-timeout: 10s
          read-timeout: 5s

ライフサイクル管理を変更する

デフォルトでは、Spring Bootはアプリケーション起動時に docker compose up を呼び、アプリケーション終了時に docker compose stop を呼びます。ライフサイクルを変更したい場合は、spring.docker.compose.lifecycle-management を使います。指定できる値には、nonestart-onlystart-and-stop があります。

例えば、アプリ終了後もコンテナを起動したままにしたい場合は start-only を使います。

spring:
  docker:
    compose:
      lifecycle-management: start-only

開発中はアプリを何度も再起動することがあります。
そのたびにDBコンテナを停止・起動すると時間がかかる場合は、start-only が便利です。

一方で、毎回クリーンな状態に近づけたい場合は、デフォルトのままにするか、停止コマンドを調整します。

spring:
  docker:
    compose:
      lifecycle-management: start-and-stop
      stop:
        command: down
        arguments:
          - "--volumes"

ただし、--volumes を使うとDBデータも消える可能性があります。
ローカルで作ったデータを残したい場合は注意してください。


Docker Composeプロファイルを使う

Docker Compose側でプロファイルを分けている場合は、Spring Bootから有効化できます。

spring:
  docker:
    compose:
      profiles:
        active: local

公式ドキュメントでも、Docker Compose profilesはSpring profilesと同じように特定環境向けにCompose設定を調整でき、spring.docker.compose.profiles.active で有効化できると説明されています。

例えば、通常開発ではMySQLだけ、重めの検証時だけRedisやMailpitも起動したい場合に便利です。

services:
  mysql:
    image: mysql:8.4
    ports:
      - "3306"
    environment:
      MYSQL_DATABASE: sample_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: app_password
      MYSQL_ROOT_PASSWORD: root_password

  redis:
    image: redis:7
    ports:
      - "6379"
    profiles:
      - local-extra

この場合、local-extra を有効にしたときだけRedisが起動します。

spring:
  docker:
    compose:
      profiles:
        active: local-extra

テストで使いたい場合

Spring BootのDocker Compose連携は、デフォルトではテスト実行時に無効です。テストでもDocker Composeを使いたい場合は、spring.docker.compose.skip.in-tests=false を設定し、Gradleでは依存関係を developmentOnly ではなく testAndDevelopmentOnly に変更する必要があります。

dependencies {
    testAndDevelopmentOnly("org.springframework.boot:spring-boot-docker-compose")
}

application.yml には以下のように書きます。

spring:
  docker:
    compose:
      skip:
        in-tests: false

ただし、結合テスト用途ではTestcontainersのほうが向いている場面もあります。
Docker Compose連携は「普段のローカル開発を楽にする」、Testcontainersは「テストコードから再現性の高いコンテナを起動する」と考えると整理しやすいです。


よくあるエラーと対処

1. dockerコマンドが見つからない

エラー例:

Cannot run program "docker"

対処:

・Docker Desktopがインストールされているか確認する
・Docker Desktopが起動しているか確認する
・docker --version が実行できるか確認する
・Windowsの場合、WSL連携やPATH設定を確認する

2. compose.ymlが見つからない

エラー例:

No Docker Compose file found

対処:

・プロジェクト直下に compose.yml があるか確認する
・ファイル名が docker-compose.yml などになっている場合も検出対象か確認する
・場所が違う場合は spring.docker.compose.file を指定する
spring:
  docker:
    compose:
      file: ./docker/compose-local.yml

3. DB接続に失敗する

エラー例:

Connection refused
Communications link failure

対処:

・DBコンテナが起動しているか確認する
・healthcheckを追加する
・DBのユーザー名・パスワード・DB名が正しいか確認する
・Spring Bootのサービス接続が効いているかログを見る

4. ポートが競合する

エラー例:

port is already allocated

対処:

・"3306:3306" のような固定ポートをやめる
・"3306" のようにコンテナ側ポートだけ指定する
・別プロジェクトのDBコンテナが起動していないか確認する

複数プロジェクトを並行開発する場合、固定ポートは衝突しやすいです。
Spring Bootのサービス接続に任せられるなら、ホスト側ポートは固定しないほうが楽です。


5. アプリ終了後にコンテナを残したい

対処:

spring:
  docker:
    compose:
      lifecycle-management: start-only

これにより、アプリ終了後もDocker Composeサービスを残しやすくなります。


移行チェックリスト

既存の手動Docker Compose運用から移行する場合は、以下を確認しましょう。

□ Docker / Docker Compose CLI が使えるか
□ build.gradle に spring-boot-docker-compose を追加したか
□ 依存関係は developmentOnly になっているか
□ compose.yml をプロジェクト直下に置いたか
□ 別ディレクトリに置く場合、spring.docker.compose.file を設定したか
□ DBやRedisに healthcheck を追加したか
□ application.yml のDB接続設定を残すか削るか決めたか
□ ポート固定による競合が起きていないか
□ コンテナを停止する運用か、残す運用か決めたか
□ READMEのローカル起動手順を更新したか
□ チームメンバーのDocker Desktop / WSL環境で動作確認したか

まとめ

Spring BootのDocker Compose連携を使うと、ローカル開発に必要なMySQL、PostgreSQL、Redisなどの外部サービスを、Spring Bootアプリの起動に合わせて自動起動できます。

重要なポイントは以下です。

・Gradleでは spring-boot-docker-compose を developmentOnly で追加する
・compose.yml をプロジェクト直下に置くと自動検出される
・Spring Boot起動時に docker compose up が実行される
・対応サービスは接続情報を自動で扱える
・healthcheck を書くと起動待ちが安定する
・必要に応じて lifecycle-management を調整する

移行作業では、いきなり既存設定を全部消すのではなく、まずは今の compose.yml を活かして、Spring Bootから自動起動できるようにするのがおすすめです。

手動で docker compose up していた作業が不要になるだけでも、ローカル開発のストレスはかなり減ります。
チームで開発している場合は、READMEの手順も短くなり、新しいメンバーが環境構築でつまずきにくくなるはずです。

是非フォローしてください

最新の情報をお伝えします

類似投稿