1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Spring BootとPostgreSQLのDocker化

Last updated at Posted at 2025-06-12

docker-logo-blue.png

本記事のDockerロゴは、公式ガイドラインに沿って使用しています。
https://www.docker.com/ja-jp/company/newsroom/media-resources/

はじめに

ポートフォリオを作成していく中で、「自分の環境では動くが、採用担当者の環境では動かない」という可能性を考えました。Java のバージョン違いやデータベースの設定差異、OSの違いなどが原因で、せっかく作ったアプリケーションが評価してもらえないリスクがあります。そこで Docker を使用して環境を統一し、どの環境でも確実に動作するようにしました。
Dockerに触れたことのない方でも、「プロジェクトのセットアップ」セクションの手順に従うことで、簡単にアプリケーションを起動できます。ハンズオンでの体験ができますので、ぜひお試しください。

ディレクトリ構成

expensecalendar/
├── .env.example          # 環境変数のテンプレート(ダミーパスワードを記述)
├── .env                  # 実際の環境変数(.gitignoreに含める)
├── expensecalendar-backend/
│   ├── Dockerfile        # イメージ
│   ├── build.gradle      # backendのビルド設定(依存、プラグインなど)
│   └── src/
│       └── main/
│           └── resources/
│               └── application-dev.properties  # 開発環境用DB設定
├── build.gradle          # rootのビルド設定(Heroku用にStageタスクのみ定義)
├── compose.yaml          # Docker Compose設定
└── settings.gradle       # Multi-Project Build構成の定義

.env

# Spring Bootのプロファイル
SPRING_PROFILES_ACTIVE=dev
 
# PostgreSQLの設定(Dockerコンテナ用)
POSTGRES_DB=expensecalendar_db
POSTGRES_USER=springuser
POSTGRES_PASSWORD=mypassword

# Spring Bootアプリケーションのデータソース設定
SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/expensecalendar_db
SPRING_DATASOURCE_USERNAME=springuser
SPRING_DATASOURCE_PASSWORD=mypassword

こちらは実際に使用する環境変数の設定です。

重要ポイント

  • PostgreSQL設定: Dockerコンテナの初期化に使用
  • Spring Boot設定: アプリケーションからのDB接続に使用
  • ホスト名: localhostではなくdb(Docker Composeのサービス名)を指定
  • パスワード: 実際に使用するものを記述し、必ず.gitignoreに含めてください

.envファイルを使用するメリット

  • 設定の一元管理: 環境変数を1つのファイルで管理
  • セキュリティ: 機密情報をコードから分離
  • 環境切り替え: 開発・本番環境の設定を簡単に変更
  • チーム開発: .env.exampleでテンプレート共有

Docker Secretsを使わない理由

本番環境ではDocker Secretsの使用が推奨されますが、今回の目的は「ローカルでの環境の固定」と「機密情報をコードから分離」することにあるため、.envファイルを採用しています。

※Docker Secretsについて詳しく知りたい方は、「参考文献」セクションの書籍や公式ドキュメントをご参照ください。

.env.example

# Spring Bootのプロファイル
SPRING_PROFILES_ACTIVE=dev

# PostgreSQLの設定(Dockerコンテナ用)
POSTGRES_DB=expensecalendar_db
POSTGRES_USER=springuser
POSTGRES_PASSWORD=yourpassword

# Spring Bootアプリケーションのデータソース設定
SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/expensecalendar_db
SPRING_DATASOURCE_USERNAME=springuser
SPRING_DATASOURCE_PASSWORD=yourpassword

GitHubに公開するダミーパスワードが書かれた環境変数のテンプレートです。
採用担当者の方はコピーして.envを作成し、実際のパスワードに変更します。

application-dev.properties

#== ローカル開発環境の設定 ==

#Postgresのドライバの設定
spring.datasource.driver-class-name=org.postgresql.Driver
#PostgresのURLの設定
spring.datasource.url=${SPRING_DATASOURCE_URL}
#Postgresのユーザ名の設定
spring.datasource.username=${SPRING_DATASOURCE_USERNAME}
#Postgresのパスワードの設定
spring.datasource.password=${SPRING_DATASOURCE_PASSWORD}

#SQLスクリプトの初期化の設定
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:schema.sql
spring.sql.init.data-locations=classpath:data.sql

#Log表示設定
logging.level.com.ozeken.expensecalendar=DEBUG

# MyBatisのマッパーXMLの場所を指定
mybatis.mapper-locations=classpath:mapper/*.xml
# MyBatisで使うエンティティのパッケージ指定
mybatis.type-aliases-package=com.ozeken.expensecalendar.entity

# Thymeleafのキャッシュを無効にする
spring.thymeleaf.cache=false

開発環境用のDB設定です。

重要ポイント

  • 環境変数の活用: ${SPRING_DATASOURCE_URL}などのプレースホルダーに.envで定義した値が挿入される
  • プロファイル: application-dev.propertiesSPRING_PROFILES_ACTIVE=devで有効になる

gradleファイル

backendにプロジェクトをまとめてDocker化する場合、gradleファイルの設定に苦労したため、gradleファイルの記述も解説します。

rootのbuild.gradle

// ==========================================
// Multi-Project Build用 ルートプロジェクト設定
// expensecalendar-backendプロジェクトのタスクをルートから実行可能にする
// ==========================================

// Heroku等のデプロイプラットフォーム用
tasks.register("stage") {
    group = "build"
    description = "Prepares application for deployment"
    dependsOn("expensecalendar-backend:bootJar")
}

Heroku など一部の PaaS 環境に対応するために、カスタムの stage タスクを定義しています。Heroku の Java ビルドパックでは、デフォルトで ./gradlew stage が実行されるため、このタスクを定義して bootJar に依存させることで、デプロイ時に自動的に JAR が生成されるようにしています。
特別な処理が不要であれば、この stage タスクだけ定義しておけば問題ありません。

rootのsettings.gradle

// プロジェクト全体の名前を定義
rootProject.name = 'expensecalendar'

// backendプロジェクトを Multi-Project Build として含める
include('expensecalendar-backend')

include('expensecalendar-backend') :
expensecalendar-backendexpensecalendarのサブプロジェクトと認識させるための設定です。

この2つのgradleファイルでrootからbackendのプロジェクトをビルドすることができます。


backendのgradleファイル

通常のSpring Bootプロジェクトと同じ書き方のため、説明は省略します。

Dockerfile

# Build stage
FROM eclipse-temurin:17-jdk AS build

WORKDIR /app

# 依存関係をキャッシュするためにビルドに必要なファイルを先にコピー
COPY build.gradle settings.gradle gradlew gradlew.bat ./
COPY gradle ./gradle
COPY expensecalendar-backend/build.gradle ./expensecalendar-backend/

# gradlewに実行権限を付与(Linux環境なら必須)
RUN chmod +x gradlew

# ソースコードをコピー
COPY expensecalendar-backend/src ./expensecalendar-backend/src

# ビルド実行(デーモンを使わずクリーンビルド)
RUN ./gradlew clean build --no-daemon

# Runtime stage
FROM eclipse-temurin:17-jre

WORKDIR /app

# build stageからビルド済みjarだけをコピー
COPY --from=build /app/expensecalendar-backend/build/libs/*.jar app.jar

# アプリ起動
CMD ["java", "-jar", "app.jar"]

1. Build Stage(ビルドステージ)

# Build stage
FROM eclipse-temurin:17-jdk AS build
  • FROM eclipse-temurin:17-jdk : Java 17のJDK(開発用)をベースイメージとして使用
  • AS build: このステージに「build」という名前を付ける(後で参照するため)
WORKDIR /app
  • WORKDIR : コンテナ内の作業ディレクトリを/appに設定
  • 以降のコマンドは全て/appディレクトリで実行される

2. 依存関係のキャッシュ戦略

# 依存関係をキャッシュするためにビルドに必要なファイルを先にコピー
COPY build.gradle settings.gradle gradlew gradlew.bat ./
COPY gradle ./gradle
COPY expensecalendar-backend/build.gradle ./expensecalendar-backend/

なぜ先にGradleファイルをコピーするのか

  • Dockerはレイヤーキャッシュという仕組みがあり、ファイルが変更されていなければ前回のビルド結果を再利用する
  • build.gradleが変わらなければ、依存関係のダウンロードをスキップできる

コピーの順序が重要

  1. 設定ファイル(変更頻度:低)→ キャッシュしやすい
  2. ソースコード(変更頻度:高)→ 最後にコピー

そのため設定ファイルを先にコピーしておきます。


3. 実行権限の付与

# gradlewに実行権限を付与(Linux環境なら必須)
RUN chmod +x gradlew

chmod +x : Linuxコンテナでは明示的に権限設定が必要なため、gradlewファイルに実行権限を与えます。


4. ソースコードのコピーとビルド

コピー

# ソースコードをコピー
COPY expensecalendar-backend/src ./expensecalendar-backend/src
  • 変更が多いため、最後にソースコードをコピー

ビルド

# ビルド実行(デーモンを使わずクリーンビルド)
RUN ./gradlew clean build --no-daemon
  • clean build : 古いビルド結果を削除してから新しくビルド
  • --no-daemon : Gradleデーモンを使わない(コンテナ内では不要で、メモリ節約)

5. Runtime Stage(実行段階)

# Runtime stage
FROM eclipse-temurin:17-jre
  • 実行段階ではJRE(実行用)をベースイメージとして設定
    (JDKと比べて軽量なため)
WORKDIR /app

# build stageからビルド済みjarだけをコピー
COPY --from=build /app/expensecalendar-backend/build/libs/*.jar app.jar
  • --from=build : 前のbuildステージからファイルを参照
  • 重要 : ソースコードやGradleキャッシュは含まれない、JARファイルのみ
# アプリ起動
CMD ["java", "-jar", "app.jar"]
  • コンテナ起動時に実行されるコマンド

6. 最終的な効果

この Dockerfile により以下が実現されます:

  • 軽量なイメージ : JRE + JARファイルのみ
  • 高速ビルド : キャッシュ戦略により依存関係の再ダウンロードを削減
  • 安全性 : ソースコードが本番イメージに含まれない

compose.yaml

services:
  expensecalendar-backend:
    build:
      context: .
      dockerfile: expensecalendar-backend/Dockerfile
    env_file:
      - .env
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE}
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      - POSTGRES_DB=${POSTGRES_DB}
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    ports:
      - "5432:5432"

サービス構成

  • expensecalendar-backend: Spring Bootアプリケーションの設定
  • db: PostgreSQLデータベースの設定

重要ポイント

  • env_file:: .envファイルの環境変数を自動読み込み
  • depends_on:: データベースが起動してからアプリケーションを開始
  • ports:: ホストからコンテナへのポート転送(8080→8080、5432→5432)
  • build:: DockerfileからイメージをビルドしてSpring Bootアプリを実行

プロジェクトのセットアップ

実際に動作を確認したい方は、以下をインストールし、リポジトリをクローンしてお試しください:

必要なツール

  • Docker Desktop (必須): コンテナ実行環境
  • pgAdmin (任意): データベースをGUIで確認

Docker Desktop

https://www.docker.com/

pgAdmin(任意)

https://www.postgresql.jp/download

データベースの中身をGUIで確認できるため、動作確認に便利です。

リポジトリのクローンと.envの作成

git clone https://github.com/ktr0203ozeken/expensecalendar.git
cd expensecalendar
cp .env.example .env
nano .env 

コンテナのビルド・起動

操作手順

docker compose up

コンテナをビルド&起動します。初回は時間がかかる場合があります。


ビルド確認ログ

[+] Running 3/3
 ✔ Network expensecalendar_default                      Created     0.0s
 ✔ Container expensecalendar-db-1                       Created     0.1s
 ✔ Container expensecalendar-expensecalendar-backend-1  Created     0.1s

コンテナの作成・起動が確認できます。


DBログインログ

expensecalendar-backend-1  | ~~ : The following 1 profile is active: "dev"

expensecalendar-backend-1  | ~~ : HikariPool-1 - Starting...
expensecalendar-backend-1  | ~~ : HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@13bdf540
expensecalendar-backend-1  | ~~ : HikariPool-1 - Start completed.

devプロファイルが使われPostgreSQLにログインできていることが確認できます。


アプリケーション起動のログ

expensecalendar-backend-1  | ~~ : Tomcat started on port 8080 (http) with context path '/'
expensecalendar-backend-1  | ~~ : Started ExpensecalendarApplication in 2.621 seconds

アプリケーションが正常に起動し、8080ポートで利用可能になります。

コンテナの停止・削除

1. コンテナの停止

実行中のコンテナを停止するには、ターミナルで Ctrl + C を押します。

2. コンテナの削除

docker compose down

停止ログ

[+] Stopping 2/2
 ✔ Container expensecalendar-expensecalendar-backend-1  Stopped     0.5s
 ✔ Container expensecalendar-db-1                       Stopped     0.5s

コンテナが停止されていることが確認できます。

削除ログ

[+] Running 3/3
✔ Container expensecalendar-expensecalendar-backend-1  Removed     0.0s
✔ Container expensecalendar-db-1                       Removed     0.0s
✔ Network expensecalendar_default                      Removed     0.6s

コンテナとネットワークが正常に削除されていることが確認できます。

まとめ

このようにDockerを使用しイメージの固定化をすることで、「自分の環境では動くが、他人の環境では動かない」という横断的関心事を解決することができます。
皆さんの参考になったら幸いです。

参考文献

本記事の執筆にあたり、以下の資料を参考にしました。

Docker/Kubernetes実践コンテナ開発入門 改訂新版

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?