正月休みで時間があったので、Spring Boot の Docker 連携機能を使ってみました。
試してみたことは次の3つです。公式ドキュメントの内容をなぞったものになっていますが、Kotlin でやるときに迷った部分があるので同じような人の助けになればと思います。
- アプリケーション起動時に MySQL コンテナを起動、接続先を自動設定
- UT 起動時に MySQL コンテナを起動、接続先を自動設定
- 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 を追加。
developmentOnly("org.springframework.boot:spring-boot-docker-compose")
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
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 公式のガイド