Creating a Wildfly Docker image with TimescaleDB support
Table of Contents
Introduction #
Wildfly docker image #
As a base image, we’ll use the latest official Wildfly docker image, named jboss/wildfly:24.0.0.Final
.
Since TimescaleDB relies on PostgreSQL, we also need to setup the PostgreSQL driver and datasource in Wildfly. This requires the following:
- Download PostgreSQL driver from the official maven repository
- Adding PostgreSQL module
- Adding PostgreSQL driver
- Setup a main Datasource
Luckily, all these steps can be automated using jboss cli (located at /opt/jboss/wildfly/bin/jboss-cli.sh
).
Here’s the full Dockerfile
:
1FROM jboss/wildfly:24.0.0.Final 2 3ENV WILDFLY_USER admin 4ENV WILDFLY_PASS password 5ENV JBOSS_CLI /opt/jboss/wildfly/bin/jboss-cli.sh 6ENV DEPLOYMENT_DIR /opt/jboss/wildfly/standalone/deployments/ 7 8ENV DB_NAME sample-db 9ENV DB_USER postgres10ENV DB_PASS postgres11ENV DB_HOST db12ENV DB_PORT 543213ENV POSTGRESQL_VERSION 42.2.2314 15RUN echo "Building wildfly"16RUN echo "=> Adding administrator user"17RUN $JBOSS_HOME/bin/add-user.sh -u $WILDFLY_USER -p $WILDFLY_PASS --silent18 19RUN echo "=> Starting WildFly server" && \20 bash -c '$JBOSS_HOME/bin/standalone.sh &' && \21 echo "=> Waiting for the server to boot" && \22 bash -c 'until `$JBOSS_CLI -c ":read-attribute(name=server-state)" 2> /dev/null | grep -q running`; do echo `$JBOSS_CLI -c ":read-attribute(name=server-state)" 2> /dev/null`; sleep 1; done' && \23 echo "=> Downloading PostgreSQL driver" && \24 curl -k --location --output ./postgresql-${POSTGRESQL_VERSION}.jar --url https://repo1.maven.org/maven2/org/postgresql/postgresql/${POSTGRESQL_VERSION}/postgresql-${POSTGRESQL_VERSION}.jar && \25 echo "=> Adding PostgreSQL module" && \26 $JBOSS_CLI --connect --command="module add --name=org.postgresql --resources=./postgresql-${POSTGRESQL_VERSION}.jar --dependencies=javax.api,javax.transaction.api" && \27 echo "=> Adding PostgreSQL driver" && \28 $JBOSS_CLI --connect --command="/subsystem=datasources/jdbc-driver=postgresql:add(driver-name=postgresql,driver-module-name=org.postgresql,driver-class-name=org.postgresql.Driver,driver-xa-datasource-class-name=org.postgresql.xa.PGXADataSource)" && \29 echo "=> Adding main Datasource" && \30 $JBOSS_CLI --connect --command="data-source add \31 --name=PostgresDS \32 --jndi-name=java:jboss/datasources/PostgresDS \33 --user-name=${DB_USER} \34 --password=${DB_PASS} \35 --driver-name=postgresql \36 --connection-url=jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME} \37 --use-ccm=false \38 --blocking-timeout-wait-millis=5000 \39 --enabled=true" && \40 echo "=> Shutting down WildFly and Cleaning up" && \41 $JBOSS_CLI --connect --command=":shutdown" && \42 rm -rf $JBOSS_HOME/standalone/configuration/standalone_xml_history/ $JBOSS_HOME/standalone/log/* && \43 rm -f ./*.jar44 45EXPOSE 8080 9990 500546 47CMD ["/opt/jboss/wildfly/bin/standalone.sh", "-b", "0.0.0.0", "-bmanagement", "0.0.0.0", "--debug", "*:5005"]
The following ports are exposed:
8080
for the application9990
for the admin console5005
for debugging
Remember to specify the correct datasource in your project’s persistence.xml
file:
1<persistence-unit name="...">2 <jta-data-source>java:jboss/datasources/PostgresDS</jta-data-source>3 ...4</persistence-unit>
Docker Compose #
For the docker-compose file, there are two services required:
- The modified Wildfly image with Timescale support, as seen above
- The Timescale instance
Both services are fully configurable through environment variables and are able to communicate using Docker’s bridge networks. Here’s the full docker-compose.yml
:
1version: "2" 2 3services: 4 wildfly: 5 container_name: "wildfly" 6 build: 7 context: . 8 dockerfile: Dockerfile 9 environment:10 - WILDFLY_USER=admin11 - WILDFLY_PASS=password12 - DB_NAME=sample-db13 - DB_USER=postgres14 - DB_PASS=postgres15 - DB_HOST=db16 - DB_PORT=543217 depends_on:18 - db19 volumes:20 - ./workdir/deploy/wildfly/:/opt/jboss/wildfly/standalone/deployments/:rw21 ports:22 - "8080:8080"23 - "9990:9990"24 - "5005:5005"25 26 db:27 container_name: "db"28 image: "timescale/timescaledb:latest-pg13"29 environment:30 - POSTGRES_DB=sample-db31 - POSTGRES_USER=postgres32 - POSTGRES_PASSWORD=postgres33 volumes:34 - ./workdir/db/init/:/docker-entrypoint-initdb.d/35 - ./workdir/db/data/:/var/lib/postgresql/36 ports:37 - "5432:5432"38 39networks:40 default:41 driver: bridge
Note that:
- Wildfly image is automatically fetched from the
Dockerfile
, which should be in the same folder as thedocker-compose.yml
- Thanks to docker’s volume mapping, you can add
.war
files in theworkdir/deploy/wildfly
and they will be deployed to Wildfly automatically - Database data is persisted in the
workdir/db
folder even when the container is destroyed. However, remember to sethibernate.hbm2ddl.auto
property toupdate
in yourpersistence.xml
file, in order to avoid losing your data between launches.
To start the services, simply run docker-compose up
from any terminal instance.
Enabling TimescaleDB Hypertables in Java #
First, create a class named CustomPostgreSQLDialect
that extends PostgreSQL95Dialect
and registers the OTHER
sql type as a String
:
1import org.hibernate.dialect.PostgreSQL95Dialect;2import java.sql.Types;3 4public class CustomPostgreSQLDialect extends PostgreSQL95Dialect { 5 public CustomPostgreSQLDialect() {6 super();7 registerHibernateType(Types.OTHER, String.class.getName());8 }9}
This is required since Timescale’s create_hypertable return value is not natively supported by Hibernate. If you skip this step, you’ll most likely end up with an error such as:
javax.persistence.PersistenceException: org.hibernate.MappingException: No Dialect mapping for JDBC type: 1111
Then, specify CustomPostgreSQLDialect
as the Hibernate dialect in your project’s persistence.xml
file:
1<persistence-unit name="...">2 <properties>3 ...4 <property name="hibernate.dialect" value="CustomPostgreSQLDialect"/> 5 ...6 </properties>7</persistence-unit>
Finally, enable TimescaleDB extension on the database and then create the hypertable:
1// Enable TimescaleDB extension2entityManager.createNativeQuery("CREATE EXTENSION IF NOT EXISTS timescaledb;").executeUpdate();3 4// Create hypertable5String result = entityManager.createNativeQuery(6 "SELECT create_hypertable('YOUR_TABLE_HERE', 'YOUR_TIME_COLUMN_HERE')"7).getSingleResult().toString();8 9LOGGER.info(String.format("Result: %s", result));
If all went well, you should see something like this in the logs:
Result: (1,public,YOUR_TABLE_HERE,t)
For more details on hypertables refer to the offical TimescaleDB documentation.
References #
- TimescaleDB
- Docker-Test_DevEnv project by BrizziB
- Creating a Wildfly Docker image with PostgreSQL by mikesir87