目次
あなたも陥る?Spring Boot + Docker Compose DB 接続の「よくある落とし穴」
Spring Boot と Docker Compose を組み合わせた開発で、「なぜかデータベースに接続できない……」という悩みに直面したことはありませんか?
多くの開発者がハマるこの問題、実は設定上の小さなミスや仕組みの誤解が原因であることがほとんどです。
ここでは、特に初〜中級の開発者が陥りやすい3つの代表的な失敗パターンを、具体例とともに紹介します。
パターン①:application.yml に localhost を書いてしまう問題
ダメな設定例(Spring Boot側)
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: user
password: pass
なぜダメなのか
Docker Compose 環境では、各サービス(コンテナ)が独立したネットワーク空間上で動作しています。
つまり、localhost は「Spring Boot アプリケーションのコンテナ」を指しており、DB コンテナのことではありません。
正しい設定例
spring:
datasource:
url: jdbc:postgresql://db:5432/mydb
username: user
password: pass
補足:db は docker-compose.yml 上のサービス名。Docker Compose は内部DNSを使って、サービス名で名前解決をしてくれます。
パターン2:ポートの誤解 – 外部ポートを参照してしまう
よくある勘違い
# application.yml 側(誤り)
url: jdbc:postgresql://localhost:15432/mydb
# docker-compose.yml 側
services:
db:
image: postgres:15
ports:
- "15432:5432"
なぜダメなのか
ports: 15432:5432 の設定は、「ホストOSの15432番ポート → コンテナ内の5432番ポート」にリダイレクトするものです。
Spring Boot コンテナはホストOSではなく、Docker Compose 内の仮想ネットワーク上で他のサービスと通信します。
そのため、ホスト側ポートではなく、コンテナ内のポート(5432)を参照すべきです。
正しい組み合わせ
# application.yml 側
url: jdbc:postgresql://db:5432/mydb
# docker-compose.yml 側(変更不要)
services:
db:
image: postgres:15
ports:
- "15432:5432"
パターン3:DB が起動する前に Spring Boot が接続を始める
よくある構成(depends_on のみ)
services:
app:
depends_on:
- db
db:
image: postgres:15
なぜダメなのか
depends_on は「起動順序」は保証しても、「サービスの準備完了(= DB が接続可能な状態)」までは保証しません。
そのため、DB がまだ起動中の段階で Spring Boot が接続を試み、Connection refused となることがあります。
改善例:healthcheck と wait-for-it を組み合わせる
services:
db:
image: postgres:15
healthcheck:
test: ["CMD", "pg_isready", "-U", "user"]
interval: 5s
timeout: 5s
retries: 5
app:
build: .
depends_on:
db:
condition: service_healthy
command: ["./wait-for-it.sh", "db:5432", "--", "java", "-jar", "app.jar"]
補足:wait-for-it.sh は指定したホスト・ポートに接続可能になるまで処理を待機するシェルスクリプトです。
このセクションのまとめ
-
localhost ではなく、Docker Compose のサービス名を使う(例: db)
-
ポートマッピングの右側(コンテナ内ポート)を参照する
-
depends_on だけでは不十分。healthcheck + wait-for-it などで接続タイミングを制御する
次のセクションでは、Docker ネットワークと Spring Boot DB 接続のメカニズムを技術的に深掘りし、「なぜそうなるのか」を解き明かしていきます。
Docker ネットワークと Spring Boot DB 接続の「なぜ?」
このセクションで何が解決できるか:
Spring Boot アプリケーションとデータベースが Docker Compose 環境で正しく通信できる仕組みを、ネットワークと接続設定の観点から根本的に理解できます。
「なぜサービス名で接続できるのか?」「なぜ localhost は通じないのか?」という疑問に対し、コンテナ内部の構造と仕組みから解き明かします。
Docker Compose における仮想ネットワークの基本
Docker Compose を使用すると、各サービスは同一の仮想ネットワーク(bridge)上に接続されます。
Compose ファイルで何も指定しない場合、すべてのサービスは自動的に同じカスタムブリッジネットワークに接続され、サービス名が DNS 名として機能します。
例:docker-compose.yml
version: "3.9"
services:
db:
image: postgres:15
app:
build: .
この場合、Spring Boot アプリケーション(app サービス)は、db というホスト名で db サービスにアクセスできます。
ネットワークの内部構成確認
docker network ls
docker network inspect <ネットワーク名>
これらのコマンドを使えば、コンテナ同士がどのネットワークに接続され、どの名前で認識されているかを確認できます。
localhost が指す場所はどこか?
これは Docker に不慣れな開発者がよく誤解するポイントです。
-
通常のローカル環境では、localhost は自分のPC(ホストOS)を指します。
-
しかし Docker コンテナ内では、localhost は「そのコンテナ自身」を指すことになります。
つまり、Spring Boot アプリケーションが localhost:5432 にアクセスしようとすると、同じコンテナ内に存在しない DB を探してしまい、接続に失敗します。
Spring Boot の JDBC URL の解釈
Spring Boot の application.yml や環境変数から取得された JDBC URL は、通常以下のように解釈されます。
spring:
datasource:
url: jdbc:postgresql://db:5432/mydb
この形式で記述された場合:
-
JDBC ドライバー(ここでは PostgreSQL)は、db:5432 に対してソケット接続を試みます。
-
db は Docker ネットワーク上のホスト名として解決され、db サービス(コンテナ)に接続します。
ホスト名解決の流れ
Docker Compose は docker-compose up 実行時に、以下を自動的に行います:
-
サービスごとに一意なコンテナ名を生成
-
同一ネットワーク内でサービス名とコンテナ名を DNS として名前解決可能にする
-
db という名前の DNS エントリ → db サービスの IP アドレスに変換
このため、ホスト名に db を使うだけで自動的に正しい接続先に到達できるという仕組みが実現しています。
application.yml と環境変数の使い分け
Docker 環境では、設定の柔軟性とセキュリティの観点から、application.yml への直書きよりも環境変数を活用する構成が推奨されます。
例:docker-compose.yml で環境変数を渡す
services:
app:
build: .
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/mydb
SPRING_DATASOURCE_USERNAME: user
SPRING_DATASOURCE_PASSWORD: pass
Spring Boot は、SPRING_DATASOURCE_URL のように環境変数名をスネークケースで渡すことで、application.yml よりも優先して値を読み取ります。
代表的な接続エラーとその原因
Connection refused
-
原因:コンテナは起動しているが、DB プロセスがまだ立ち上がっていない、または起動に失敗している
-
対策:healthcheck を使って、DB の準備完了を待つ
Unknown host
-
原因:JDBC URL に書かれたホスト名(例: db)が Docker ネットワーク上に存在しない、またはスペルミス
-
対策:docker-compose ps でサービス名を再確認。サービス名 ≠ コンテナ名に注意
No suitable driver found
-
原因:JDBC ドライバーが依存関係に含まれていない、または URL フォーマットが不正
-
対策:spring-boot-starter-data-jpa や postgresql 依存が適切に追加されているか確認
このセクションのまとめ
-
Docker Compose のサービス名は DNS として機能し、ホスト名に使える
-
localhost は自分自身のコンテナを指すため、DB への接続にはサービス名を使う
-
application.yml での設定は、環境変数を使うとより柔軟かつ安全に管理できる
-
典型的な接続エラーには、それぞれ背景となる原因があるため、「なぜそのエラーが出るのか」を理解することが重要
次のセクションでは、実践的な「デバッグ術」と「チェックリスト」に進みます。
Spring Boot + Docker Compose 環境で、DB 接続問題が発生した際にどのように原因を切り分け、解決していけば良いのかを体系的に解説していきます。
もう悩まない!Spring Boot + Docker Compose DB 接続の体系的デバッグ術
このセクションで何が解決できるか:
Spring Boot + Docker Compose 環境で発生するデータベース接続エラーに対し、再現性のあるチェックリストとコマンドベースのデバッグ手順を体系的に学べます。
「どこから確認すべきか分からない」「そもそも何を疑えばいいのか分からない」といった不安を解消し、自力での問題解決に必要なスキルと視点を獲得できます。
ステップ1:コンテナの状態を確認する
まず最初に確認すべきは、コンテナそのものが正しく起動しているかどうかです。
docker-compose ps
-
各サービスの State が Up であることを確認
-
Exit 状態や Restarting が表示されている場合、何らかのエラーで落ちている可能性あり
コンテナログの確認
docker-compose logs app
docker-compose logs db
-
Spring Boot 側で Connection refused や Unknown host が出ていないか
-
DB 側で初期化失敗や認証エラーが出ていないか
ステップ2:DB コンテナが起動済みで接続可能かを確認する
アプリから接続する前に、DB コンテナが実際に受け入れ可能な状態かを直接確認します。
docker exec -it <dbコンテナID> psql -U user -d mydb
あるいは MySQL の場合:
docker exec -it <dbコンテナID> mysql -u user -p mydb
-
これが成功すれば、DB は少なくとも内部的には起動しており、認証情報も正しい可能性が高い
-
ここで失敗する場合は、environment に設定したユーザー・パスワードの確認が必要
ステップ3:ネットワーク接続性のテスト
Spring Boot 側のコンテナから、DB サービスへの接続確認を行います。
docker exec -it <appコンテナID> ping db
docker exec -it <appコンテナID> nc -zv db 5432
-
ping db が通らない → Docker Compose のネットワーク設定やサービス名ミスを疑う
-
nc -zv が失敗 → ポートが開いていない、起動が遅れている可能性
ステップ4:JDBC URL と application.yml の確認
JDBC URL に誤りがあると、起動後即座に Connection refused または No suitable driver になります。
確認ポイント:
-
ホスト名が localhost ではなく、サービス名(例: db)になっているか
-
ポート番号が DB 側と一致しているか(通常は PostgreSQL: 5432、MySQL: 3306)
-
データベース名・ユーザー名・パスワードの設定に誤りがないか
ステップ5:環境変数が正しく渡っているか確認する
環境変数経由で設定を注入している場合は、実際にアプリケーションコンテナ内で値が渡っているかを確認します。
docker inspect <appコンテナID> | grep SPRING_DATASOURCE
または中に入って env コマンドを実行してもOKです:
docker exec -it <appコンテナID> /bin/sh
env | grep SPRING
ステップ6:Spring Boot のログを詳細化する
接続の詳細エラーを確認したい場合は、application.yml または環境変数で以下のようにログレベルを変更します。
logging:
level:
org.springframework.jdbc: DEBUG
org.springframework.boot.autoconfigure.jdbc: DEBUG
これにより、JDBC 接続時の詳細ログ(ドライバ読み込み、接続試行のタイミングなど)が表示され、原因特定がしやすくなります。
ステップ7:最小構成での再現と切り分け
問題が複雑な場合、最低限の app + db の構成で再現性を確認することが有効です。
-
docker-compose.yml で必要最低限のサービスのみ定義
-
application.yml を単純な1ファイル構成に
-
DB イメージもできるだけ公式のまま使用し、カスタム設定を外す
これにより、「接続設定のミスなのか、アプリ側のバグなのか、ネットワーク構成なのか」を切り分けやすくなります。
よくある失敗のチェックリスト(まとめ)
-
docker-compose ps でコンテナが起動しているか確認したか?
-
docker-compose logs でアプリとDBのエラーを確認したか?
-
DB に手動でログインできることを確認したか?
-
アプリコンテナから ping や nc で DB に接続できるか?
-
JDBC URL のホスト名・ポート・DB名に誤りはないか?
-
環境変数は正しく注入されているか?
-
Spring Boot のログ出力を詳細にしてエラー箇所を特定したか?
-
必要に応じて最小構成で切り分けを行ったか?
このセクションのまとめ:
-
単なる感覚や試行錯誤に頼らず、体系的な確認手順を使うことで、効率的に原因を特定できる
-
コンテナ環境では「どこで失敗しているか」が見えにくいため、構造的な視点で段階的に切り分けることが重要
-
どのステップで詰まっているかを明確にすれば、チーム内での相談や外部調査もスムーズになる
次のセクションでは、今後同じ問題が起きないための設計・構築のベストプラクティスに移ります。
設定の外部化、待機制御、ネットワークの設計といった、「そもそもつまずかないための工夫」を具体的に解説します。
堅牢な Spring Boot + Docker Compose 環境構築のためのベストプラクティスと設計思想
このセクションで何が解決できるか:
Spring Boot + Docker Compose 環境で再び同じトラブルを起こさないための設計・構築の知見を得られます。
設定の整理、起動タイミングの制御、セキュリティと運用性の観点から、実践的なベストプラクティスを体系的に学ぶことができます。
1. DB の起動確認は healthcheck で明示的に制御する
Docker Compose の depends_on は「サービスの起動順序」だけを制御します。
「DB が接続を受け付ける状態」になったかどうかは保証されません。
そのため、healthcheck を正しく設定することが極めて重要です。
例:PostgreSQL の場合
services:
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
healthcheck:
test: ["CMD", "pg_isready", "-U", "user"]
interval: 5s
timeout: 5s
retries: 5
アプリ側の depends_on 条件
app:
build: .
depends_on:
db:
condition: service_healthy
これにより、DB が正常稼働するまで Spring Boot アプリが起動しない構成が実現できます。
2. 起動タイミング制御には wait-for-it.sh または entrypoint.sh を活用する
healthcheck は Docker 側の状態把握に適していますが、アプリケーションが起動タイミングを制御するには待機スクリプトが有効です。
wait-for-it.sh の使用例
COPY wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh
command: ["wait-for-it.sh", "db:5432", "--", "java", "-jar", "app.jar"]
代替案:entrypoint.sh にリトライロジックを記述
#!/bin/sh
until nc -z db 5432; do
echo "Waiting for db..."
sleep 2
done
exec java -jar app.jar
このように、DB が本当に使える状態になるまでリトライして待機することで、接続エラーを未然に防げます。
3. 設定の外部化と秘匿化を徹底する
環境によって設定を柔軟に切り替えるには、環境変数と .env ファイル、override.yml の活用が有効です。
.env ファイル例(Git 管理対象外)
SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/mydb
SPRING_DATASOURCE_USERNAME=user
SPRING_DATASOURCE_PASSWORD=pass
docker-compose.yml 側
services:
app:
environment:
- SPRING_DATASOURCE_URL
- SPRING_DATASOURCE_USERNAME
- SPRING_DATASOURCE_PASSWORD
application.yml 側では参照だけ
spring:
datasource:
url: ${SPRING_DATASOURCE_URL}
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
これにより、設定の変更・切り替え・秘匿化が容易になり、安全で保守しやすい構成になります。
4. イメージの軽量化と起動高速化を意識する
-
マルチステージビルドで不要な依存物を除外
-
JDK → JRE ベースに切り替える(例: eclipse-temurin:17-jre)
-
アプリ側の Dockerfile に不要なキャッシュや build ツールを残さない
これにより、イメージサイズの削減と起動時間の短縮が実現でき、起動タイミングの問題を根本から減らすことにもつながります。
5. ロギングとモニタリングを仕組みに組み込む
-
Spring Boot 側で logback や log4j2 による詳細ログ出力を整備
-
docker-compose logs だけでなく、ログファイルの永続化や監視システムへの出力も視野に入れる
-
システム起動順や接続成否を ログベースで自動的に追跡できる状態にする
これにより、問題発生時にもすばやく根本原因を特定でき、チーム開発におけるトラブル共有・再現性確保にもつながります。
6. 開発環境と本番環境の設定差異を最小化する
-
docker-compose.override.yml を活用して、環境ごとの上書きを柔軟に管理
-
本番と開発で DB ホスト名やポート番号が異なると、開発時に発見できないエラーの温床になる
-
開発・テスト・本番環境をできる限り一貫した構成で管理することが重要
このセクションのまとめ:
-
起動順の保証だけでなく、「接続可能な状態」まで待つ設計を導入する
-
設定は環境変数ベースで柔軟に管理し、外部ファイルに切り出す
-
イメージの軽量化、ログの可視化、環境一貫性の確保で、開発トラブルの予防と運用性の向上を実現する
まとめ|もう「繋がらない!」で悩まない
このセクションで何が解決できるか:
この記事全体の要点を振り返り、読者が「なぜ繋がらないのか?」への理解を深め、今後のトラブルに対する自信と再現性のある対応力を得られたことを確認します。
また、さらなる学習や実践への道筋を明示し、「次にやるべきこと」が明確になります。
本記事で学んだことの振り返り
-
よくある失敗パターンを具体例で把握
-
localhost の誤用
-
ポートの勘違い
-
depends_on による起動順制御の限界
-
-
Docker ネットワークと接続メカニズムの理解
-
サービス名による DNS 解決
-
application.yml と環境変数の連携
-
コンテナ間通信と JDBC の仕組み
-
-
再現性のあるデバッグ手順とチェックリスト
-
コンテナ状態確認
-
接続テストコマンド
-
ログの読み方
-
構成の最小化と切り分け
-
-
設計レベルでのトラブル予防策
-
healthcheck と wait-for-it.sh
-
設定の外部化・秘匿化
-
イメージ最適化・ロギング整備
-
読者が得た価値
-
「繋がらない」原因を理屈で理解できるようになった
-
単なるエラー回避ではなく、本質的な仕組みに基づいた対応ができるようになった
-
似た問題が起きても、一人で冷静に切り分けて進められる手順を手に入れた
次にできること・おすすめリソース
-
本記事のチェックリストをベースにした自作テンプレートの作成
-
より実践的な検証環境の構築(複数DB、Redis との連携など)
最後に
Spring Boot と Docker Compose を使った開発は、環境の柔軟性とスケーラビリティの面で大きなメリットがありますが、同時に「見えづらい壁」によるつまずきも起こりやすい領域です。
しかし、仕組みを正しく理解し、構成の原則を押さえれば、接続エラーは恐れるべきものではありません。
「なぜ繋がらないのか?」と迷っていたあの日に、終止符を打ちましょう。
あなたの Spring Boot + Docker 開発は、今日からもう一段上のレベルに進めるはずです。
【外部リンク】
Docker公式: Docker Compose のネットワーキング
【内部リンク】
Spring Bootアプリ開発で頻発するWhitelabel Error Page|Thymeleafのテンプレートエラーと対策まとめ
Docker + Spring Boot で手軽に開発環境を構築しよう!
Spring Boot バリデーション入門|MVC統合とカスタムアノテーション実践例
【Spring Boot実践ガイド】List型・Map型の違いとBeanクラスの基礎&応用
JavaとSpring Bootで学ぶWebアプリ作成の第一歩|初心者向けステップバイステップガイド
【初心者向け】Spring Boot のパラメータ受け取り|@ModelAttribute と @RequestBody の違いと使い分け
Spring Bootでロールバックされない原因とは?@Transactional完全ガイド
MVC構成を理解すれば現場で詰まらない | Spring Boot実装ガイド
【保存版】JPA vs JDBC│Spring Bootでの実務的な使い分けと導入判断ガイド
Spring Boot の@Autowired はなぜ動く?NullPointerException 対策から学ぶ DI/IoC の基本と「正しい」コンポーネント管理術
Javaのfor文をStreamに書き換えるには?Spring Bootでの実践例付きでわかる!
Spring Bootで理解するGETとPOSTの違い|Thymeleaf実装例付きで初心者の画面遷移・エラー対応まで丁寧解説