0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

この記事では、Docker Compose を利用した Spring Boot / PostgreSQL の開発環境構築手順について記載します。

開発環境

開発環境は以下の通りです。

  • Windows 11
  • Docker Engine 29.4.0
  • Docker Compose 5.1.4
  • PostgreSQL 18.4
  • Java (JDK) 25
  • Spring Boot 4.1.0
  • Spring Framework 7.0.7
  • Maven 3

Spring Boot プロジェクトの作成

まずは Spring Boot プロジェクトを用意します。

Spring Initializr でプロジェクト生成

Spring Initializr を使用してプロジェクトを生成します。

設定は以下の通りです。

  • Project: Maven
  • Language: Java
  • Spring Boot: 4.1.0
  • Java: 25
  • Dependencies:
    • Spring Web
    • Spring Data JPA
    • PostgreSQL Driver

生成されたZIPを解凍すると、以下のような構成になります。

spring-postgres-crud/
├── src/
│   └── main/
│       ├── java/com/example/spring-postgres-crud/
│       │   └── SpringPostgresCrudApplication.java
│       └── resources/
│           └── application.properties
├── mvnw
├── mvnw.cmd
└── pom.xml

pom.xml の確認

生成された pom.xml は以下の通りです。

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>4.1.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>spring-postgres-crud</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name/>
	<description/>
	<url/>
	<licenses>
		<license/>
	</licenses>
	<developers>
		<developer/>
	</developers>
	<scm>
		<connection/>
		<developerConnection/>
		<tag/>
		<url/>
	</scm>
	<properties>
		<java.version>25</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webmvc</artifactId>
		</dependency>

		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webmvc-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

ソースコードの実装

エンティティの作成

users テーブルに対応するエンティティクラスを作成します。

src/main/java/com/example/spring-postgres-crud/User.java
package com.example.spring_postgres_crud;

import jakarta.persistence.*;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 32)
    private String name;

    @Column(nullable = false, unique = true, length = 32)
    private String email;

    // Constructors
    public User() {}
    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    // Getters and Setters
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
}

リポジトリの作成

Spring Data JPA の JpaRepository を継承したリポジトリインターフェースを作成します。

src/main/java/com/example/spring-postgres-crud/UserRepository.java
package com.example.spring_postgres_crud;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    
}

コントローラーの作成

ユーザー一覧を返すエンドポイントを実装します。

src/main/java/com/example/spring-postgres-crud/UserController.java
package com.example.spring_postgres_crud;

import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/users")
public class UserController {
    private final UserRepository userRepository;

    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @GetMapping
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
}

Docker 設定

アプリケーションコンテナとデータベースコンテナを定義します。

Dockerfile の作成

Spring Boot アプリのイメージをビルドするための Dockerfile を作成します。
マルチステージビルドを使って最終イメージを軽量に保ちます。

Dockerfile
# ---- Build Stage ----
FROM eclipse-temurin:25-jdk-alpine AS builder

WORKDIR /app

COPY mvnw mvnw
COPY .mvn .mvn
COPY pom.xml ./
COPY src src

RUN chmod +x mvnw && ./mvnw package -DskipTests --no-transfer-progress

# ---- Run Stage ----
FROM eclipse-temurin:25-jre-alpine

WORKDIR /app

COPY --from=builder /app/target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

eclipse-temurin は Eclipse Foundation が提供する OpenJDK の公式ディストリビューションです。
alpine ベースを使用することで最終イメージを軽量化しています。
-DskipTests オプションを指定することで、イメージビルド時のテスト実行をスキップしています。

DB 初期データの作成

DBコンテナ起動時に実行する初期 SQL ファイルを用意します。

db/init-users.sql
CREATE TABLE IF NOT EXISTS users (
    id    SERIAL       PRIMARY KEY,
    name  VARCHAR(32)  NOT NULL,
    email VARCHAR(32)  NOT NULL
);

INSERT INTO users (name, email) VALUES ('Wyatt', 'wyatt@example.com');
INSERT INTO users (name, email) VALUES ('Billy', 'billy@example.com');

compose.yaml の作成

以下の要件を満たす compose.yaml を作成します。

  • Spring Boot
    • コンテナ名:app-container
    • ビルド:Dockerfile
    • ポート:8080
    • ソースコード:ホストマシンで実装
  • PostgreSQL
    • コンテナ名:db-container
    • イメージ:PostgreSQL 公式イメージ 18.4-alpine
    • ポート:5432
    • 初期データを用意
    • データはコンテナを削除しても残す
    • ホストマシンからDB接続可能
  • コンテナ間通信可能
  • AppコンテナはDBコンテナの起動完了を待ってから起動する

サービス・コンテナ名

各コンテナのサービスとコンテナ名を定義します。

compose.yaml
services:
  app:
    container_name: "app-container"
  db:
    container_name: "db-container"

ボリューム

PostgreSQL のデータをコンテナ削除後も保持するため、DBコンテナ用のボリュームを定義します。
services と同じ階層に定義します。

compose.yaml
services:
  ...
volumes:
  db-volume:

ビルド・イメージ

AppコンテナはDockerfileから、DBコンテナは公式イメージからビルドするように定義します。

compose.yaml
services:
  app:
    ...
    build: . # Dockerfile path
  db:
    ...
    image: postgres:18.4-alpine
...

ポート

公開するポートを定義します。

compose.yaml
services:
  app:
    ...
    ports:
      - "8080:8080"
  db:
    ...
    ports:
      - "5432:5432"
...

バインドマウント

DBコンテナの初期データ作成ファイルをバインドマウントします。

compose.yaml
services:
  ...
  db:
    ...
    volumes:
      - type: bind
        source: ./db
        target: /docker-entrypoint-initdb.d
...

初期データ作成ファイルのマウント先 /docker-entrypoint-initdb.d は、Docker Hub の PostgreSQL リポジトリの Initializing a fresh instance セクションに記載があります。1

ボリュームマウント

データをコンテナ削除後も保持できるようにDBボリュームをDBコンテナにマウントします。

compose.yaml
services:
  ...
  db:
    ...
    volumes:
      ...
      - type: volume
        source: db-volume
        target: /var/lib/postgresql
volumes:
  db-volume:

マウント先の /var/lib/postgresql/data は、PostgreSQL サーバーがデータを保存するデフォルトのディレクトリです。

環境変数

DB接続情報を環境変数として定義します。
AppコンテナとDBコンテナの両方に設定することで、コンテナ間通信とホストマシンからの接続を可能にします。

compose.yaml
services:
  app:
    ...
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/sampledb
      SPRING_DATASOURCE_USERNAME: user
      SPRING_DATASOURCE_PASSWORD: userpassword
      SPRING_JPA_HIBERNATE_DDL_AUTO: none
  db:
    ...
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: userpassword
      POSTGRES_DB: sampledb

SPRING_DATASOURCE_URL のホスト部分に db を指定することで、Docker Compose のサービス名を使ったコンテナ間通信が可能になります。

ヘルスチェックと起動順序の制御

DBコンテナの起動完了を待ってからAppコンテナを起動するよう、healthcheck と depends_on を設定します。

compose.yaml
services:
  app:
    ...
    depends_on:
      db:
        condition: service_healthy
  db:
    ...
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d sampledb"]
      interval: 10s
      timeout: 5s
      retries: 5
...

depends_on に condition: service_healthy を指定することで、DBコンテナの healthcheck が通過するまでAppコンテナの起動を待機します。
単純な depends_on: db ではコンテナの起動順序しか制御できず、PostgreSQLの初期化完了を保証できないため注意が必要です。

完成

完成した compose.yaml は以下の通りです。

compose.yaml
services:
  app:
    container_name: "app-container"
    build: . # Dockerfile path
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/sampledb
      SPRING_DATASOURCE_USERNAME: user
      SPRING_DATASOURCE_PASSWORD: userpassword
      SPRING_JPA_HIBERNATE_DDL_AUTO: none
    depends_on:
      db:
        condition: service_healthy
  db:
    container_name: "db-container"
    image: postgres:18.4-alpine
    ports:
      - "5432:5432"
    volumes:
      - type: bind
        source: ./db
        target: /docker-entrypoint-initdb.d
      - type: volume
        source: db-volume
        target: /var/lib/postgresql
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: userpassword
      POSTGRES_DB: sampledb
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d sampledb"]
      interval: 10s
      timeout: 5s
      retries: 5
volumes:
  db-volume:

application.properties の設定

src/main/resources/application.properties にDB接続情報を設定します。
コンテナ起動時は Docker Compose の環境変数が優先されますが、ローカル実行時のデフォルト値として記載しておきます。

src/main/resources/application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/sampledb
spring.datasource.username=user
spring.datasource.password=userpassword
spring.jpa.hibernate.ddl-auto=none

spring.jpa.hibernate.ddl-auto=none を指定することで、Hibernate によるテーブルの自動生成・更新を無効化し、db/init-users.sql で作成したテーブル定義を維持します。

ディレクトリ構成

ここまでの作業で、プロジェクトのディレクトリ構成は以下の通りになります。

spring-postgres-crud/
├── db/
│   └── init-users.sql
├── src/
│   └── main/
│       ├── java/com/example/spring_postgres_crud/
│       │   ├── SpringPostgresCrudApplication.java
│       │   ├── User.java
│       │   ├── UserRepository.java
│       │   └── UserController.java
│       └── resources/
│           └── application.properties
├── compose.yaml
├── Dockerfile
├── mvnw
├── mvnw.cmd
└── pom.xml

動作確認

コンテナを起動します。

docker compose up --build

DBコンテナのヘルスチェック通過後にAppコンテナが起動し、以下のようなログが出力されます。

db-container  | 2026-06-20 05:38:14.933 UTC [1] LOG:  database system is ready to accept connections
Container db-container Healthy
app-container  | 
app-container  |   .   ____          _            __ _ _
app-container  |  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
app-container  | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
app-container  |  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
app-container  |   '  |____| .__|_| |_|_| |_\__, | / / / /
app-container  |  =========|_|==============|___/=/_/_/_/
app-container  | 
app-container  |  :: Spring Boot ::                (v4.1.0)
app-container  | 
app-container  | 2026-06-20T05:38:25.386Z  INFO 1 --- [spring-postgres-crud] [           main] c.e.s.SpringPostgresCrudApplication      : Starting SpringPostgresCrudApplication v0.0.1-SNAPSHOT using Java 25.0.3 with PID 1 (/app/app.jar started by root in /app)

コンテナ一覧を確認します。

docker container ls

compose.yaml で定義した名前通りのコンテナが作成されています。

CONTAINER ID   IMAGE                      COMMAND                   CREATED         STATUS                   PORTS                                NAMES
83e9ac60ec4f   spring-postgres-crud-app   "java -jar app.jar"       2 minutes ago   Up 2 minutes             0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp   app-container
be9bfb2103dc   postgres:18.4-alpine       "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes (healthy)   0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp   db-container

API エンドポイントにアクセスして、初期データが返ることを確認します。

curl http://localhost:8080/users

初期データとして挿入したユーザーが返ります。

[
    {"name":"Wyatt","email":"wyatt@example.com","id":1},  
    {"name":"Billy","email":"billy@example.com","id":2}
]

PostgreSQL に直接接続して確認することもできます。

docker exec -it db-container psql -U user -d sampledb
sampledb=# select * from users;
 id | name  |       email
----+-------+-------------------
  1 | Wyatt | wyatt@example.com
  2 | Billy | billy@example.com
(2 rows)

参考

  1. https://hub.docker.com/_/postgres ↩

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?