Sunday, October 9, 2016

Change database without changing code using default datasource and Docker.

In this blog post we will consider the use case that we want to use different databases for our system but we don't want to change any line of code or any file in built application. In this example we will use a simple application with a REST interface. The source code is available on github https://github.com/andrzejszywala/hellojee

In persistence.xml we don't specify datasource so application will use default datasource which is provided by the container.
<persistence version="2.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
    xsi:schemalocation="http://xmlns.jcp.org/xml/ns/persistence
    http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="hellojee" transaction-type="JTA">
    <properties>
      <property name="javax.persistence.schema-generation.database.action" value="drop-and-create">
    </property></properties>
  </persistence-unit>
</persistence>

Now let's create first Dockerfile
FROM jboss/wildfly
ADD hellojee.war $JBOSS_HOME/standalone/deployments/hellojee.war

This Dockerfile extends jboss/wildfly image and adds hellojee.war to deployments directory. Next let's build and run the image
docker build -t andrzejszywala/hellojee .
docker run -d -p 8080:8080 --name hellojee andrzejszywala/hellojee
Open browser http://localhost:8080/hellojee/resources/hello and verify that the application works. In the response you should see json object with database name, host name and some sample data from Hello table.
{"database":"H2 - 1.3.173 (2013-07-28)","host":"597840afb246 (172.17.0.2)","hello": "Hello","Witaj","Hallo","Hej","Ahoj","Bonjour","Hola"]}
Stop container
docker stop hellojee
Now we will create docker image that connects to mysql databse. Dockerfile is available on https://github.com/andrzejszywala/docker-images/tree/master/hellojee/mysql
FROM jboss/wildfly
ADD customization $JBOSS_HOME
RUN /opt/jboss/wildfly/bin/jboss-cli.sh --file=/opt/jboss/wildfly/wildfly_conf.txt
# FIX for Error: WFLYCTL0056: Could not rename /opt/jboss/wildfly/standalone/configuration/standalone_xml_history/current...
RUN rm -rf /opt/jboss/wildfly/standalone/configuration/standalone_xml_history/current/*
ADD hellojee.war $JBOSS_HOME/standalone/deployments/hellojee.war
the most important part is wildfly_conf.txt file which configures mysql module and sets mysql datasource as default so wildfly will use it in our application.
embed-server --server-config=standalone.xml
batch
# add mysql module
module add --name=com.mysql --resources=/opt/jboss/wildfly/mysql-connector-java-5.1.34.jar --dependencies=javax.api,javax.transaction.api
# driver configuration
/subsystem=datasources/jdbc-driver=mysql:add(driver-name=mysql,driver-module-name=com.mysql,driver-xa-datasource-class-name=com.mysql.jdbc.jdbc2.optional.MysqlXADataSource)
# add new datasource
data-source add --name=mysqlDS --driver-name=mysql --jndi-name=java:jboss/datasources/MySQLDS --connection-url=jdbc:mysql://mysqldb:${env.DB_PORT}/sample?useUnicode=true&characterEncoding=UTF-8 --user-name=mysql --password=mysql --use-ccm=false --max-pool-size=25 --blocking-timeout-wait-millis=5000 --enabled=true
# set default datasource
/subsystem=ee/service=default-bindings:write-attribute(name="datasource", value="java:jboss/datasources/MySQLDS")
# Execute the batch
run-batch
reload
stop-embedded-server
quit
Note that mysql host name is mysqldb. This will be the name of the mysql container and after run containers in the same network we will be able to connect to the database. Now we can build docker image
docker build -t andrzejszywala/hellojee-mysql .
Create docker network
docker network create mynet
Run mysql container
docker run --name mysqldb --net mynet -e "MYSQL_ROOT_PASSWORD=mysql" -e "MYSQL_DATABASE=sample" -e "MYSQL_USER=mysql" -e "MYSQL_PASSWORD=mysql"-d mysql:latest
And finally run the application container
docker run -d -p 8080:8080 -e "DB_PORT=3306" --name hellojee-mysql --net mynet andrzejszywala/hellojee-mysql
Open browser http://localhost:8080/hellojee/resources/hello. You should see something like this:
{"database":"MySQL - 5.7.15","host":"8acd618e942e (172.20.0.3)","hello":["Hello","Witaj","Hallo","Hej","Ahoj","Bonjour","Hola"]}
As you can see database is MySQL. JEE 7 gives us ability to build once and deploy anywhere and if we do not go beyond standard we can easily change servers and databases. All files used in this blog post are available on github https://github.com/andrzejszywala/docker-images/tree/master/hellojee