This documentation is step by step process of deploying a Spring boot application which is interacting with MySQL DB. This seems to simple development effort but what if this effort is to be containerised.
For descriptive details, please check this video.
Essentials
Operating System : | Any Operating system (Window/Linux/Mac) |
Container | Docker (Should be installed) |
Application | Spring boot application (CRUD Operation) |
Database | MySQL |
Approach
This Spring boot application is based on Rest based service, which is interacting with the database for its operations. This is acting as a microservice and inherit the following advantages of microservice.
We are considering an example of a Spring boot application which encapsulates the Rest api, which handles the CRUD operations. This application’s design is simple as the user requests the operation with appropriate payload and it gets stored in the database. This application includes the following features.
- The Spring boot application is built on Spring boot which caters the CRUD operations for the Order system.
- Data will be stored in the MYSQL database.
- The application has an initial script that will be executed at the start-up only once.
- If any data is already present in the database and the container is restarted, then previous data will be persisted.
Technical Details:
Project Details
We have a sample application on Springboot. This application have the following package structure
The package names are self explanatory with their responsibilities. Here the api package contains the rest controllers, service package encapsulate the business logic and repos package have the JPA related logic which interacted with the MYSQL database.
Following API are defined in the controller class
API | Method | Usage |
---|---|---|
\bill\api\create | PUT | Create a new record |
\bill\api\update | POST | Update the existing record |
\bill\api\get | GET | Fetch all the records |
\bill\api\get\{id} | GET | Fetch the specific record |
Application Resources
There is not much information present in application resource file as we will be moving our configuration into docker-compose file. There is datasource URL present in this resource file which is used to test the DB connectivity in local environment.
Initial DB script
To run the application we need a database. The script below is used to create the database before the application deployment. We will not be doing any manual steps for this deployment. Everything would be automated and clean.
Deployment:
docker deployment configuration
Lets invest some time to deploy this application using the docker compose. We are using docker compose as this allow us to consolidate the deployment configuration in one file. We will achieve the following objectives with this configuration.
- Deployment of Web application
- This deployment have log files which are available outside the container.
- Deployment of database container.
- Since container can be crash any time and if data is present in the ephemeral storage, it will be lost too. So data files are present outside of the container.
- This storage could be on any cloud. This can also be in local system but we cannot scale container with the local storage.
version: "3.8"
services:
billing_data_db: ##Service will be refer in the JDBC URL in the billing_web_app service
container_name: billing-percona-db
platform: linux/x86_64
image: percona:ps-5.6
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=$ROOT_PASSWORD
- MYSQL_USER=$DB_USER
- MYSQL_PASSWORD=$DB_PASSWORD
- MYSQL_DATABASE=$MYSQLDB_BILLING_DATABASE
- MYSQL_ROOT_HOST="%"
ports:
- $MYSQLDB_BILLING_LOCAL_PORT:$MYSQLDB_BILLING_DOCKER_PORT
volumes:
- type: bind
source: $BASE_LOC/$BILLING_MYSQL_DATA_LOC
target: /var/lib/mysql
volume:
nocopy: true
- type: bind
source: $BASE_LOC/$BILLING_INITIAL_SCRIPT_LOC
target: /docker-entrypoint-initdb.d/1.sql
volume:
nocopy: true
billing_web_app:
depends_on:
- billing_data_db
container_name: billing-web-app
build:
dockerfile: Dockerfile
restart: on-failure
env_file: ./.env
ports:
- $BILLING_WEB_LOCAL_PORT:$BILLING_DOCKER_WEB_PORT
environment:
SPRING_APPLICATION_JSON: '{
"spring.datasource.url": "$MYSQLDB_BILLING_URL",
"spring.datasource.username": "$DB_USER",
"spring.datasource.password": "$DB_PASSWORD",
"spring.jpa.properties.hibernate.dialect": "org.hibernate.dialect.MySQL5InnoDBDialect",
"spring.jpa.hibernate.ddl-auto": "$DDL_OPTION",
"spring.jpa.show-sql": "$SHOW_SQL"
}'
volumes:
- type: bind
source: $BASE_LOC/$BILLING_LOG_LOC
target: /opt/multimoduleprojects/restaurant/billing/logs
volume:
nocopy: true
stdin_open: true
tty: true
We have the docker-compose file which contains the deployment configuration. Lets peep inside and see what is defined here. We will check the docker compose configurations explanation in other blogpost. Here we just mention the specific configuration, which is required for this deployment.
services: This section used to define the services. With this application, we have the following items.
- Springboot Service:
- We are calling this as service as the API are exposed here which serve the response for a request.
- We have 4 API exposed except (delete) in this application which interact with the DB (DB Service)
- This service is represented by the billing_web_app
- Database Service
- To access the database we will be accessing DB service, not the DB. This means that the DB service will interact with DB.
- This service is represented by the billing_data_db.
Configuration for the services
Following properties are included in the service:
Configuration Key | Description |
---|---|
container_name | Name of the container. |
image | image used to create the container. |
depend_on | This parameter is used identify if this service is dependent on any other service. Usually this is setting the order of start and stop the service. In our example db should start first then web application. |
build | This section is used to define the Dockerfile location in local with which the image can be created. It has 2 attributes 1) context 2) dockerfile |
env_file | This is the file from where the properties are picked for this deployment Here we have defined the environment file as .env in the same folder. |
environment | This section is represents an array and will hold the environment variable and its value. In data_db_service the environment attribute are defined, which is used by the image of percona db. You can refer the page for more env variable as per your requirement. |
ports | This configuration is used to define the port forwarding. So here the port in the container is mapped with the host system |
restart | This configuration suggest the policy when restart is required This configuration accept the collection |
environment | This configuration refer the environment variable required for the application. This configuration accept the list |
volumes | This is the mechanism with used to persist the data outside the containers. Volume is also accept list which contains the following elements. |
volumes – type | This element is the type of the volume, it could be bind, volume. |
volumes – source | This is the path or file in the host (Where docker daemon is running) |
volumes – destination | This is the path in the container where the file or directory is mounted. |
Environment file:
We have created the file where we are capturing the variables which are used in the docker-compose file. Lets take a view on this file. This file help to organise the variables and its corresponding values into it. This file is registered with docker compose using the configuration env_file.
Note: This file is named as .env
##GLOBAL VARIABLES:
ROOT_PASSWORD=root
DB_USER=<MYSQL_USER>
DB_PASSWORD=<MYSQL_PASSWORD>
SHOW_SQL=true
DDL_OPTION=none
BASE_LOC=/Users/cpandey/dev/itlogiclab/blog
##BILLING VARIABLE
MYSQLDB_BILLING_DATABASE=billdb
MYSQLDB_BILLING_LOCAL_PORT=3311
MYSQLDB_BILLING_DOCKER_PORT=3306
MYSQLDB_BILLING_URL=jdbc:mysql://billing_data_db:$MYSQLDB_BILLING_DOCKER_PORT/$MYSQLDB_BILLING_DATABASE?useSSL=false
BILLING_WEB_LOCAL_PORT=20001
BILLING_DOCKER_WEB_PORT=20003
BILLING_MYSQL_DATA_LOC=docker-data/restaurant/billing/mysql/data
BILLING_INITIAL_SCRIPT_LOC=docker-data/restaurant/billing/mysql/script/billing.sql
BILLING_LOG_LOC=docker-data/restaurant/billing/logs
Initial Script execution
In above configuration we have defined section in the volume where we have renamed sql file to 1.sql. We have mounted this file inside the container under the folder named as docker-entrypoint-initdb.d . These scripts are getting executed name wise in ascending order. If we have 2 scripts, then we can rename them with 1 and 2 for their order and mount.
Deployment and Validation
Let’s do our hand dirty by running the application and test. Lets execute the few docker commands.
Application deployment: Lets start with the deployment process using the file we have prepared so far.
Command: docker-compose -f docker-compose-billing.yaml up -d
This command will bring up the services.
Note: Data files which are present where the docker daemon is running, is defined as type of bind. It should be volume. I have just kept it as bind to demonstrate it in local env.
Lets check the container status. Execute the following docker command to check the services:
Command: docker ps
There are 2 containers created. One container belongs to mysql-percona db and other one is a web application, which is using the DB as backend. Here notice the details under the column PORTS. If we take a close look here, these ports can be explained as
0.0.0.0:20001->20003/tcp, :::20001->20003/tcp | 0.0.0.0:20001->20003/tcp | Web application | All the traffic on the host system at the port 20001 will get routed to 20003 port on the container. |
0.0.0.0:20001->20003/tcp, :::20001->20003/tcp | :::20001->20003/tcp | Web application | All the traffic on the host system at the port 20001 will get routed to 20003 port on the container. |
0.0.0.0:3311->3306/tcp, :::3311->3306/tcp | 0.0.0.0:3311->3306/tcp | DB Services | Here all the traffic on the host system at port 3311 will forwarded to 3306 port on container. |
0.0.0.0:3311->3306/tcp, :::3311->3306/tcp | ::3311->3306/tcp | DB Services | Here all the traffic on the host system at port 3311 will forwarded to 3306 port on container. |
Lets login into the mysql container to validate the deployment.
Lets check the tables: Which all are empty initially.
Validation:
Fetch Records: Since we do not have any data in the database, so the record return by the container will be blank.
Add Records: Lets give it a try to add the record in the DB.
UPDATE Record: Lets update the same record. Here I have updated amount and billAmount fields, which are updated successfully.
GET All: Records:
Database view: database is getting populated with the following record.
Shut down the container:
Container will be removed by using the following command. With this command the container will be removed but the data which is persisted in the host machine will not be erased. when you run the containers again, you will get all the transaction which you did in the last run.
Conclusion: With this docker compose we can manage all the configuration of the deployment at the single file. Even if we have multi module project, we can define as many as services and their corresponding DB services, messaging services and one can define how these services interact with each other.
Codebase
You can find the code at
https://github.com/pandeych009/itlogiclab-microservices/tree/dev