Deploying a Java Open Liberty application with PostgreSQL
This tutorial illustrates deploying a Java Open Liberty application with odo and linking it to an in-cluster PostgreSQL service in a minikube environment.
There are two roles in this example:
- Cluster Admin - Prepare the cluster by installing the required Operators on the cluster.
- Application Developer - Imports a Java application, creates a Database instance, and connect the application to the Database instance.
Cluster admin
Prerequisites
- This section assumes that you have installed minikube and configured it.
We will be using Operators in this guide. An Operator helps in deploying the instances of a given service, for example PostgreSQL, MySQL, Redis.
Furthermore, these Operators are "bind-able". Meaning, if they expose information necessary to connect to them, odo can help connect your component to their instances.
See the Operator installation guide to install and configure an Operator on a minikube cluster.
The cluster admin must install two Operators into the cluster:
- PostgreSQL Operator
- Service Binding Operator
We will use Dev4Devs PostgreSQL Operator found on the OperatorHub to demonstrate a sample use case. This Operator will be installed in my-postgresql-operator-dev4devs-com
namespace by default, if you want to use another namespace, make sure that you add your namespace to .spec.targetNamespaces
list in the definition file before installing it.
In case of IBM Z & Power, please see below part to install PostgreSQL Operator
Steps to install Dev4Devs PostgreSQL Operator on IBM Z and Power
Note: Since operator Dev4Devs PostgreSQL Operator is only supported on x86, this section will use operator-registry image and PostgreSQL Operator image which are published on quay.io/ibm
by default. For Z, use operator-registry-s390x image and postgresql-operator-s390x image. For Power, use operator-registry-ppc64le image and postgresql-operator-ppc64le image.
- Create custom CatalogSource
oc apply -f https://raw.githubusercontent.com/redhat-developer/odo/main/docs/website/manifests/catalog-source-$(uname -m).yaml
- Install PostgreSQL Operator from custom CatalogSource
oc create -f https://raw.githubusercontent.com/redhat-developer/odo/main/docs/website/manifests/postgresql-operator-dev4devs-com-IBM-Z-P.yaml
Note: We will use the my-postgresql-operator-dev4devs-com
namespace for this guide.
Application Developer
Prerequisites
This section assumes that you have installed odo
.
Since the PostgreSQL Operator installed in above step is available only in my-postgresql-operator-dev4devs-com
namespace, ensure that odo uses this namespace to perform any tasks:
odo project set my-postgresql-operator-dev4devs-com
If you installed the Operator in a different namespace, ensure that odo uses it to perform any tasks:
odo project set <your-namespace>
Importing the JPA MicroService
In this example we will use odo to manage a sample Java JPA MicroService application.
Clone the sample application to your system:
git clone https://github.com/OpenLiberty/application-stack-samples.git
Go to the sample JPA app directory:
cd ./application-stack-samples/jpa
Initialize the application:
odo create java-openliberty mysboproj
java-openliberty
is the type of your application andmysboproj
is the name of your application.Deploy the application to the cluster:
odo push --show-log
The application is now deployed to the cluster - you can view the status of the cluster, and the application test results by streaming the cluster logs of the component that we pushed to the cluster in the previous step.
odo log --follow
Notice the failing tests due to an
UnknownDatabaseHostException
:[INFO] [err] java.net.UnknownHostException: ${DATABASE_CLUSTERIP}
[INFO] [err] at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:220)
[INFO] [err] at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:403)
[INFO] [err] at java.base/java.net.Socket.connect(Socket.java:609)
[INFO] [err] at org.postgresql.core.PGStream.<init>(PGStream.java:68)
[INFO] [err] at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:144)
[INFO] [err] ... 86 more
[ERROR] Tests run: 2, Failures: 1, Errors: 1, Skipped: 0, Time elapsed: 0.706 s <<< FAILURE! - in org.example.app.it.DatabaseIT
[ERROR] testGetAllPeople Time elapsed: 0.33 s <<< FAILURE!
org.opentest4j.AssertionFailedError: Expected at least 2 people to be registered, but there were only: [] ==> expected: <true> but was: <false>
at org.example.app.it.DatabaseIT.testGetAllPeople(DatabaseIT.java:57)
[ERROR] testGetPerson Time elapsed: 0.047 s <<< ERROR!
java.lang.NullPointerException
at org.example.app.it.DatabaseIT.testGetPerson(DatabaseIT.java:41)
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR] DatabaseIT.testGetAllPeople:57 Expected at least 2 people to be registered, but there were only: [] ==> expected: <true> but was: <false>
[ERROR] Errors:
[ERROR] DatabaseIT.testGetPerson:41 NullPointer
[INFO]
[ERROR] Tests run: 2, Failures: 1, Errors: 1, Skipped: 0
[INFO]
[ERROR] Integration tests failed: There are test failures.Note: This error will be fixed at a later stage in the tutorial when we connect a database instance to this application.
You can also create a URL with
odo
to access the application:odo url create --host $(minikube ip).nip.io
Push the URL to activate it:
odo push --show-log
Display the created URL:
odo url list
You will see a fully formed URL that can be used in a web browser:
$ odo url list
Found the following URLs for component mysboproj
NAME STATE URL PORT SECURE KIND
mysboproj-9080 Pushed http://mysboproj-9080.192.168.49.2.nip.io 9080 false ingressUse the URL to navigate to the
CreatePerson.xhtml
data entry page to use the application: In case of this tutorial, we will accesshttp://mysboproj-9080.192.168.49.2.nip.io/CreatePerson.xhtml
. Note that the URL could be different for you. Now, enter a name and age data using the form.Click on the Save button when complete
Note that the entry of any data does not result in the data being displayed when you click on the "View Persons Record List" link, until we connect the application to a database.
Creating a database to be used by the sample application
You can use the default configuration of the PostgreSQL Operator to start a Postgre database from it. But since our app uses few specific configuration values, lets make sure they are properly populated in the database service we start.
Store the YAML of the service in a file:
odo service create postgresql-operator.v0.1.1/Database --dry-run > db.yaml
Modify and add following values under
metadata:
section in thedb.yaml
file:name: sampledatabase
annotations:
service.binding/db_name: 'path={.spec.databaseName}'
service.binding/db_password: 'path={.spec.databasePassword}'
service.binding/db_user: 'path={.spec.databaseUser}'This configuration ensures that when a database service is started using this file, appropriate annotations are added to it. Annotations help the Service Binding Operator in injecting those values into the application. Hence, the above configuration will help Service Binding Operator inject the values for
databaseName
,databasePassword
anddatabaseUser
into the application.Change the following values under
spec:
section of the YAML file:databaseName: "sampledb"
databasePassword: "samplepwd"
databaseUser: "sampleuser"Create the database from the YAML file:
odo service create --from-file db.yaml
odo push --show-log
This action will create a database instance pod in the
my-postgresql-operator-dev4devs-com
namespace. The application will be configured to use this database.
Binding the database and the application
Now, the only thing that remains is to connect the DB and the application. We will use odo to create a link to the PostgreSQL Database Operator in order to access the database connection information.
List the service associated with the database created via the PostgreSQL Operator:
odo service list
Your output should look similar to the following:
$ odo service list
NAME MANAGED BY ODO STATE AGE
Database/sampledatabase Yes (mysboproj) Pushed 6m35sCreate a Service Binding Request between the application, and the database using the Service Binding Operator service created in the previous step:
odo link Database/sampledatabase
Push this link to the cluster:
odo push --show-log
After the link has been created and pushed, a secret will have been created containing the database connection data that the application requires.
You can inspect the new intermediate secret via the dashboard console in the
my-postgresql-operator-dev4devs-com
namespace by navigating to Secrets and clicking on the secret namedmysboproj-database-sampledatabase
: notice that it contains 4 pieces of data that are related to the connection information for your PostgreSQL database instance.Use
minikube dashboard
to launch the dashboard console.Note: Pushing the newly created link will terminate the existing application pod and start a new application pod that mounts this secret.
Once the new pod has initialized, you can see the secret database connection data as it is injected into the pod environment by executing the following:
odo exec -- bash -c 'export | grep DATABASE' \
declare -x DATABASE_CLUSTERIP="10.106.182.173" \
declare -x DATABASE_DB_NAME="sampledb" \
declare -x DATABASE_DB_PASSWORD="samplepwd" \
declare -x DATABASE_DB_USER="sampleuser"Once the new version is up (there will be a slight delay until the application is available), navigate to the
CreatePerson.xhtml
using the URL created in a previous step. Enter the requested data and click the Save button.Notice that you are re-directed to the
PersonList.xhtml
page, where your data is displayed having been input to the postgreSQL database and retrieved for display purposes.You may inspect the database instance itself and query the table to see the data in place by using the postgreSQL command line tool,
psql
.Navigate to the pod containing your db from the dashboard console. Use
minikube dashboard
to start the console.Click on the terminal tab.
At the terminal prompt access
psql
for your databasesampledb
.psql sampledb
Your output should look similar to the following:
sh-4.2$ psql sampledb
psql (12.3)
Type "help" for help.
sampledb=#Issue the following SQL statement from your :
SELECT * FROM person;
You can see the data that appeared in the results of the test run:
sampledb=# SELECT * FROM person;
personid | age | name
----------+-----+---------
5 | 52 | person1
(1 row)