開発時のサービス

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

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 (Javadoc)

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

ArtemisConnectionDetails (Javadoc)

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

CassandraConnectionDetails (Javadoc)

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

ElasticsearchConnectionDetails (Javadoc)

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

HazelcastConnectionDetails (Javadoc)

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

JdbcConnectionDetails (Javadoc)

"clickhouse/clickhouse-server"、"bitnami/clickhouse"、"gvenzl/oracle-free"、"gvenzl/oracle-xe"、"mariadb"、"bitnami/mariadb"、"mssql/server"、"mysql"、"bitnami/mysql"、"postgres"、"bitnami/postgresql" という名前のコンテナー

LdapConnectionDetails (Javadoc)

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

MongoConnectionDetails (Javadoc)

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

Neo4jConnectionDetails (Javadoc)

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

OtlpLoggingConnectionDetails (Javadoc)

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

OtlpMetricsConnectionDetails (Javadoc)

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

OtlpTracingConnectionDetails (Javadoc)

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

PulsarConnectionDetails (Javadoc)

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

R2dbcConnectionDetails (Javadoc)

"clickhouse/clickhouse-server"、"bitnami/clickhouse"、"gvenzl/oracle-free"、"gvenzl/oracle-xe"、"mariadb"、"bitnami/mariadb"、"mssql/server"、"mysql"、"bitnami/mysql"、"postgres"、"bitnami/postgresql" という名前のコンテナー

RabbitConnectionDetails (Javadoc)

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

RedisConnectionDetails (Javadoc)

"redis"、"bitnami/redis"、"redis/redis-stack"、"redis/redis-stack-server" という名前のコンテナー

ZipkinConnectionDetails (Javadoc)

"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 (Javadoc) メソッドを宣言する @TestConfiguration (Javadoc) クラスを作成できます。

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

典型的な 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 (Javadoc) メソッドから動的プロパティを提供する場合は、追加の DynamicPropertyRegistrar (Javadoc) Bean を定義します。レジストラは、プロパティのソースとなるコンテナーをパラメーターとして挿入する @Bean (Javadoc) メソッドを使用して定義する必要があります。この配置により、プロパティが使用される前にコンテナーが起動していることが保証されます。

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

import org.testcontainers.containers.MongoDBContainer;

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

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

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

	@Bean
	public DynamicPropertyRegistrar mongoDbProperties(MongoDBContainer container) {
		return (properties) -> {
			properties.add("spring.data.mongodb.host", container::getHost);
			properties.add("spring.data.mongodb.port", container::getFirstMappedPort);
		};
	}

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

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 (Javadoc) メソッドとして定義するのではなく、これらの宣言クラスをインポートできます。これを行うには、テスト構成クラスに @ImportTestcontainers (Javadoc) アノテーションを追加します。

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 (Javadoc) アノテーションを削除します。宣言クラスに @DynamicPropertySource (Javadoc) アノテーション付きメソッドを追加することもできます。

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

devtools を使用する場合、Bean と Bean メソッドに @RestartScope (Javadoc) のアノテーションを付けることができます。このような 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 タスクはコード内の変更を取得しません。