DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • The Evolution of Scalable and Resilient Container Infrastructure
  • Scaling Microservices With Docker and Kubernetes on Production
  • Docker Model Runner: Streamlining AI Deployment for Developers
  • A Guide to Container Runtimes

Trending

  • How to Convert XLS to XLSX in Java
  • Data Quality: A Novel Perspective for 2025
  • Advancing Your Software Engineering Career in 2025
  • Navigating Change Management: A Guide for Engineers
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. How to Compose an Infinispan Docker Image

How to Compose an Infinispan Docker Image

Read on to explore how to create multicontainer Docker applications involving Infinispan with the help of Docker Compose.

By 
Manik Surtani user avatar
Manik Surtani
·
Dec. 07, 16 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
7.0K Views

Join the DZone community and get the full member experience.

Join For Free

In a previous post, we showed how to manipulate the Infinispan Docker container configuration at both runtime and boot time.

Before diving into multi-host Docker usage, in this post, we'll explore how to create multi-container Docker applications involving Infinispan with the help of Docker Compose.

For this, we'll look at a typical scenario of an Infinispan server backed by an Oracle database as a cache store.

All the code for this sample can be found on GitHub.

Using Infinispan With the Oracle JDBC Cache Store

In order to have a cache with persistence with Oracle, we need to do some configuration: configure the driver in the server, create the data source associated with the driver, and configure the cache itself with JDBC persistence.

Let's take a look at each of those steps.

Obtaining and Configuring the Driver

The driver (ojdbc6.jar) should be downloaded and placed in the Driver folder of the sample project.

The module.xml declaration used to make it available on the server is as follows:

<?xml version="1.0" encoding="UTF-8"?>

<module xmlns="urn:jboss:module:1.0" name="com.oracle.jdbc.driver">
    <resources>
        <resource-root path="ojdbc6.jar"/>
    </resources>

    <dependencies>
      <module name="javax.api"/>
       <module name="javax.transaction.api"/>
    </dependencies>
</module>

Configuring the Data Source

The data source is configured in the datasource element of the server configuration file as shown below:

<datasource enabled="true" jndi-name="java:jboss/datasources/OracleDS" pool-name="oracle">
          <connection-url>jdbc:oracle:thin:@oracle:1521:xe</connection-url>
          <connection-property name="oracle.net.encryption_client">accepted</connection-property>
          <connection-property name="oracle.net.encryption_types_client">AES128</connection-property>
          <connection-property name="oracle.jdbc.ReadTimeout">120000</connection-property>
          <driver>oracle</driver>
          <security>
            <user-name>SYSTEM</user-name>
            <password>oracle</password>
          </security>
          <pool>
            <min-pool-size>1</min-pool-size>
            <max-pool-size>50</max-pool-size>
            <prefill>true</prefill>
            <flush-strategy>EntirePool</flush-strategy>
          </pool>
          <validation>
            <validate-on-match>true</validate-on-match>
            <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleValidConnectionChecker"/>
            <use-fast-fail>true</use-fast-fail>
            <stale-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleStaleConnectionChecker"/>
            <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.oracle.OracleExceptionSorter"/>
          </validation>
          <timeout>
            <blocking-timeout-millis>60000</blocking-timeout-millis>
            <allocation-retry>100</allocation-retry>
            <allocation-retry-wait-millis>10000</allocation-retry-wait-millis>
            <idle-timeout-minutes>10</idle-timeout-minutes>
            <query-timeout>30000</query-timeout>
          </timeout>
          <statement>
            <share-prepared-statements>false</share-prepared-statements>
          </statement>
        </datasource>

Inside the datasource/drivers element, we need to declare the driver:

<driver module="com.oracle.jdbc.driver" name="oracle">
            <xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
          </driver>

Creating the Cache

The last piece is to define a cache with the proper JDBC Store:

        <replicated-cache name="docker-compose-demo" mode="ASYNC" start="EAGER">
          <expiration interval="300000" lifespan="525600000000"/>
          <transaction mode="NONE"/>
          <string-keyed-jdbc-store datasource="java:jboss/datasources/OracleDS" passivation="false" preload="true" purge="false" shared="true">
            <property name="databaseType">ORACLE</property>
            <string-keyed-table prefix="ISPN">
              <id-column name="id" type="VARCHAR(256)"/>
              <data-column name="datum" type="BLOB"/>
              <timestamp-column name="version" type="NUMBER"/>
            </string-keyed-table>
            <property name="skipLoad">true</property>
            <property name="startupTimeout">30000</property>
            <write-behind modification-queue-size="209715200" shutdown-timeout="25000" flush-lock-timeout="15000" thread-pool-size="5"/>
          </string-keyed-jdbc-store>
        </replicated-cache>

Putting It All Together

From now on, without using Docker, we'll be ready to download and install Oracle following the specific instructions for your OS, then download the Infinispan Server, edit the configuration files, copy over the driver jar, and figure out how to launch the database and server, taking care not to have any port conflicts.

If it sounds too much work, it's because it really is. Wouldn't it be nice to have all these wired together and launched with a simple command line? Let's take a look at the Docker way next.

Enter Docker Compose

Docker Compose is a tool part of the Docker stack to facilitate the configuration, execution, and management of related Docker containers.

By describing the application aspects in a single YAML file, it allows centralized control of the containers, including custom configuration and parameters, and it also allows runtime interactions with each of the exposed services.

Composing Infinispan

Our Docker Compose file to assemble the application is given below:

version: '2'

services:
  oracle:
    image: wnameless/oracle-xe-11g
    environment:
      - ORACLE_ALLOW_REMOTE=true
  infinispan:
    image: jboss/infinispan-server:8.2.5.Final
    command: custom/clustered-docker
    depends_on:
      - oracle
    volumes:
      - $PWD/driver:/opt/jboss/infinispan-server/modules/com/oracle/jdbc/driver/main/
      - $PWD/custom:/opt/jboss/infinispan-server/standalone/configuration/custom

It contains two services:

  • Oracle: Uses the wnameless/oracle-xe-11g Docker image with an environment variable to allow remote connections.
  • Infinispan: Uses Version 8.2.5 Final of the Infinispan Server image. It is launched with a custom command pointing to the changed configuration file and it also mounts two volumes in the container: one for the driver and its module.xml and another for the folder holding our server XML configuration.

Launching

To start the application, just execute:

docker-compose up -d

To inspect the status of the containers, use:

$ docker-compose ps

         Name                        Command               State                                           Ports                                         
--------------------------------------------------------------------------------------------------------------------------------------------------------
infinispan_infinispan_1   docker-entrypoint.sh custo ...   Up      11211/tcp, 11222/tcp, 57600/tcp, 7600/tcp, 0.0.0.0:8080->8080/tcp, 8181/tcp, 9990/tcp 
infinispan_oracle_1       /bin/sh -c /usr/sbin/start ...   Up      0.0.0.0:1521->1521/tcp, 22/tcp, 8080/tcp                                       

To follow the Infinispan server logs, use:

docker-compose logs -f infinispan

Infinispan usually starts faster than the database, and since the server waits until the database is ready (more on that later), keep an eye on the log output for "Infinispan Server 8.2.5.Final (WildFly Core 2.0.10.Final) started." After that, both Infinispan and Oracle are properly initialized.

Testing It

Let's insert a value using the Rest endpoint from Infinispan and verify it was saved to the Oracle database:

IP=$(docker-compose exec infinispan hostname -i | tr -d '\r')

curl -v -X PUT  -H "Content-Type: text/plain" --data "value" http://${IP}:8080/rest/docker-compose-demo/hello

To check the Oracle database, we can attach to the container and use Sqlplus:

$ docker-compose exec oracle bash

root@9212b18ea641:/# sqlplus SYSTEM/oracle

SQL*Plus: Release 11.2.0.2.0 Production on Tue Nov 29 17:29:32 2016

Copyright (c) 1982, 2011, Oracle.  All rights reserved.

Connected to:
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production

SQL> select id from "ISPN_docker_compose_demo";

ID
--------------------------------------------------------------------------------
hello 

Other Operations

It's also possible to increase and decrease the number of containers for each of the services:

docker-compose scale infinispan=2

A Thing or Two About Startup Order

When dealing with dependent containers in Docker-based environments, it's highly recommended to make the connection obtention between parties robust enough so that the fact that one dependency is not totally initialized doesn't cause the whole application to fail when starting.

Although Compose does have a depends_on instruction, it simply starts the containers in the declared order but it has no means to detected when a certain container is fully initialized and ready to serve requests before launching a dependent one.

One may be tempted to simply write some glue script to detect if a certain port is open, but that does work in practice; the network socket may be opened, but the background service could still be in a transient initialization state.

The recommended solution for this it to make whoever depends on a service to retry periodically until the dependency is ready. On the Infinispan plus Oracle case, we specifically configured the data source with retries to avoid failing at once if the database is not ready:

          <timeout>
            <blocking-timeout-millis>60000</blocking-timeout-millis>
            <allocation-retry>100</allocation-retry>
            <allocation-retry-wait-millis>10000</allocation-retry-wait-millis>
            <idle-timeout-minutes>10</idle-timeout-minutes>
            <query-timeout>30000</query-timeout>
          </timeout>

When starting the application via Compose you'll notice that Infinispan print some WARN with connection exceptions until Oracle is available. Don't panic; this is expected!

Conclusion

Docker Compose is a powerful and easy to use tool to launch applications involving multiple containers. In this post, it's allowed the start of Infinispan plus Oracle with custom configurations with a single command.

It's also a handy tool to have during development and testing phase of a project, especially when using and evaluating Infinispan with its many possible integrations.

Be sure to check other examples of using Docker Compose involving Infinispan, such as the Infinispan+Spark Twitter demo, and the Infinispan+Apache Flink demo.

Docker (software) Infinispan

Published at DZone with permission of Manik Surtani, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • The Evolution of Scalable and Resilient Container Infrastructure
  • Scaling Microservices With Docker and Kubernetes on Production
  • Docker Model Runner: Streamlining AI Deployment for Developers
  • A Guide to Container Runtimes

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!