Nikhil Chandrappa, Ecosystem Software Engineer at Yugabyte, contributed to this blog post.
Modernizing monolithic applications dominated this past decade. Over the next decade, enterprises will increasingly need to look at modernizing Relational Database Management Systems (RDBMS) workloads to handle the scale that the increase in microservices has yielded.
Distributed SQL gives businesses a path toward modernizing this next application tier. App developers will benefit from the ease of linear scaling supported by distributed SQL databases. And they will still have that familiar spring data abstraction, which already has wide adoption in the developer community.
In this blog, we’ll walk you through the steps of connecting a Spring Boot application with a cloud-native distributed SQL database powered by Yugabyte. This application uses the familiar Spring Data JPA repositories with a cluster-aware JDBC data source that Yugabyte recently released.
YugabyteDB YSQL and YCQL for Spring Data
What You Will Build
In this tutorial, you will install a Spring Boot application that exposes REST APIs for performing CRUD operations against a YugabyteDB cluster. This application will use Spring Data JPA and the YugabyteDB JDBC driver.
This application implements four API endpoints that store mock data about a customer (name, email, and customer ID). Once running, we will curl
the REST APIs to add information to the database and query it. The application structure is simple. All the functionality is divided among five classes, which will be discussed below.
What You Need
In order to complete the tutorial, you will need the following:
-
Access to a PKS cluster, with cluster requirements of, at minimum:
-
1x master node (4 CPU, 16GB RAM, 32GB disk)
-
4x worker nodes (8 CPU, 32GB RAM, 64GB disk)
-
Enabled privileged container access
-
-
Helm 2 and Tiller installed on the PKS cluster
-
Docker installed locally
-
Git CLI tools installed locally
-
JDK 1.8 or later
-
A favorite text editor or IDE
-
A container repository such as Harbor or Docker Hub
-
About 15 minutes
Install YugabyteDB on PKS
To begin, we will install a three-node YugabyteDB cluster with a replication factor (RF) of three. At this RF level, the cluster can sustain a single node failure without data loss or downtime.
To install YugabyteDB on PKS, we first need to create an RBAC policy for the service, then initialize it using Helm.
$ kubectl create -f https://raw.githubusercontent.com/YugaByte/charts/master/stable/yugabyte/yugabyte-rbac.yaml
$ helm init --service-account yugabyte-helm --upgrade --wait |
$ helm repo add yugabytedb https://charts.yugabyte.com
|
$ helm repo update
|
Then we install YugabyteDB.
$ helm install yugabytedb/yugabyte --wait --namespace yb-demo --name yb-demo --set "disableYsql=false" |
Finally, we review the resources deployed by the Helm chart.
$ kubectl get all -n yb-demo |
YugabyteDB is now installed on the PKS cluster. In the next section, we will clone the application from GitHub, then go over the classes that make up the integration and the functionality.
Building the Application
This application was built using Spring Initializr. Spring Initializr both offers an easy way to pull in dependencies and builds the boilerplate application for you. We will go over the application classes that integrate it into YugabyteDB in detail.
For now, we’ll clone the repo from GitHub.
$ git clone https://github.com/yugabyte/spring-yugabytedb-demo.git |
Now that we’ve downloaded the application, let’s explore how the integration is done. It consists of five classes, plus an additional dependency. Let’s take a look at how it works.
Added Dependencies
The Spring Initializr does a great job of building out all of the needed dependencies. But the application needed one more that was not initially included. Here are the lines added in spring-yugabytedb-demo/pom.xml
<dependency> |
This tells Maven the application is dependent on YugabyteDB YSQL, Yugabyte’s PostgreSQL-compliant API, and to download the necessary bits.
Configuring the Connection
Spring Boot’s auto-reconfiguration mechanism will initialize the JDBC data source on startup. But without configuring, it will not know how to connect to the YugabyteDB instances created above.
YugabyteDB supports postgres dialect of Hibernate. Hence, within spring-yugabytedb-demo/src/main/resources/application.properties
, we set spring.jpa.properties.hibernate.dialect
to configure the JPA to use the PostgreSQL dialect.
Next, we set yugabyte.sql.datasource.url
. This configures the data source URL to use the Kubernetes service DNS name of the YugabyteDB cluster, which will be running locally with this application.
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
yugabyte.sql.datasource.url=jdbc:postgresql://yb-tservers.yb-demo.svc.cluster.local:5433/yugabyte
Instantiate the Cluster-Aware JDBC DataSource
Now that the configurations are done, let’s look at the classes. This first class, located at spring-yugabytedb-demo/src/main/java/com/yugabyte/demo/springyugabytedbdemo/config/YugabyteDataSourceConfig.java
, instantiates the cluster-aware data source using the address assigned previously in the application.properties
file.
[...] |
Define the Entity Model
Next, we need to create a class that will define a JDBC entity—in this case, a table for our customer information to be stored.
First, we create a new table entity “customer” within the class com.yugabyte.spring.ycql.demo.springycqldemo.domain.Customer
, then define several attributes related to the customer. Finally, getter and setter functions are provided for those attributes.
[...] |
Create the JPA Repository
The Spring Data JPA Repository provides consistent access patterns for working with databases. It considerably reduces the boilerplate code required to implement data access layers. Here we are extending JpaRepository
for CRUD operations to be performed against the customer entity defined above.
In class com.yugabyte.spring.ycql.demo.springycqldemo.repo.CustomerRepository
, the JpaRepository
interface enables APIs for all the common operations Spring Data supports. For example, save(), findById(), findAll(), and deleteByID()
. Here, we are simply instantiating a new repository.
[...] |
Create the Controller Class
Finally, we examine the Controller class located at:
spring-yugabytedb-demo/src/main/java/com/yugabyte/demo/springyugabytedbdemo/controller/CustomerController.java
.
This class defines our API and its behavior.
[...] |
In this controller, we are instantiating APIs for creating a new customer record, retrieving that record and the ability to delete it.
Build the JAR and Generate the Docker Image
Now that we have seen all the code our app needs to run, it is time to build, package, and deploy the application on PKS.
First, using our IDE or toolset of choice, we build the application. If we use IntelliJ IDEA for MacOS, command+F9 will do this, but your IDE may vary the commands used.
Next, before we package the application, we set a variable for our container repository account name. This will make the next couple of commands easier to run.
$ export REGISTRY_UN=registry-username |
Then we package the application into a Docker image.
$ ./mvnw com.google.cloud.tools:jib-maven-plugin:dockerBuild -Dimage=$REGISTRY_UN/spring-yugabytedb-demo:0.1v |
Once the application is built, we push it to our registry.
$ ./mvnw com.google.cloud.tools:jib-maven-plugin:build -Dimage=$REGISTRY_UN/spring-yugabytedb-demo:0.1v |
Deploy the Application on PKS
Now that the application is built and pushed to our registry, it’s time to install it onto the PKS cluster. Since the application is now just a container stored in a repository, this is straightforward to do in Kubernetes.
$ kubectl run --image=$REPO_ACCOUNT/spring-yugabytedb-demo:0.1v spring-yugabytedb-demo --limits="cpu=1200m,memory=2Gi" --requests="cpu=1000m,memory=2Gi" --image-pull-policy=Always --port=8080 |
This installs the container onto the cluster and sets up some infrastructure limits. And since we are using cluster-aware drivers, the connection pool gets initialized to all the available servers in the cluster automatically. We can review the connection pool information from the application logs.
To use the service, we need to expose it and get a public IP. To do this, we run the kubectl expose
command with type=LoadBalancer
.
$ kubectl expose deployment spring-yugabytedb-demo --type=LoadBalancer --name=demo-service |
To get the public-facing IP for the exposed service, we run the following.
$ watch kubectl get service |
This will return a list of services running on the cluster. The demo service will initially say the external IP is pending. When it shows the EXTERNAL-IP address, we save it as an environment variable.
$ export LOADBALANCER_IP=xxx.xxx.xxx.xxx |
Using the Service
Now that the application is running and connected to the YugabyteDB instance, we will insert some data into the customer table. To do this, we run the following curl command, which will create a customer record for “Alice.” You can feel free to play with this and add multiple customer records, just make sure to insert unique IDs and emails for each customer.
$ curl --location --request POST |
Next, we retrieve those records from the customer table with the following command. This should return a JSON object containing all uploaded customers, and all data about them.
$ curl http://$LOADBALANCER_IP:8080/customers |
Finally, we retrieve some customer information using only the customer email as an ID. This should also return a JSON object, but unlike the command above, this should be just for the single customer queried.
$ curl http://$LOADBALANCER_IP:8080/customer/[email protected] |
That’s it! This is now a functioning Spring application connected to a distributed SQL instance powered by Yugabyte. And it’s all running on PKS. There is more that can be done with this application, so go explore the code some more!
If you want to know more about Spring, check out the recently refreshed spring.io site! If you want to know more about YugabyteDB, and the ease of use it brings to distributed SQL and more, check out their site. And for more about Enterprise PKS, and the Tanzu suite of applications, check out tanzu.io.