Simplifying Docker Compose and Testcontainers Integration with Spring Boot 3.1

Before Spring Boot 3.1, if there were Docker containers supporting the application, we had to start the Docker containers first and then start the app.

But with Spring Boot 3.1, we can simplify this process by adding the following dependency:

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

Spring Boot 3.1 supports the following files for Docker Compose configuration:

Here's an example of a sample Docker Compose file:

      
version: '3.1'
services:
  mysql:
    image: mysql:8
    container_name: mysql-8-server
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      MYSQL_USER: root
      MYSQL_PASSWORD: root
      MYSQL_DATABASE: testdb
    ports:
      - "3308:3306"
    volumes:
      - /Users/man/mysql_data:/var/lib/mysql
    command: --default-authentication-plugin=mysql_native_password
      
    

To use a non-standard file, you can set the spring.docker.compose.file property in your application.properties or application.yaml. For example:

      
spring.docker.compose.file=../<file name>.yml
      
    

From the logs:

      
2023-06-08T13:35:13.671+01:00  INFO 63741 --- [  restartedMain] .s.b.d.c.l.DockerComposeLifecycleManager : Using

 Docker Compose file '/Users/man/workspace/test-containers-demo/compose.yaml'
2023-06-08T13:35:15.047+01:00  INFO 63741 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container mysql-8-server  Created
2023-06-08T13:35:15.049+01:00  INFO 63741 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container mysql-8-server  Starting
2023-06-08T13:35:15.736+01:00  INFO 63741 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container mysql-8-server  Started
2023-06-08T13:35:15.739+01:00  INFO 63741 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container mysql-8-server  Waiting
2023-06-08T13:35:16.243+01:00  INFO 63741 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container mysql-8-server  Healthy
      
    

Testcontainers

In addition, Spring Boot provides the capability to use Testcontainers during development. Testcontainers allows you to quickly start containers for the services your application depends on, such as database servers, eliminating the need for manual provisioning. To use Testcontainers, you can create a configuration class in the test package:

      
@Configuration
public class MySqlContainerDev {

  @Bean
  @ServiceConnection
  @RestartScope
  MySQLContainer mySQLContainer() {
    return new MySQLContainer<>(DockerImageName.parse("mysql:latest"));
  }

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

When executing MySqlContainerDev, the logs will show the container startup:

      
2023-06-08T13:39:05.145+01:00  INFO 64013 --- [  restartedMain] tc.mysql:latest                          : Creating container for image: mysql:latest
2023-06-08T13:39:05.284+01:00  INFO 64013 --- [  restartedMain] tc.mysql:latest                          : Container mysql:latest is starting: fba51ec6d16d7afaa6ec3e9405bce1703463feac56916ed358f121ce709a742b
2023-06-08T13:39:05.892+01:00  INFO 64013 --- [  restartedMain] tc.mysql:latest                          : Waiting for database connection to become available at jdbc:mysql://192.168.64.19:49239/test using query 'SELECT 1'
2023-06-08T13:39:22.265+01:00  INFO 64013 --- [  restartedMain] tc.mysql:latest                          : Container mysql:latest started in PT17.120098S
2023-

06-08T13:39:22.271+01:00  INFO 64013 --- [  restartedMain] tc.mysql:latest                          : Container mysql:latest is healthy
      
    

In the logs, tc.mysql:latest refers to the Testcontainer with the tag mysql:latest.

With the @ServiceConnection annotation, there is no need to use @DynamicPropertySource to map the Spring Boot properties.

Before Spring Boot 3.1, we needed to map the Spring Boot properties when initializing test containers. For example:

      
static {
  mysql = new MySQLContainer<>(DockerImageName.parse("mysql:8-oracle"));
  mysql.start();
}

@DynamicPropertySource
static void registerPgProperties(DynamicPropertyRegistry registry) {

  if (mysql.isCreated()) {
    registry.add("spring.datasource.url", mysql::getJdbcUrl);
    registry.add("spring.datasource.username", mysql::getUsername);
    registry.add("spring.datasource.password", mysql::getPassword);
  }
}

By using the @ServiceConnection annotation, we no longer need to use @DynamicPropertySource.
      
    

This simplifies the configuration and eliminates the need for manual mapping of properties.

The `@RestartScope` annotation part of dev tools informs Spring Boot that the container has already started, preventing it from attempting to start it again.

Overall, Spring Boot's Docker Compose support and Testcontainers simplify the management of Docker containers and their integration with your Spring Boot application.