This workshop demonstrates how to use Docker Compose - the de facto standard for local development - to deploy a REST API application using Java Spring Boot, one of the most popular frameworks for enterprise applications.
Workshop was prepared as part of the interview process for Introduct Group LLC
Workshop materials:
By the end of this workshop you will understand and learn about:
- What is Docker Compose?
- What is Java Spring Boot and it's main features
- What kind of prerequisites are required to run Java project with Docker Compose?
- How to use Spring Boot Starter App Kit Templating tool to write your first application
- Basic Docker Compose workflow and commands
- How to write Dockerfile to dockerize your Spring Boot Application
- Modify the Compose YAML file to add your application service
- Run your entire stack with one command:
docker compose up
Docker Compose is an orchestration tool used to define and run multi-container applications. While the standard Docker CLI manages individual containers (one at a time), Docker Compose allows you to manage an entire stack of services (each packed into individual container) - such as a Java Spring Boot app, a MySQL database, and etc. - using a single YAML configuration file.
Docker Compose can work in all environments: production, staging, development, testing and CI worklfows.
For more information, see:
Docker Compose provides different CLI commands to manage the full lifecycle of your application development.
To manage the lifecycle of a Java Spring Boot application effectively, you need to understand the distinction between commands that manage the entire stack and those that target individual containers.
The following table outlines the essential Docker Compose CLI commands for local development and troubleshooting.
| Command | Lifecycle Phase | Description | Key Flag/Usage |
|---|---|---|---|
docker compose up |
Start | Creates and starts all containers defined in the YAML file. | -d (Detached mode) to run in the background. |
docker compose up --build |
Rebuild & Start | Forces a rebuild of the Dockerfile before starting. | Use this after changing Java code or Maven/Gradle dependencies. |
docker compose down |
Teardown | Stops and removes containers, networks, and images. | -v to also remove persistent volumes (data). |
docker compose stop |
Pause | Stops the containers but does not remove them. | Use this if you want to resume exactly where you left off. |
docker compose start |
Resume | Starts existing containers that were previously stopped. | Useful for a quick restart without recreating resources. |
docker compose ps |
Status | Lists the status of all services in the current stack. | Shows which containers are running, exited, or unhealthy. |
docker compose logs |
Monitor | Displays the output (STDOUT/STDERR) of your services. | -f (Follow) to stream live Spring Boot startup logs. |
docker compose exec |
Interact | Runs a command inside a specific running container. | docker compose exec db to enter the db container. |
The following is a typical workflow of using Docker Compose commands to manage application development lifecycle:
- Initialization:
docker compose up -dThis starts the DB and the Spring Boot app in the background. - Verification:
docker compose psConfirms both services are "Up" and "Healthy". - Debugging:
docker compose logs -f appWatch the Spring Boot logs to ensure the DB connection is established. - Database Inspection:
docker compose exec dbGo inside the DB container and execute SQL queries. - Clean Up:
docker compose downWipes the environment to ensure no "hanging" resources interfere with the next task.
Java Spring Boot is an open-source, "opinionated" framework built on top of the Spring Framework. Its primary goal is to simplify the process of creating standalone, production-grade Java applications.
Instead of requiring developers to manually configure every part of the application, Spring Boot uses a "Convention over Configuration" approach - it provides sensible defaults so you can start coding business logic immediately.
Spring Boot lets you create stand-alone, production-grade Spring applications with minimal configuration. You write very little (or almost no) XML/config code - just add dependencies, write your business logic, and run.
Enterprises favor Spring Boot because it addresses the complexity and scalability requirements of large-scale systems through several key pillars:
- Rapid Bootstrapping: With "Starters" (pre-configured dependency descriptors), you can add capabilities like Web, Security, or Data JPA with a single line in your build file.
- Auto Configuration: Spring Boot auto-configuration automatically configures your application context based on the JAR dependencies found in your classpath. For example, if it detects a MySQL driver, it will automatically instantiate a DataSource and set up the database connection without requiring manual XML or Java configuration.
- Embedded Servers: It includes embedded servers (Tomcat, Jetty, or Undertow) by default. You package your app as a single FAT JAR (along with app code includes external library dependencies and an embedded web server), eliminating the need for complex external application server setups.
- Production-Ready Features: It comes built-in with Spring Boot Actuator, which provides endpoints for health checks, metrics, and application info - essential for DevOps and monitoring in production.
- Microservices Support: Spring Boot is the foundation of Spring Cloud, that provides tools for developers to quickly build some of the common patterns in distributed systems that are easy to scale and containerize.
In order to run the workshop, first you have to ensure that you've installed and met the following requirements:
- Installed Java 17 or later
java -versionjavac -versionmvn -vdocker -v- Docker Compose plugin (Linux only)
docker compose version- (OPTIONAL)
ctopCLI tool to view Docker containers
The Demo Spring Boot Application provides a CRUD-based API that allows you to Create, Read, Update, and Delete user records within a MySQL database. It exposes specific REST endpoints - like /add, /all, and /delete - which act as the entry points for managing user data via standard HTTP methods.
The application code is available in separate repository: github.com/Brain2life/demo-java-springboot-app
To run the application code, first clone it into separate folder:
git clone git@github.com:Brain2life/demo-java-springboot-app.gitthen in the root of the project run:
./mvnw spring-boot:runThis will spin up the default embedded Apache Tomcat webserver, download all the required dependencies, deploy MySQL database defined in compose.yaml file as a Docker container and then run your application on http://localhost:8080
The official Spring website provides a start.spring.io web service that allows you to create the template of your Spring Boot Application with specific configuration and then download the output .zip archive.
- To manually initialize the project, go to start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you.
- Choose Maven and Java language.
- Click Dependencies and select Spring Web, Spring Data JPA, MySQL Driver, Docker Compose Support, and Testcontainers.
- Click Generate.
- Download the resulting ZIP file, which is an archive of a web application that is configured with your choices.
Caution
In our setup, our Spring Boot app is running locally on our machine by using the embedded Tomcat webserver.
However, our database is running as a Docker container and is defined in compose.yaml file as a separate service
Hence, as our next task we have to Dockerize our Spring application and run it as Docker container and run with our database container alongside
To run your Spring Boot application with Docker Compose, you need to create a Dockerfile in the root of your project. This file contains instructions on how to build a Docker image for your application.
Here's an example Dockerfile for your Spring Boot application:
# Stage 1: Build the Fat JAR
FROM eclipse-temurin:21-jdk-jammy AS build
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests # Build the application and skip tests for faster build time
# Stage 2: Run the application
FROM eclipse-temurin:21-jre-jammy
WORKDIR /app
COPY --from=build /app/target/*.jar app.ja r
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]This Dockerfile uses mutli-stage build in order to reduce the final image size. This technique is considered as one of the Docker best practices. For more information, see Docker Building Best Practices
All Java Spring Boot Applications starting from v3.1 supports Docker Compose and when initializing the project cit reates a default compose.yaml file. This file defines our application's Docker Compose config, specifically our MySQL database.
As a next step, now we have to modify Docker Compose file and add our dockerized application as a service:
services:
mysql:
image: 'mysql:8.4.7'
environment:
MYSQL_DATABASE: mydatabase
MYSQL_PASSWORD: secret # For demonstration purposes only, do not use hardcoded passwords in production
MYSQL_ROOT_PASSWORD: verysecret # For demonstration purposes only, do not use hardcoded passwords in production
MYSQL_USER: myuser
healthcheck:
# This command checks if mysql is ready to accept connections
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "myuser", "-psecret"]
interval: 5s
timeout: 5s
retries: 10
ports:
- '3306:3306'
# Java Spring Boot application service
app:
build: .
ports:
- '8080:8080'
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/mydatabase
SPRING_DATASOURCE_USERNAME: myuser # For demonstration purposes only, do not use hardcoded passwords in production
SPRING_DATASOURCE_PASSWORD: secret # For demonstration purposes only, do not use hardcoded passwords in production
depends_on:
mysql:
condition: service_healthy # Until the mysql service is healthy before starting the app serviceThere's a risk of occuring a state when our application starts early than MySQL database and tries to access the tables inside it while it is in not ready state. To avoid this, we have to ensure that our application starts after MySQL database and when it's healthy and ready to accept connections.
To achieve this we must make the following changes in our compose.yaml file for our application service:
...
depends_on:
mysql:
condition: service_healthy # Until the mysql service is healthy before starting the app serviceThe depends_on key defines the startup order of services, ensuring that a dependent container (like your Spring Boot app) begins its execution only after the specified dependency (like MySQL) has started. By adding the condition: service_healthy sub-key, you refine this behavior so the application waits until the database passes its internal healthcheck, preventing "connection refused" errors during the initial boot sequence.
For more information, see:
Now we can start our Application and MySQL database running as a Docker containers with:
docker compose upcommand.
To check our running containers:
docker compose psor
ctop- Go through the workshop from start to the end by replicating our example in a separate project folder.
- Our
compose.yamlfile has hardcoded values of environment variables and passwords, which is a not best practice and not recommended way to use in production. Modifycompose.yamlso that:- to use environment variables from file by using
env_fileattribute - use
secretsattribute to load DB database credentials from encrypted file or vault. Use open-source SOPS tool for file encryption.
- to use environment variables from file by using
- Pick any fronend framework of your choice (React, Vue, Angular etc.) or use plain HTML, CSS and develop the frontend application binded to our REST API application, dockerize it and add as a service to Docker Compose file



