spring-boot-docker-compose を使ってPostgreSQLを自動起動＆初期化【CI/CD】

## はじめに

SpringBoot起動時に、Dockerコンテナを自動で立ててくれる`spring-boot-docker-compose`を紹介します。


## この記事でできること

SpringBootプロジェクトで、アプリ起動時にdocker-composeでPostgreSQLを起動し、初期化SQL（DDL/DML）も自動実行、CI/CDでも自動化できる構成にする。

## 1.`spring-boot-docker-compose`の依存関係を追加

`pom.xml`または`build.gradle`に依存関係を追加します。

```xml:pom.xml
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-docker-compose</artifactId>
		<optional>true</optional>
	</dependency>
</dependencies>
```

```gradle:build.gradle
dependencies {
	developmentOnly 'org.springframework.boot:spring-boot-docker-compose'
}
```

## 2.docker-compose.yml を用意

プロジェクトルートに`docker-compose.yml`を作成します。

```yml:docker-compose.yml
version: '3.8'
services:
  db:
    image: postgres:15
    container_name: postgres_local
    restart: always
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./sql:/docker-entrypoint-initdb.d

volumes:
  postgres_data:
```

ファイル名については`compose.yml`でもOKでした。
それ以外のファイル名に関しては、application.ymlに明記する必要があります。

```yml:application.yml
spring:
  docker:
    compose:
      file: ../my-compose.yml
```

パスは絶対パスかプロジェクトルートからの相対パスにします。

## 3.init.sql に DDL/DML を書く

DBのテーブル作成や初期データ投入を自動化するために、init.sql を用意します。
この辺りは通常のDockerと変わりません。

```sql:sql/init.sql
CREATE TABLE IF NOT EXISTS movies (
  id SERIAL PRIMARY KEY,
  title VARCHAR(255) NOT NULL
);

INSERT INTO movies (title) VALUES
  ('The Phantom Menace'),
  ('Attack of the Clones'),
  ('Revenge of the Sith'),
  ('A New Hope'),
  ('The Empire Strikes Back'),
  ('Return of the Jedi'),
  ('The Force Awakens'),
  ('The Last Jedi'),
  ('The Rise of Skywalker');
```

## ４.application.yml

```yml:application.yml
spring:
  application:
    name: spring-docker
  docker:
    compose:
      file: ./my-compose.yml
      skip:
        in-tests: false
```

本来であればDataSource周りの設定が必要ですが、卒属先をDockerコンテナ上のデータベースにするのであれば、設定は不要です。
`spring-boot-docker-compose`がよしなにやってくれるみたいです。

## おまけ. GitHub Actions

GitHub Actionsを用いたCIに関しても以下のようにシンプルに設定できます。

```yml:action.yml
name: CI

on:
  push:
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup JDK
        uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: 21

      - name: Run tests
        run: ./gradlew test

```

## Springを起動してみる

起動前はもちろん、dockerコンテナ、イメージともに存在していません。

```sh
% docker ps -a 
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
```

Springを起動させると

```log
2025-04-22 21:24:39 [INFO] -  db Pulling 

〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 中略 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜

2025-04-22 21:24:50 [INFO] -  56134e0541ae Pull complete 
2025-04-22 21:24:50 [INFO] -  db Pulled 
2025-04-22 21:24:50 [INFO] -  Network spring-docker_default  Creating
2025-04-22 21:24:50 [INFO] -  Network spring-docker_default  Created
2025-04-22 21:24:50 [INFO] -  Volume "spring-docker_postgres_data"  Creating
2025-04-22 21:24:50 [INFO] -  Volume "spring-docker_postgres_data"  Created
2025-04-22 21:24:50 [INFO] -  Container postgres_local  Creating
2025-04-22 21:24:50 [INFO] -  Container postgres_local  Created
2025-04-22 21:24:50 [INFO] -  Container postgres_local  Starting
2025-04-22 21:24:50 [INFO] -  Container postgres_local  Started
2025-04-22 21:24:50 [INFO] -  Container postgres_local  Waiting
2025-04-22 21:24:51 [INFO] -  Container postgres_local  Healthy
2025-04-22 21:24:51 [INFO] - Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
2025-04-22 21:24:51 [INFO] - Finished Spring Data repository scanning in 5 ms. Found 0 JDBC repository interfaces.
```

という具合に、通常の起動時の処理に加えて、コンテナの立ち上げ等を行ってくれます。
コンテナの様子も確認します。

```sh
% docker ps -a 
CONTAINER ID   IMAGE         COMMAND                   CREATED         STATUS         PORTS                    NAMES
76401f1dce10   postgres:15   "docker-entrypoint.s…"   5 minutes ago   Up 5 minutes   0.0.0.0:5432->5432/tcp   postgres_local
```

成功しているみたいです！

## ついでにGitHubActionsも

DBとの接続が必要なテストケースをいくつか作成し、GitHubActionsで`./gradlew test`を走らせてみました。

```log

Starting a Gradle Daemon (subsequent builds will be faster)
> Task :compileJava
> Task :processResources
> Task :classes
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test

BUILD SUCCESSFUL in 1m 11s
4 actionable tasks: 4 executed
```

こちらもうまくいっていそうです！

## 最後に

今回は、application.ymlに最小限の記載しかしませんでした。
実際には本番のDBをコンテナ上には置かないと思うので、プロファイルでの書き換え等必要かなと思います！