開発時のサービス

開発時サービスは、開発中にアプリケーションを実行するために必要な外部依存関係を提供します。これらは開発中にのみ使用されることになっており、アプリケーションがデプロイされると無効になります。

Spring Boot は、Docker Compose と Testcontainers という 2 つの開発時間サービスをサポートしています。次のセクションでは、それらについて詳しく説明します。

Docker Compose サポート

Docker Compose は、アプリケーションが必要とするサービスの複数のコンテナーを定義および管理するために使用できる一般的なテクノロジです。compose.yml ファイルは通常、サービスコンテナーを定義および構成するアプリケーションの隣に作成されます。

Docker Compose の一般的なワークフローは、docker compose up を実行し、開始されたサービスに接続してアプリケーションを操作し、完了したら docker compose down を実行します。

spring-boot-docker-compose モジュールをプロジェクトに含めると、Docker Compose を使用したコンテナーの操作のサポートを提供できます。次の Maven および Gradle のリストに示すように、モジュールの依存関係をビルドに追加します。

Maven
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-docker-compose</artifactId>
		<optional>true</optional>
	</dependency>
</dependencies>
Gradle
dependencies {
	developmentOnly("org.springframework.boot:spring-boot-docker-compose")
}

このモジュールが依存関係として含まれている場合、Spring Boot は次のことを行います。

  • 作業ディレクトリで compose.yml やその他の一般的な compose ファイル名を検索します

  • 検出された compose.yml を使用して docker compose up を呼び出します

  • サポートされているコンテナーごとにサービス接続 Bean を作成する

  • アプリケーションのシャットダウン時に docker compose stop を呼び出します

アプリケーションの起動時に Docker Compose サービスがすでに実行されている場合、Spring Boot はサポートされているコンテナーごとにサービス接続 Bean のみを作成します。再び docker compose up を呼び出すことはなく、アプリケーションのシャットダウン時に docker compose stop を呼び出すこともありません。

再パッケージ化されたアーカイブには、デフォルトでは Spring Boot の Docker Compose が含まれていません。このサポートを使用する場合は、これを含める必要があります。Maven プラグインを使用する場合は、excludeDockerCompose プロパティを false に設定します。Gradle プラグインを使用する場合は、タスクのクラスパスを構成して developmentOnly 構成を含めます

前提条件

パス上に docker および docker compose (または docker-compose) CLI アプリケーションが必要です。サポートされる Docker Compose の最小バージョンは 2.2.0 です。

サービス接続

サービス接続は、任意の リモートサービスへの接続です。Spring Boot の自動構成は、サービス接続の詳細を消費し、使用して リモートサービスへの接続を確立できます。その場合、接続の詳細は、接続関連の構成プロパティよりも優先されます。

Spring Boot の Docker Compose サポートを使用する場合、コンテナーによってマップされたポートへのサービス接続が確立されます。

Docker compose は通常、コンテナー内のポートがコンピューター上の一時ポートにマップされるような方法で使用されます。例: Postgres サーバーはポート 5432 を使用してコンテナー内で実行されますが、ローカルではまったく異なるポートにマッピングされます。サービス接続は常に、ローカルにマップされたポートを検出して使用します。

サービス接続は、コンテナーのイメージ名を使用して確立されます。現在、次のサービス接続がサポートされています。

接続詳細 一致

ActiveMQConnectionDetails

"symptoma/activemq" または "apache/activemq-classic" という名前のコンテナー

ArtemisConnectionDetails

"apache/activemq-artemis" という名前のコンテナー

CassandraConnectionDetails

"cassandra" または "bitnami/cassandra" という名前のコンテナー

ElasticsearchConnectionDetails

"elasticsearch" または "bitnami/elasticsearch" という名前のコンテナー

JdbcConnectionDetails

"gvenzl/oracle-free"、"gvenzl/oracle-xe"、"mariadb"、"bitnami/mariadb"、"mssql/server"、"mysql"、"bitnami/mysql"、"postgres"、"" という名前のコンテナービットナミ / ポストグレ SQL」

LdapConnectionDetails

"osixia/openldap" という名前のコンテナー

MongoConnectionDetails

"mongo" または "bitnami/mongodb" という名前のコンテナー

Neo4jConnectionDetails

"neo4j" または "bitnami/neo4j" という名前のコンテナー

OtlpMetricsConnectionDetails

"otel/opentelemetry-collector-contrib" という名前のコンテナー

OtlpTracingConnectionDetails

"otel/opentelemetry-collector-contrib" という名前のコンテナー

PulsarConnectionDetails

"apachepulsar/pulsar" という名前のコンテナー

R2dbcConnectionDetails

"gvenzl/oracle-free"、"gvenzl/oracle-xe"、"mariadb"、"bitnami/mariadb"、"mssql/server"、"mysql"、"bitnami/mysql"、"postgres"、"" という名前のコンテナービットナミ / ポストグレ SQL」

RabbitConnectionDetails

"rabbitmq" または "bitnami/rabbitmq" という名前のコンテナー

RedisConnectionDetails

"redis" または "bitnami/redis" という名前のコンテナー

ZipkinConnectionDetails

"openzipkin/zipkin" という名前のコンテナー。

カスタム画像

サービスを提供するために、独自のバージョンのイメージを使用する必要がある場合があります。標準イメージと同じように動作する限り、任意のカスタムイメージを使用できます。具体的には、標準イメージがサポートする環境変数はカスタムイメージでも使用する必要があります。

イメージで別の名前が使用されている場合は、Spring Boot がサービス接続を提供できるように、compose.yml ファイルでラベルを使用できます。org.springframework.boot.service-connection という名前のラベルを使用してサービス名を指定します。

例:

services:
  redis:
    image: 'mycompany/mycustomredis:7.0'
    ports:
      - '6379'
    labels:
      org.springframework.boot.service-connection: redis

特定のコンテナーをスキップする

compose.yml で定義されたコンテナーイメージがアプリケーションに接続したくない場合は、ラベルを使用してそれを無視できます。org.springframework.boot.ignore というラベルが付いたコンテナーは、Spring Boot によって無視されます。

例:

services:
  redis:
    image: 'redis:7.0'
    ports:
      - '6379'
    labels:
      org.springframework.boot.ignore: true

特定の構成ファイルの使用

作成ファイルがアプリケーションと同じディレクトリにない場合、または別の名前が付けられている場合は、application.properties または application.yaml で spring.docker.compose.file を使用して別のファイルを指すことができます。プロパティは、正確なパスまたはアプリケーションに対する相対パスとして定義できます。

例:

  • プロパティ

  • YAML

spring.docker.compose.file=../my-compose.yml
spring:
  docker:
    compose:
      file: "../my-compose.yml"

コンテナーの準備が完了するまで待機

Docker Compose によって開始されたコンテナーは、完全に準備が完了するまでに時間がかかる場合があります。準備が整っているかどうかを確認する推奨方法は、compose.yml ファイルのサービス定義に healthcheck セクションを追加することです。

healthcheck 構成が compose.yml ファイルから省略されることは珍しいことではないため、Spring Boot はサービスの準備状況を直接チェックします。デフォルトでは、マップされたポートへの TCP/IP 接続を確立できる場合、コンテナーは準備完了とみなされます。

compose.yml ファイルに org.springframework.boot.readiness-check.tcp.disable ラベルを追加することで、コンテナーごとにこれを無効にできます。

例:

services:
  redis:
    image: 'redis:7.0'
    ports:
      - '6379'
    labels:
      org.springframework.boot.readiness-check.tcp.disable: true

application.properties または application.yaml ファイルでタイムアウト値を変更することもできます。

  • プロパティ

  • YAML

spring.docker.compose.readiness.tcp.connect-timeout=10s
spring.docker.compose.readiness.tcp.read-timeout=5s
spring:
  docker:
    compose:
      readiness:
        tcp:
          connect-timeout: 10s
          read-timeout: 5s

全体のタイムアウトは spring.docker.compose.readiness.timeout を使用して構成できます。

Docker Compose ライフサイクルの制御

デフォルトでは、Spring Boot はアプリケーションの起動時に docker compose up を呼び出し、シャットダウン時に docker compose stop を呼び出します。別のライフサイクル管理を使用したい場合は、spring.docker.compose.lifecycle-management プロパティを使用できます。

次の値がサポートされています。

  • none - Docker Compose を起動または停止しないでください

  • start-only - アプリケーションの起動時に Docker Compose を起動し、実行したままにします。

  • start-and-stop - アプリケーションの起動時に Docker Compose を起動し、JVM の終了時に停止します。

さらに、spring.docker.compose.start.command プロパティを使用して、docker compose up または docker compose start のどちらを使用するかを変更できます。spring.docker.compose.stop.command では、docker compose down または docker compose stop を使用するかどうかを設定できます。

次の例は、ライフサイクル管理を構成する方法を示しています。

  • プロパティ

  • YAML

spring.docker.compose.lifecycle-management=start-and-stop
spring.docker.compose.start.command=start
spring.docker.compose.stop.command=down
spring.docker.compose.stop.timeout=1m
spring:
  docker:
    compose:
      lifecycle-management: start-and-stop
      start:
        command: start
      stop:
        command: down
        timeout: 1m

Docker Compose プロファイルのアクティブ化

Docker Compose プロファイルは、特定の環境に合わせて Docker Compose 構成を調整できるという点で Spring プロファイルに似ています。特定の Docker Compose プロファイルをアクティブ化する場合は、application.properties または application.yaml ファイルで spring.docker.compose.profiles.active プロパティを使用できます。

  • プロパティ

  • YAML

spring.docker.compose.profiles.active=myprofile
spring:
  docker:
    compose:
      profiles:
        active: "myprofile"

テストでの Docker Compose の使用

デフォルトでは、テストの実行時に Spring Boot の Docker Compose サポートは無効になっています。

テストで Docker Compose サポートを有効にするには、spring.docker.compose.skip.in-tests を false に設定します。

Gradle を使用する場合は、spring-boot-docker-compose 依存関係の構成を developmentOnly から testAndDevelopmentOnly に変更する必要もあります。

Gradle
dependencies {
	testAndDevelopmentOnly("org.springframework.boot:spring-boot-docker-compose")
}

テストコンテナーのサポート

Testcontainers を統合テストに使用するだけでなく、開発時に使用することもできます。次のセクションでは、これについて詳しく説明します。

開発時のテストコンテナーの使用

このアプローチにより、開発者はアプリケーションが依存するサービスのコンテナーを迅速に起動できるため、データベースサーバーなどを手動でプロビジョニングする必要がなくなります。この方法で Testcontainers を使用すると、コンテナー構成が YAML ではなく Java であることを除いて、Docker Compose と同様の機能が提供されます。

開発時に Testcontainer を使用するには、"main" クラスパスではなく "test" クラスパスを使用してアプリケーションを起動する必要があります。これにより、宣言されたすべてのテスト依存関係にアクセスできるようになり、テスト構成を自然に記述できる場所が提供されます。

アプリケーションのテスト起動可能なバージョンを作成するには、src/test ディレクトリに "Application" クラスを作成する必要があります。例: メインアプリケーションが src/main/java/com/example/MyApplication.java にある場合は、src/test/java/com/example/TestMyApplication.java を作成する必要があります

TestMyApplication クラスは、SpringApplication.from(…​) メソッドを使用して実際のアプリケーションを起動できます。

import org.springframework.boot.SpringApplication;

public class TestMyApplication {

	public static void main(String[] args) {
		SpringApplication.from(MyApplication::main).run(args);
	}

}

アプリケーションと一緒に開始する Container インスタンスも定義する必要があります。これを行うには、spring-boot-testcontainers モジュールが test 依存関係として追加されていることを確認する必要があります。それが完了したら、開始するコンテナーの @Bean メソッドを宣言する @TestConfiguration クラスを作成できます。

ConnectionDetails Bean を作成するために、@Bean メソッドに @ServiceConnection アノテーションを付けることもできます。サポートされているテクノロジーの詳細については、「サービス接続」セクションを参照してください。

典型的な Testcontainers 構成は次のようになります。

import org.testcontainers.containers.Neo4jContainer;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

	@Bean
	@ServiceConnection
	public Neo4jContainer<?> neo4jContainer() {
		return new Neo4jContainer<>("neo4j:5");
	}

}
Container Bean のライフサイクルは、Spring Boot によって自動的に管理されます。コンテナーは自動的に起動および停止されます。
spring.testcontainers.beans.startup プロパティを使用して、コンテナーの起動方法を変更できます。デフォルトでは sequential 起動が使用されますが、複数のコンテナーを並行して起動する場合は、parallel を選択することもできます。

テスト構成を定義したら、with(…​) メソッドを使用してテストランチャーに接続できます。

import org.springframework.boot.SpringApplication;

public class TestMyApplication {

	public static void main(String[] args) {
		SpringApplication.from(MyApplication::main).with(MyContainersConfiguration.class).run(args);
	}

}

これで、通常の Java main メソッドアプリケーションと同じように TestMyApplication を起動して、アプリケーションと実行する必要のあるコンテナーを開始できるようになりました。

Maven ゴール spring-boot:test-run または Gradle タスク bootTestRun を使用して、コマンドラインからこれを行うことができます。

開発時に動的プロパティを提供する

開発時に Container@Bean メソッドから動的プロパティを提供したい場合は、DynamicPropertyRegistry を注入することで実行できます。これは、テストで使用できる @DynamicPropertySource アノテーションと同様の方法で機能します。これにより、コンテナーの起動後に使用可能になるプロパティを追加できます。

一般的な構成は次のようになります。

import org.testcontainers.containers.MongoDBContainer;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistry;

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

	@Bean
	public MongoDBContainer mongoDbContainer(DynamicPropertyRegistry properties) {
		MongoDBContainer container = new MongoDBContainer("mongo:5.0");
		properties.add("spring.data.mongodb.host", container::getHost);
		properties.add("spring.data.mongodb.port", container::getFirstMappedPort);
		return container;
	}

}
可能な限り @ServiceConnection を使用することをお勧めしますが、動的プロパティは、まだ @ServiceConnection をサポートしていないテクノロジにとって有用なフォールバックになる可能性があります。

Testcontainer 宣言クラスのインポート

Testcontainers を使用する場合の一般的なパターンは、Container インスタンスを静的フィールドとして宣言することです。多くの場合、これらのフィールドはテストクラスで直接定義されます。親クラスまたはテストが実装するインターフェース上で宣言することもできます。

例: 次の MyContainers インターフェースは、mongo コンテナーと neo4j コンテナーを宣言します。

import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;

import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

public interface MyContainers {

	@Container
	@ServiceConnection
	MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0");

	@Container
	@ServiceConnection
	Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>("neo4j:5");

}

すでにこの方法でコンテナーを定義している場合、またはこのスタイルを好む場合は、コンテナーを @Bean メソッドとして定義するのではなく、これらの宣言クラスをインポートできます。これを行うには、テスト構成クラスに @ImportTestcontainers アノテーションを追加します。

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.context.ImportTestcontainers;

@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(MyContainers.class)
public class MyContainersConfiguration {

}
サービス接続機能を使用するつもりはなく、代わりに @DynamicPropertySource を使用したい場合は、Container フィールドから @ServiceConnection アノテーションを削除します。@DynamicPropertySource アノテーション付きメソッドを宣言クラスに追加することもできます。

開発時にテストコンテナーで DevTools を使用する

devtools を使用する場合、Bean および Bean メソッドに @RestartScope のアノテーションを付けることができます。このような Bean は、devtools がアプリケーションを再起動するときに再作成されません。これは、アプリケーションの再起動にもかかわらず状態が維持されるため、Testcontainer Container Bean の場合に特に便利です。

import org.testcontainers.containers.MongoDBContainer;

import org.springframework.boot.devtools.restart.RestartScope;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

	@Bean
	@RestartScope
	@ServiceConnection
	public MongoDBContainer mongoDbContainer() {
		return new MongoDBContainer("mongo:5.0");
	}

}
Gradle を使用していてこの機能を使用したい場合は、spring-boot-devtools 依存関係の構成を developmentOnly から testAndDevelopmentOnly に変更する必要があります。デフォルトのスコープ developmentOnly では、devtools がアクティブではないため、bootTestRun タスクはコード内の変更を取得しません。