DevContainers Support with Docker Compose in SpringBoot 3.1

In this blog post we will see how we can use docker containers during development time using docker compose files in Spring Boot 3.1 which simplifies the development and testing efforts by providing infrastructure.

In my previous blog posts (part-1, part-2), I have already shown how can we use docker containers during development for testing applications.

In Spring Boot 3.1, framework has support for containers during development time either using docker-compose file or Testcontainers.

In this blog post we will see the dev containers support with docker compose module in Spring Boot application.

If you are using docker compose file to provision infrastructure like database or Message queue with earlier spring boot version, you had to manually start the services from docker compose file before starting your application and stopping once application is tested with following command.

Starting docker compose services

docker-compose upCode language: Java (java)

Stopping the servicess

docker-compose downCode language: Java (java)

Docker Compose Support

Starting with version 3.1, Spring Boot framework comes with new module called, “spring-boot-docker-compose” . It provides integration with Docker Compose file

If you want to use the docker compose module, add the following dependency in your pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-docker-compose</artifactId>
</dependency>Code language: Java (java)

and place docker compose file in project root folder.

Note

As of writing this blog post “spring-boot-docker-compose” module is not available in start.spring.io , so you need to add it manually.
The docker compose or docker-compose CLI application needs to be on your path in order for Spring Boot’s support to work correctly.

docker compose file could be named as one of the following.

  • compose.yaml
  • compose.yml
  • docker-compose.yaml
  • docker-compose.yml

spring -docker-compose module adds the support to start and stop services from docker compose when spring boot application starts and stops automatically.

When docker compose modules is included as a dependency Spring Boot will do the following:

  • Search for a compose.yml and other common compose filenames in your application directory
  • Call docker compose up with the discovered compose.yml
  • Create service connection beans for each supported container
  • Call docker compose down when the application is shutdown

If you are starting database with compose file

In below startup logs , you can see that, spring boot docker module recognized the presence of compose file and started service defined in it.

  INFO 20780 --- [           main] .s.b.d.c.l.DockerComposeLifecycleManager : Found docker compose file 'D:\IdeaProjects\springboot3-dev-containers\docker-compose.yml'
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Network springboot3-dev-containers_default  Creating
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Network springboot3-dev-containers_default  Created
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container springboot3-dev-containers-postgres-1  Creating
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container springboot3-dev-containers-postgres-1  Created
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container springboot3-dev-containers-postgres-1  Starting
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container springboot3-dev-containers-postgres-1  Started
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container springboot3-dev-containers-postgres-1  Waiting
  INFO 20780 --- [utReader-stderr] o.s.boot.docker.compose.core.DockerCli   : Container springboot3-dev-containers-postgres-1  Healthy
Code language: Java (java)

Service Connections

Service Connections is new mechanism introduced in Spring Boot 3.1

A service connection is a connection to any remote service such as database, Message Queue, Elastic Search or Cache Service.

Spring Boot’s auto-configuration can read the details of a service connection and use them to establish a connection to a remote service.

If you start a database service using docker compose file, service connection can read username,password and url of the database and use those details to connect to database from spring boot project. i.e No need to define those properties in the application.properties file

Spring Boot gives higher preference to service connection details than any connection-related configuration properties.

i.e. If Database connection details are configured in application.properties, and if you are using docker-compose module then environment variables (which form connection information) defined in docker compose file take precedence.

ServiceConnection feature is supported by limited no of services at the moment.

Service connections are established by using the image name of the container. The following service connections are currently supported:

Connection DetailsMatched on
CassandraConnectionDetailsContainers named “cassandra”
ElasticsearchConnectionDetailsContainers named “elasticsearch”
JdbcConnectionDetailsContainers named “gvenzl/oracle-xe”, “mariadb”, “mssql/server”, “mysql”, or “postgres”
MongoConnectionDetailsContainers named “mongo”
R2dbcConnectionDetailsContainers named “gvenzl/oracle-xe”, “mariadb”, “mssql/server”, “mysql”, or “postgres”
RabbitConnectionDetailsContainers named “rabbitmq”
RedisConnectionDetailsContainers named “redis”
ZipkinConnectionDetailsContainers named “openzipkin/zipkin”.

Using Custom Images

Sometimes you may need to use your own version of an image to provide a service. Any custom image can be used as long as it performs the same as the standard image. Any environment variables supported by the standard image must be used in your custom image as well.

If your image uses a different name, you can add a label in your docker compose file to allow Spring Boot to provide a service connection. Use a label named org.springframework.boot.service-connection to provide the service name.

services:
  postgres:
    image: 'mydatabase/mypostgres:13.2'
    ports:
      - '5432'
    labels:
      org.springframework.boot.service-connection: postgresCode language: Java (java)

Skipping Specific Containers

If you have a container image defined in your docker compose file that you don’t want connected to your application you can ignore it using label. Spring Boot will ignore any container labelled with org.springframework.boot.ignore.

This feature very useful when you have more than service defined in your docker compose but you want to run selected service during application run, then label all unwanted services with ignore.

services:
  redis:
    image: 'postgres:13.2'
    ports:
      - 5432:5432
    labels:
      org.springframework.boot.ignore: true
Code language: Java (java)

Using a Specific Compose File

If your docker compose file not in the root of the project or its named differently than default recognized file names, you can use spring.docker.compose.file in your application.properties or application.yaml to point to a different file. Properties can be defined as an exact path or a path that’s relative to your application.

spring.docker.compose.file=./local-dev/docker-compose.yml
Code language: Java (java)

Waiting for Container Readiness

Containers started by Docker Compose may take some time to become fully ready. The recommended way of determining readiness is to add a healthcheck section in your docker compose file under the service definition.

Because it is common for healthcheck configuration to be omitted from compose.yml files, Spring Boot also checks for service readiness directly. A container is deemed ready by default when a TCP/IP connection to its mapped port can be established.

You may deactivate it per container by adding an org.springframework.boot.readiness-check.tcp.disable label to your compose.yml file.

services:
  redis:
    image: 'postgres:13.2'
    ports:
      - '5432'
    labels:
      org.springframework.boot.readiness-check.tcp.disable: true
Code language: Java (java)

You can also define timeout values in your application.properties or application.yaml file:

spring.docker.compose.readiness.tcp.connect-timeout=10s
spring.docker.compose.readiness.tcp.read-timeout=5s
Code language: Java (java)

Controlling the Docker Compose Lifecycle

By default Spring Boot calls docker compose up when your application starts and docker compose down when it’s shutdown. If you prefer to have different lifecycle management you can use the spring.docker.compose.lifecycle-management property.

The following values are supported:

  • none – Do not start or stop Docker Compose
  • start-only – Start Docker Compose on application startup and leave it running
  • start-and-stop – Start Docker Compose on application startup and stop it on application shutdown

In addition you can use the spring.docker.compose.startup.command property to change if docker up or docker start is used. The spring.docker.compose.shutdown.command allows you to configure if docker down or docker stop is used.

The following example shows how lifecycle management can be configured:

spring.docker.compose.lifecycle-management=start-and-stop
spring.docker.compose.startup.command=start
spring.docker.compose.shutdown.command=stop
spring.docker.compose.shutdown.timeout=1m
Code language: Java (java)

Using Docker Compose Profiles

Docker Compose profiles are similar to Spring profiles in that they let you adjust your Docker Compose configuration for specific environments. If you want to activate a specific Docker Compose profile you can use the spring.docker.compose.profiles.active property in your application.properties or application.yaml file:

spring.docker.compose.profiles.active=devCode language: Java (java)

You can download the source code this blog post from GitHub

Similar Posts