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 up
Code language: Java (java)
Stopping the servicess
docker-compose down
Code 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
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 discoveredcompose.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 Details | Matched on |
---|---|
CassandraConnectionDetails | Containers named “cassandra” |
ElasticsearchConnectionDetails | Containers named “elasticsearch” |
JdbcConnectionDetails | Containers named “gvenzl/oracle-xe”, “mariadb”, “mssql/server”, “mysql”, or “postgres” |
MongoConnectionDetails | Containers named “mongo” |
R2dbcConnectionDetails | Containers named “gvenzl/oracle-xe”, “mariadb”, “mssql/server”, “mysql”, or “postgres” |
RabbitConnectionDetails | Containers named “rabbitmq” |
RedisConnectionDetails | Containers named “redis” |
ZipkinConnectionDetails | Containers 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: postgres
Code 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=dev
Code language: Java (java)
You can download the source code this blog post from GitHub