Payara Micro in Docker

Photo of Matthew Gill by Matthew Gill

The Payara Micro 173 release had a few changes which will make the lives of Docker users easier. This blog will cover the changes which affect Payara Micro in Docker,  demonstrating the following:

  • Using the new Payara Micro 5 Docker image, which provides Java EE 8 features.

  • Deploying applications without the targetted database being present.

  • Adding library JARs from the command line.


Using Payara Server with Docker -   Guide Download  Using Payara Micro with Docker -   Guide Download

 

New Payara Server 5 Snapshot Docker images

We have recently begun publishing snapshot builds of Payara Server and Payara Micro 5, our next major version of Payara Server which provides updated APIs such as CDI 2.0. Along with the 173 release of Payara Server, we also began publishing 5-SNAPSHOT tags of our official Docker images which are built daily. These can be used as follows:

  • docker run -it payara/micro:5-SNAPSHOT
  • docker run -it payara/server-full:5-SNAPSHOT

Adding library JARs from the command line

Payara 5 snapshots also include the latest changes to Payara 173, which means that both the Payara Micro 5 and Payara Micro 173 images have the new --addJars command option. This option can be used in multiple ways depending on the need. The following usages are supported:

  • Adding a single JAR library
    e.g. java -jar payara-micro.jar --addJars myLib.jar

  • A directory of JAR libraries
    e.g. java -jar payara-micro.jar --addJars myLibraryDirectory/

  • Adding a colon-separated list of JARs and/or directories (similar to the Java classpath)
    e.g. java -jar payara-micro.jar --addJars myLib.jar:myLibraryDirectory/:myOtherLib.jar

  • Using --addJars in combination with --outputUberJAR will package all libraries into the JAR so that the long command does not need to be specified each time.
    e.g. java -jar payara-micro.jar --addJars myLib.jar --ouputuberjar payara-micro-with-libs.jar

Deploying applications without checking the database

With Payara 173, applications can now be deployed regardless of whether the target database is available. This is extremely useful to users of container-based services since there is no need to start a database inside the container for the application to deploy during the build cycle of the image. This means that the application will be successfully deployed more quickly, more reliably, and the container can start with everything already deployed and configured. Previously, the application may be left undeployed but the container would keep the server running and deem it to be healthy.

Test Project

To demonstrate these features, I have created a test project. The application creates a connection to a database on the server "database" every time /ping is visited, and returns the validity of the connection. The application contains two short classes and a glassfish-resources.xml. The full source code for this example is available in our Payara Examples repository, Payara-Examples/Payara-Micro/database-ping.

 

src/main/webapp/WEB-INF/glassfish-resources.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
 
    <!-- Creates a connection pool in Payara to connect to a MySql database called "test" with the server name "database" -->
    <jdbc-connection-pool   allow-non-component-callers="false"
                            associate-with-thread="false"
                            connection-creation-retry-attempts="0"
                            connection-creation-retry-interval-in-seconds="10"
                            connection-leak-reclaim="false"
                            connection-leak-timeout-in-seconds="0"
                            connection-validation-method="auto-commit"
                            datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
                            fail-all-connections="false"
                            idle-timeout-in-seconds="300"
                            is-connection-validation-required="false"
                            is-isolation-level-guaranteed="true"
                            lazy-connection-association="false"
                            lazy-connection-enlistment="false"
                            match-connections="false"
                            max-connection-usage-count="0"
                            max-pool-size="32"
                            max-wait-time-in-millis="60000"
                            name="jdbc/testConnPool"
                            non-transactional-connections="false"
                            pool-resize-quantity="2"
                            res-type="javax.sql.DataSource"
                            statement-timeout-in-seconds="-1"
                            steady-pool-size="8"
                            validate-atmost-once-period-in-seconds="0"
                            wrap-jdbc-objects="false">
        <property name="URL" value="jdbc:mysql://database:3306/test"/>
        <property name="User" value="root"/>
        <property name="Password" value="password"/>
    </jdbc-connection-pool>
 
    <!-- Creates a DataSource called "jdbc/testDS" for accessing the connection pool -->
    <jdbc-resource enabled="true" jndi-name="jdbc/testDS" object-type="user" pool-name="jdbc/testConnPool">
        <description>Test DataSource</description>
    </jdbc-resource>
 
</resources>

src/main/java/test/PingEndpoint.java

@Path("/ping")
@RequestScoped
public class PingEndpoint {
 
    // Injects the DataSource called "jdbc/testDS" (it's an app scoped JNDI resource as it was declared in the glassfish-resources.xml).
    @Resource(lookup = "java:app/jdbc/testDS")
    private DataSource testDS;
 
    /**
     * Listens on /ping. Creates a connection, prints the connection validity then closes the connection.
     */
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String ping() throws SQLException {
        Connection conn = testDS.getConnection();
        boolean valid = conn.isValid(3);
        conn.close();
        return "Connection made.\nChecking validity of connection... " + valid + ".";
    }
}

src/main/java/test/RestApplication.java

@ApplicationPath("/")
public class PingEndpoint extends Application {
  // Loads each available JAX-RS resource (there's only 1!)
}

 

The Dockerfile to use this application with Payara Micro is shown below:

 

Dockerfile
# Using the Payara Micro 5 snapshot build.
FROM payara/micro:5-SNAPSHOT
 
# Downloads the database connector library
RUN wget -O $PAYARA_PATH/database-connector.jar http://central.maven.org/maven2/mysql/mysql-connector-java/5.1.43/mysql-connector-java-5.1.43.jar
 
# Adds an application to be loaded
ADD myapplication.war $PAYARA_PATH
 
ENTRYPOINT ["java", "-jar", "$PAYARA_PATH/payara-micro.jar", "--addJars", "$PAYARA_PATH/database-connector.jar", "--deploy", "$PAYARA_PATH/myapplication.war"]

 

Since the application will be deployed regardless of whether the database is available or not, the images can be started in any order (as long as the Payara Micro image has a link to the database server). This means that these images would work together in a Docker Swarm environment. But just for ease, we can just run the following commands:

docker run -d --name database -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=test mariadb
docker run -d -p 8080:8080 --name payara --link database:database custom-micro

 

After this you can then go to http://localhost:8080/myapplication/ping, where you should get the following response:

 
Connection made.
Checking validity of connection... true

 

Before 173, you might have gotten the following error (as well as an "--addJars is not a valid command line argument" error!) in the Payara logs:

 
RAR5038:Unexpected exception while creating resource for pool { PoolInfo : (name=java:app/jdbc/testConnPool), (applicationName=myapplication) }. Exception : javax.resource.spi.ResourceAllocationException: Connection could not be allocated because: Communications link failure
 

This is because Payara Server would detect that the required database wasn’t running, and would be unable to create the resource for it. This isn’t the case anymore however.

 
 Microservices for Jakarta EE Developers  Download the Guide
 

 

Comments