Dockerizing a Spring Boot application with MySQL database
- June 21, 2023
In this technical article, we’re going to dive into the following topics:
- Installing Docker engine
- Creating a Docker network
- Verifying Docker installation
- Building a Spring Boot application and connecting with MySQL running in a container
- Building a JAR via Gradle or Maven
- Configuring a Dockerfile
- Building a Docker image
- Running the Docker image
Installing Docker engine
- First we will download and install the docker engine. To download go to: https://docs.docker.com/docker-for-windows/install/
- Run the Docker Desktop Installer.exe
- Once the installation process starts, select whether you want to use WSL2 or Hyper-V.
- Follow the installation process until installation is complete.
- After completion of the installation click Close.
- Start the docker desktop engine from the shortcut menu.
Creating a Docker network
A Docker network is a collection of containers running together. A Docker network is used to provide complete isolation to containers.
- To create a docker network type the following command:
docker network create <network-name>
- To see all available networks, type the following command:
docker network ls
Verifying Docker installation
Verifying the Docker installation, pulling the MySQL image from DockerHub, and running it.
- To pull MySQL’s docker image type the following command in the terminal:
docker pull MySQL
- To run the pulled image type the following command:
docker run --name <mysql-container-name>
--network <network-name>
-p <host-machine-port>:<mysql-server-port-in-container>
-e MYSQL_ROOT_PASSWORD=<root-user-new-password>
-d mysql
–name: It is used to specify a specific name for a container; otherwise, Docker Engine will assign a unique name itself.
–network: It is used to define a Docker network on which our container will be deployed. Networks help in achieving total isolation of containers.
-p: It is used to perform port mapping between our host machine and the container, where <host-machine-port> represents the port through which we will interact with our host machine. All requests made to <host-machine-port> will be forwarded to <mysql-server-port-in-container> within the container.
-e: It is used to pass an environment variable. In this case, we will be passing a new password for the root user.
-d: It is used to run containers in detached mode, so that our container is not terminated when the terminal is closed.
- To connect to the database in the container, open MySQL Workbench and connect to localhost:<host-machine-port>. Then, enter the password assigned to the root user.
- Create a new database named ‘poc’. We will use this database in our application.
Building a Spring Boot application and connecting with MySQL running in a container:
We will create a REST API with a single endpoint only to save users in the database.
- To create a new Spring Boot project go to https://start.spring.io/
- Now configure project type (Gradle or Maven), Spring Boot version, metadata and Java version according to your need.
-
Add following dependencies:
- Spring Web
- Spring Data JPA
- MySQL Driver
- Generate and download the project.
Now we will make the following changes to our application:
- Create an Entity class “user” with basic information.
package com.apisero.microservice.entities;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String email;
private String name;
private int age;
public User() {
}
public User(int id, String email, String name, int age) {
this.id = id;
this.email = email;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- Now let’s create a repository to interact with the database.
- Now let’s create a RestController to give endpoints to our REST API.
- Add the following database configuration to the application.properties file:
spring.datasource.url=jdbc:mysql://localhost:3309/poc
spring.datasource.username=root
spring.datasource.password=Apisero@123
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true
- Now we will run our application and make a call to endpoint ‘POST: localhost:8080/users’.
Building a JAR via Gradle or Maven:
Before building the jar, we need to update the application.properties file because till now we are able to access localhost:3309 on the host machine, But on containerization of our application, port 3309 on the host machine will not be accessible, since localhost in the container will point to the container itself, thus we need to modify our datasource in application.properties file.
Update spring.datasource.url to jdbc:mysql://<mysql-container-name>:3306/poc
1. Building Jar via Gradle:
Go to the root of your project and run the following command:
gradle clean build jar
Gradle will generate a jar file in ‘./build/libs/’
Eg: ‘./build/libs/microservice-0.0.1-SNAPSHOT.jar’
2. Building Jar via Maven:
Go to the root of your project and run the following command:
mvn clean package
Maven will generate a jar file in ‘./target/’ folder
Eg: ‘./target/microservice-0.0.1-SNAPSHOT.jar’
Configuring a Dockerfile:
Create a file named “Dockerfile” in the root or any subdirectory of the project and write the following configuration code.
FROM openjdk:17
COPY /path/to/generated/jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
FROM: It will create a layer from an existing Java image from any container registry.
ADD: It will copy files from the source and add them to the filesystem of the image at the provided path (usually second argument).
ENTRYPOINT: It specifies the command that Docker will use to run our app. In this case we will pass [“java”, “-jar”, “<name-of-the-jar>”]
Building a Docker image:
To Build a docker image type the following command. (Don’t add the name “Dockerfile” to the path):
docker build --tag <image-name>:<image-tag> ./path/to/Dockerfile
To see the newly created docker image type the following command:
docker image ls
Running the Docker image:
To run a docker image run the following command:
docker run
-network <network-name>
-p <host-machine-port>:<application-port>
-d <image-name>
Here -p is used to do port mapping between the <host-machine-port> and <application-port>. where <host-machine-port> is the port number on the host system which we will use to interact with the container and <application-port> is the port within the container on which our application is running.
All requests made to <host-machine-port> will be forwarded to the <application-port> in the container.
–network is used to define the docker network, on which our container will be deployed, network is required for the complete isolation of our docker container.
-d is used to run containers in detached mode, So our container is not killed upon closing the terminal.
Now, we’ll make a call to the endpoint ‘POST: localhost:9090/users’
As we can observe, calls are now being made on port 9090 instead of the original port 8080, which indicates that our application has been successfully dockerized. However, if we check the Spring startup logs in the terminal, it states that the application started on port 8080 because the application was originally running on port 8080 within the container.
— By Sudhanshu Jha