Skip to main content
Version: v2

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:

  1. Cluster Admin - Prepare the cluster by installing the required Operators on the cluster.
  2. Application Developer - Imports a Java application, creates a Database instance, and connect the application to the Database instance.

Cluster admin


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:

  1. PostgreSQL Operator
  2. 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 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.

  1. Create custom CatalogSource
oc apply -f$(uname -m).yaml
  1. Install PostgreSQL Operator from custom CatalogSource
oc create -f

Note: We will use the my-postgresql-operator-dev4devs-com namespace for this guide.

Application Developer


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.

  1. Clone the sample application to your system:

    git clone
  2. Go to the sample JPA app directory:

    cd ./application-stack-samples/jpa
  3. Initialize the application:

    odo create java-openliberty mysboproj

    java-openliberty is the type of your application and mysboproj is the name of your application.

  4. Deploy the application to the cluster:

    odo push --show-log
  5. 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] at java.base/
    [INFO] [err] at java.base/
    [INFO] [err] at java.base/
    [INFO] [err] at org.postgresql.core.PGStream.<init>(
    [INFO] [err] at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(
    [INFO] [err] ... 86 more
    [ERROR] Tests run: 2, Failures: 1, Errors: 1, Skipped: 0, Time elapsed: 0.706 s <<< FAILURE! - in
    [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>

    [ERROR] testGetPerson Time elapsed: 0.047 s <<< ERROR!

    [INFO] Results:
    [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
    [ERROR] Tests run: 2, Failures: 1, Errors: 1, Skipped: 0
    [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.

  6. You can also create a URL with odo to access the application:

    odo url create --host $(minikube ip)
  7. Push the URL to activate it:

    odo push --show-log
  8. 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
    mysboproj-9080 Pushed 9080 false ingress
  9. Use the URL to navigate to the CreatePerson.xhtml data entry page to use the application: In case of this tutorial, we will access Note that the URL could be different for you. Now, enter a name and age data using the form.

  10. 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.

  1. Store the YAML of the service in a file:

    odo service create postgresql-operator.v0.1.1/Database --dry-run > db.yaml
  2. Modify and add following values under metadata: section in the db.yaml file:

    name: sampledatabase
    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 and databaseUser into the application.

  3. Change the following values under spec: section of the YAML file:

    databaseName: "sampledb"
    databasePassword: "samplepwd"
    databaseUser: "sampleuser"
  4. 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.

  1. 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
    Database/sampledatabase Yes (mysboproj) Pushed 6m35s
  2. Create 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
  3. 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 named mysboproj-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.

  4. 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="" \
    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.

  5. Navigate to the pod containing your db from the dashboard console. Use minikube dashboard to start the console.

  6. Click on the terminal tab.

  7. At the terminal prompt access psql for your database sampledb.

    psql sampledb

    Your output should look similar to the following:

    sh-4.2$ psql sampledb
    psql (12.3)
    Type "help" for help.

  8. Issue the following SQL statement from your :

    SELECT * FROM person;
  9. 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)