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

Spring Boot + Kotlin で Docker Compose 連携と Testcontainers を使ってみた

Posted at

正月休みで時間があったので、Spring Boot の Docker 連携機能を使ってみました。
試してみたことは次の3つです。公式ドキュメントの内容をなぞったものになっていますが、Kotlin でやるときに迷った部分があるので同じような人の助けになればと思います。

  1. アプリケーション起動時に MySQL コンテナを起動、接続先を自動設定
  2. UT 起動時に MySQL コンテナを起動、接続先を自動設定
  3. UT のコンテナ設定を利用してアプリケーション起動

サンプルコード

検証環境

version
Spring Boot 3.4.1
Kotlin 1.9.25
Docker 27.4.0
mybatis-spring-boot-starter 3.0.4

1. アプリケーション起動時に MySQL コンテナを起動、接続先を自動設定

spring-boot-docker-compose

Spring Boot 3.1.0 で導入された Docker Compose との連携機能。dependency に追加して compose.yaml を書くだけで、アプリケーション起動時にコンテナを自動的に起動し、DataSource にその接続先を設定してくれます。

使い方

build.gradle.kts で dependencies に spring-boot-docker-compose を追加。

build.gradle.kts
	developmentOnly("org.springframework.boot:spring-boot-docker-compose")

compose.yaml を書く

compose.yaml
services:
  mysql:
    image: 'mysql:8.1.0'
    ports:
      - 3306
    environment:
      - 'MYSQL_ROOT_PASSWORD=passw0rd'
      - 'MYSQL_DATABASE=hoge'
    volumes:
      - './mysql/data:/var/lib/mysql'
      - './mysql/ddl:/docker-entrypoint-initdb.d'

ホスト側のポート番号は指定不要です。コンテナ起動時にランダムなポートが割り当てられますが、Spring が自動的にそのポートに接続してくれます。便利!

bootRun で起動

あとは通常通りに bootRun タスクでアプリケーションを起動すると、次のようなログが出て compose.yaml に記載したコンテナが起動します。

2025-01-11T17:25:35.263+09:00  INFO 70705 --- [demo-app] [           main] .s.b.d.c.l.DockerComposeLifecycleManager : Using Docker Compose file /Users/zzz/Documents/demo-app/compose.yaml
2025-01-11T17:25:35.593+09:00  INFO 70705 --- [demo-app] [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   :  Container demo-app-1  Created
2025-01-11T17:25:35.594+09:00  INFO 70705 --- [demo-app] [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   :  Container demo-app-1  Starting
2025-01-11T17:25:35.717+09:00  INFO 70705 --- [demo-app] [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   :  Container demo-app-1  Started
2025-01-11T17:25:35.718+09:00  INFO 70705 --- [demo-app] [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   :  Container demo-app-1  Waiting
2025-01-11T17:25:36.219+09:00  INFO 70705 --- [demo-app] [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   :  Container demo-app-1  Healthy

2. UT 起動時に MySQL コンテナを起動、接続先を自動設定

TestContainers について

コンテナを利用したテストを行うためのライブラリです。テストコードからコンテナを起動させ、それを利用して本番環境に近い構成でテストを行えます。Spring Boot でも Testcontainers 自体は以前から利用できましたが、バージョン 3.1.0 から compose.yaml と同様に接続情報の自動設定が可能になったようです。

dependency

build.gradle.kts
	testImplementation("org.springframework.boot:spring-boot-testcontainers")
	testImplementation("org.testcontainers:junit-jupiter")
	testImplementation("org.testcontainers:mysql") // Testcontainers の MySQL モジュール

UT での使い方

static なフィールド(Kotlin の場合 companion object) に起動したいコンテナを記載し、@Container@ServiceConnection アノテーションを付けるだけです。

MyBatis を使っているので @MyBatisTest ですが @SpringBootTest でも同様です。

@MybatisTest
class UserMapperTest {
    companion object {
        @Container
        @ServiceConnection
        val mySqlContainer = MySQLContainer("mysql:8.1.0")
    }

    @Test
    fun testHoge() {
      // 略
    }
}

Testcontainers には様々な Docker イメージに対応した「モジュール」が存在し、MySQL なら MySQLContainer、Oracle なら OracleContainer といったクラスが用意されています。モジュールが用意されていないイメージを利用する場合や、詳細なカスタマイズが必要な場合は汎用的なクラスとして GenericContainer が使えます。

モジュールは公式サイトで検索できます。

設定の共通化

static なフィールドで定義するため、そのままではコンテナ設定をテストクラスごとに書く必要があります。複数のテストクラスで共通化するためには object として外部に切り出し、

object MyContainers {
    @Container
    @ServiceConnection
    val mySqlContainer = MySQLContainer("mysql:8.1.0")
}

@ImportTestcontainers アノテーションでコンテナ定義をインポートします。

@MybatisTest
@ImportTestcontainers(MyContainers::class)
class UserMapperTest {
    @Test
    fun testHoge() {
      // 略
    }
}

テーブル作成

/docker-entrypoint-initdb.d にマウントできれば良いのですが、MySQLContainer でのボリュームのマウント方法がよくわからなかったので次の方法で対処。

application.properties で spring.sql.init.mode=always を指定。コンテナ起動後、 src/test/resources/schema.sql が実行されるようになります。

3. UT のコンテナ設定を利用してアプリケーション起動

Configuration クラスを作成し、UTで利用している共通設定(MyContainers)をインポート

@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(MyContainers::class)
class MyContainersConfiguration

src/test 配下に次のメイン関数を定義すると、bootTestRun タスクでアプリケーション起動が可能です。このときアプリケーション起動時には MyContainersConfiguration でインポートした MyContainers に記載したコンテナが起動します。

fun main(args: Array<String>) {
	fromApplication<DemoApplication>()
		.with(MyContainersConfiguration::class.java)
		.run(*args)
}

感想

昨年の JJUG CCC でこれらの機能を知りましたが利用経験が無かったので、とりあえず基本的なところを触ってみました。Docker Compose 連携については Docker の知識さえあればかなり簡単に使い始められますし導入のハードルは低そうです。

参考

Development-time Services :: Spring Boot
開発時のサービス :: Spring Boot - リファレンスドキュメント
Testcontainers 公式のガイド

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