Introduction

Docker has revolutionized application deployment by enabling developers to package applications and their dependencies into portable containers. In this comprehensive guide, we’ll explore how to dockerize a Spring Boot application with MySQL, leveraging the power of Docker and Docker Compose. By containerizing your Spring Boot application, you can achieve easy deployment, improved portability, scalability, and version control.

The YouTube Channels in both English (En) and French (Fr) are now accessible, feel free to subscribe by clicking here.

What is Docker Compose?

Docker Compose stands as an indispensable tool. This extension of Docker offers the ability to define and manage multi-container applications using simple configuration files written in YAML. Instead of manually managing each container individually, Docker Compose allows the declaration of services, networks, and volumes within a single file, significantly simplifying the deployment process.

Why use Docker Compose?

Docker Compose presents several significant advantages in the deployment and management of multi-container applications. Here are some of these benefits:

  • Simplicity of Configuration: Docker Compose uses simple YAML configuration files to define the structure of applications. This approach makes the configuration and management of services, networks, and volumes easier.
  • Facilitated Orchestration: With Docker Compose, it becomes easy to declare and coordinate multiple services and containers within a single application. This simplifies the orchestration of interconnected components.
  • Rapid Deployment: Using a single configuration file, Docker Compose provides an efficient method to quickly deploy applications with all their necessary components. This speeds up the development and testing process.
  • Environment Isolation: Docker Compose configuration files can be tailored for different environments such as development, production, or testing. This allows effective isolation of settings and configurations specific to each phase of an application’s lifecycle.

To follow this guide, ensure you have the following prerequisites:

  • Docker installed on your machine, this guide could help.
  • Java Development Kit (JDK) 17 installed, recent versions could work.
  • Maven or Gradle build tool installed.

Create a Spring Boot Application

Before proceeding, let’s create a basic Spring Boot App with the latest stable release at the time of writing, which is version 3.1.2.

It involves accessing the initializer service at https://start.spring.io, providing some basic details regarding the App, selecting the required dependencies then hitting on the GENERATE button to have the basic structure of the project as follows:

Dockerize Spring Boot and MySQL with Docker Compose
Spring Boot Initializer

You can quickly determine the following dependencies that come packaged in the Maven project:

  • Spring Data JPA: Persist data in SQL stores with Java Persistence API using Spring Data and Hibernate.
  • Spring Web: Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.
  • MySQL Driver: MySQL JDBC driver.

Open the generated project in your favorite IDE or editor (I’m mainly using IntelliJ IDEA and VsCode), from there you can tweak it a bit to have some entities, controllers, and business logic.

Hosted on GitHub, here’s the source code of the Spring Boot application that we’ll be using to set up Docker along with a MySQL database.

The application.properties file holds some App configurations, it’s not uncommon to see sensitive credentials in it, here’s its content:

# Server port
server.port=8090

# Datasource connection
spring.datasource.platform=mysql
spring.datasource.initialization-mode=always
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect

# Hibernate
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.show-sql=true

# Logging
logging.level.org.springframework=ERROR
logging.level.com.numericaideas=DEBUG
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

Let’s build the App to make sure it compiles as expected, the following command must be run from the project root folder:

./mvnw clean install -DskipTests

At the end of the execution, the Maven build output should look like this:

Dockerize Spring Boot and MySQL with Docker Compose
Maven build

Other Bash scripts are available within the project for convenience:

  • build.sh: to build the project.
  • up.sh: to start the project using Docker Compose.
  • down.sh: to shut everything down.

For our demo, the port in use is 8090 and we have implemented the CRUD operations for the User entity as well as a Ping endpoint, we won’t go deeper on that since it’s out of scope and you can follow the next sections of this guide with an existing Spring Boot (Maven) project too.

Create Docker Image for Spring Boot Application

The Dockerfile should be provided to build an image of the Spring Boot Application, it contains the following lines:

# Use a base image with Java 17
FROM openjdk:17

# Copy the JAR package into the image
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar

# Expose the application port
EXPOSE 8090

# Run the App
ENTRYPOINT ["java", "-jar", "/app.jar"]

It’s straightforward, the Dockerfile uses an image based on Java 17, it copies into the image the executable JAR file that resulted from the build in the previous step, exposes the port the App is running on, and then provides the entry point which is the bash command to run at the end to start the container.

By building your image with the command docker build ., a successful output should be similar to the next image:

Dockerize Spring Boot and MySQL with Docker Compose
Build Spring Boot Docker image

By this stage, we have the App image and since we’ll use the official MySQL Docker image, we can manually spin up both components and link them together by using the database credentials to run the App, but to make the process easier we’ll link their deployments together by using Docker Compose in the next section.

Docker Compose Spring Boot and MySQL

Docker Compose simplifies the orchestration of multi-container applications. Create a file named docker-compose.yml in your project directory and add the following configuration:

version: '3.7'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 8090:8090
    depends_on:
      mysqldb:
        condition: service_healthy
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysqldb:3306/${MYSQL_DATABASE}
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD}
    networks:
      - springboot-mysql-network
  mysqldb:
    image: mysql:8.0.33
    ports:
      - 3306:3306
    environment:
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - springboot-mysql-network
    healthcheck:
      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
      retries: 10
      interval: 3s
      timeout: 30s
volumes:
  mysql-data:
networks:
  springboot-mysql-network:
    name: springboot-mysql-network

Here’s what happens when Docker Compose processes these configurations:

  • This Docker Compose configuration defines two services: app for the NodeJS Application and mysqldb for the MySQL database.
  • The app service builds the image based on the Dockerfile in the project’s root directory.
  • The mysqldb service uses the official MySQL image and sets the environment variables for the database configuration.
  • The depends_on attribute ensures that the NodeJS application starts after the MySQL database to guarantee dependency ordering.
  • Finally, the healthcheck makes sure the MySQL service is ready to accept connections before running the App.

For the App to connect itself to the MySQL database, as an enhanced security measure, we provided the database credentials as environment variables to the MySQL services’ environment attributes so these are hidden from the project source code:

  • MYSQL_DATABASE: The database name.
  • MYSQL_PASSWORD: The database root’s password, we use the root user account for simplicity only.

The environment attributes present in the app service are provided as environment variables to the App container at run time, we are talking about:

  • SPRING_DATASOURCE_URL: It contains the DB Host which is addressable via the mysqldb service name since both services are in the same network. The DB name and port are included in this string too.
  • SPRING_DATASOURCE_USERNAME: The username to access the DB with.
  • SPRING_DATASOURCE_PASSWORD: The password to access the DB with.

Spring Boot automatically assigns these variables to the related application.properties configurations listed below:

  • spring.datasource.url
  • spring.datasource.username
  • spring.datasource.password

This means we don’t have to provide these manually in the application.properties file, so the App will be connected to the database.

Run the Dockerized Spring Boot Application With MySQL

To run the App via Docker Compose, open a terminal, navigate to the project’s root directory, and execute the following command in which we provide the environment variables directly:

MYSQL_DATABASE=mydatabase MYSQL_PASSWORD=rootpassword docker-compose up

In case you would like to provide the environment variables from a hidden .env file, feel free to create it from the .env.sample file and put it close to the docker-compose.yml within the project. In case these files are in different locations, you must use the env_file field in the mysqldb service to specify the folder to access the .env file.

This being done, the command to run will change a bit to the following:

docker-compose up

Docker Compose will build the Spring Boot and MySQL images, create the containers, create the network, and start them all. You’ll see logs from both the application and the database. To stop the containers, press Ctrl+C.

Using Docker Desktop enables you to view a nice summary of your Docker state in which we can see our running containers as illustrated below:

running-containers
Running containers on Docker Desktop

The complete source code of the project is available on GitHub.

Open POSTMAN and create a POST request to the URL localhost:8090/api/users with a random user object to be persisted in the DB:

create-user
Test API: create a user

Let’s list all users which includes the one we just created:

list-users
Test API: list all users

Stop Docker Compose Services

To stop all the running containers, run:

docker compose down

Here’s the exact command to stop and remove everything created by Docker Compose, talking about the containers, images, and networks:

docker compose down --rmi all

Other Docker Compose Examples

Do you want to apply the same with a Spring Boot Application? Read this article titled Dockerize NodeJS and MySQL with Docker Compose:

If you are interested in related content, take a look at the following which explains how to Quickly Dockerizing NodeJS Application using the Docker Init Command:

———————

We have just started our journey to build a network of professionals to grow even more our free knowledge-sharing community that’ll give you a chance to learn interesting things about topics like cloud computing, software development, and software architectures while keeping the door open to more opportunities.

Does this speak to you? If YES, feel free to Join our Discord Server to stay in touch with the community and be part of independently organized events.

———————

Conclusion

By following the steps outlined in this guide, we were able to package a NodeJS application and MySQL database into separate containers and deploy them as a cohesive application stack using Docker Compose. With Docker, you can achieve consistent application execution across different environments, easily scale your application, and simplify version control. Docker Compose streamlines the management of multi-container applications, allowing you to define, configure, and deploy complex systems effortlessly.

Thanks for reading this article. Like, recommend, and share if you enjoyed it. Follow us on FacebookTwitter, and LinkedIn for more content.

author-avatar

About Orleando Dassi

I'm a Solutions Architect with 10 years of experience who is constantly learning while impacting the community by producing technical articles/videos, building projects, and conducting tech mentoring/coaching sessions. What describes me the most is my flexibility. Follow me on Twitter and LinkedIn.