Docker Configuration Guide

Introduction

This guide walks through the process of embedding Tomorrow Software into a CI/CD pipeline and creating a containerized deployment. It is assumed that the reader is familiar with the basic steps of deploying configurations within Tomorrow Software and understands the basic concepts of Docker and Jenkins.

The Tomorrow Software console provides a proprietary integrated solution development environment including version management of all repositories (rulesets, configurations, content files etc.) created within the console. As a result, Tomorrow Software will retain the ‘source’ mastering responsibility and the process described below does not implement a traditional source code repository solution for driving CI/CD pipelines.

Traditional Pipeline

Build pipelines are typically initiated via changes to the source code repository using triggers on check-in or merge requests.

Tomorrow Software Integrated Pipeline

The Tomorrow Software console provides sandpit functionality for local rapid solution development configuration and testing. Locally defined service endpoints are used to interface with the delivery pipeline.

Deployment Overview

A predefined server definition within the Tomorrow Software console is used to stage a release candidate. Whereas the traditional operational model is to push the configuration directly to a remote (production) endpoint, the staged candidate is stored locally on the console server. A command (CLI) function is provided to package the staged release in a format that can be incorporated into a container image.

The process described in this document details the steps to create a JBoss/WildFly container with the running Tomorrow Software configuration based on a server definition called UATServer1. By having “functional environment” named servers the console can manage the specific configuration such as credentials that may differ as candidates are promoted through environments.

Jenkins Plugins Used

  • HTTP Request – calls the Tomorrow Software console CLI interface

  • Ant – creates the Tomorrow Software WAR file

Deployment process pseudocode

  1. Pass the Tomorrow Software server name into pipeline as a parameter

  2. Create deployment structure in workspace

  3. Call Tomorrow Software console CLI function to get home location of console.

  4. Copy required configuration files into workspace

  5. Retrieve deployment configuration using console CLI function

  6. Edit Tomorrow Software configuration files with target parameters

  7. Build WAR file

  8. Build Docker image

Tomorrow Software Configuration – JBoss/WildFly

Create the Tomorrow Software Server Definition

The first step is to create a server definition in the Tomorrow Software Console for the target (UATServer1) server.

Once the server has been created, deploy the BaseWebTrial example configuration. This will publish the default configuration files to the file system and provides a known starting point to verify files are correctly included and propagated into the container.

#ls -la
total 20124
drwxrwxr-x.  4 tomorrow tomorrow     4096 Sep 14 20:21 .
drwxr-xr-x. 10 tomorrow tomorrow     4096 Sep 14 20:17 ..
-rw-r--r--.  1 tomorrow tomorrow     4092 Sep 14 20:21 ActiveRules.xml
drwxr-xr-x.  3 tomorrow tomorrow       31 Sep 14 20:21 backups
-rw-r--r--.  1 tomorrow tomorrow     4753 Sep 14 20:21 BasicWebLister.xml
-rw-r--r--.  1 tomorrow tomorrow     4092 Sep 14 20:21 BasicWebTrial.xml
-rw-r--r--.  1 tomorrow tomorrow    33584 Sep 14 20:21 errors.properties
-rw-r--r--.  1 tomorrow tomorrow 20539238 Sep 14 20:21 GeoLiteCity.dat
drwxr-xr-x.  3 tomorrow tomorrow     4096 Sep 14 20:21 resources

Pipeline Stage 1 - Extract

The first pipeline stage prepares the workspace and prepares all files. Two Tomorrow Software console CLI commands are executed, getInstallLocation and getServerHome. The first returns the absolute folder path that the console server is installed; the second command returns a zip-file with the deployed server contents

stage('Extract from Console') {
steps {
echo 'Stage1 – Prepare and Extract from Console'
script {
def dockerDir = "${env.WORKSPACE}/docker"
def scriptServer="http://localhost/console/ScriptRunner"
def usr = "admin"
def pwd = "admin"
sh "rm -rf ${dockerDir}"
sh "mkdir ${dockerDir}"
sh "mkdir ${dockerDir}/configuration"
sh "mkdir ${dockerDir}/jars"
sh "mkdir ${dockerDir}/war"
def getInstallHomeCmd = "puts \" [getInstallLocation ]\" "
response = httpRequest httpMode: 'POST',
contentType: 'APPLICATION_FORM',
url: "${scriptServer}",
requestBody: "user=${usr}&password=${pwd}&script=${getInstallHomeCmd}"
def consoleHomeValue = response.content
sh "cp ${consoleHomeValue}/BaseApp/appname/WEB-INF/web.xml ${dockerDir}/configuration"
sh "cp ${consoleHomeValue}/BaseApp/appname/WEB-INF/classes/magic.properties ${dockerDir}/configuration"
sh "cp ${consoleHomeValue}/BaseApp/appname/WEB-INF/lib/magic-10.0.jar ${dockerDir}/jars"
sh "cp ${consoleHomeValue}/BaseApp/appname/WEB-INF/lib/magic-10.0.jar ${dockerDir}/jars"
sh "cp ${consoleHomeValue}/server/lib/jdbc/derby/derby.jar ${dockerDir}/jars"
def deployZip = "${env.WORKSPACE}/${params.SERVER}.zip"
def tempDeployZip = "${consoleHomeValue}/server/temp/${params.SERVER}.zip"
def getServerHomeCmd = "set tmp \"[getServerHome ${params.SERVER} ${tempDeployZip} ]\" "
response = httpRequest httpMode: 'POST',
contentType: 'APPLICATION_FORM',
url: "${scriptServer}",
requestBody: "user=${usr}&password=${pwd}&script=${getServerHomeCmd}"
sh "mv ${tempDeployZip} ${deployZip} "
unzip zipFile: "${deployZip}", dir: "${dockerDir}/Tomorrow", quiet: true
}
}

Pipeline Stage 2 - Configure

Stage 2 involves updating the magic.properties file to set the target home directory, autostart and the admin port details.

stage('Update Config Files') {
steps {
echo 'Stage2 - Update Config Files'
script {
sh "sed -i \"s|homeDir=.*\$|homeDir=//Tomorrow//${params.SERVER}//|g\" ${env.WORKSPACE}/docker/configuration/magic.properties"
sh "sed -i \"s|autoStart=.*\$|autoStart=true|g\" ${env.WORKSPACE}/docker/configuration/magic.properties"
sh "sed -i \"s|port=.*\$|port=9990|g\" ${env.WORKSPACE}/docker/configuration/magic.properties"
}
}
}

Pipeline Stage 3 – WAR File

The third stage involves wrapping the config and jar files into a WAR file for deployment into the web-application server. Ant is used to build the WAR and it is driven by an XML file generated from within the pipeline script.

stage('Build WAR File') {
steps {
echo 'Stage3 - Build WAR File'
script {
def wL1 = "<?xml version=\"1.0\" ?><project name=\"InlineFilter\" default=\"war\"><target name=\"war\" >"
def wL2 = "<war destfile=\"./TomorrowInlineFilter.war\" webxml=\"../configuration/web.xml\">"
def wL3 = "<lib dir=\"../jars\"><include name=\"magic-10.0.jar\"/></lib>"
def wL4 = "<lib dir=\"../jars\"><include name=\"derby.jar\"/></lib>"
def wL5 = "<classes dir=\"../configuration\"><include name=\"magic.properties\"/></classes>"
def wL6 = "</war></target></project>"
writeFile file: "./docker/war/InlineFilterBuild.xml", text: "${wL1}${wL2}${wL3}${wL4}${wL5}${wL6}"
def antVersion = 'Ant1.9.4'
withEnv( ["ANT_HOME=${tool antVersion}"] ) {
sh "$ANT_HOME/bin/ant -buildfile ./docker/war/InlineFilterBuild.xml"
}
}
}
}

Pipeline Stage 4 – Docker Image

The fourth stage in this pipeline example creates a Docker image from the configured files using the repository tag tomorrow/jboss. The Dockerfile used to construct the image is dynamically generated from the Jenkins pipeline script.

stage('Build Docker Image') {
steps {
echo 'Stage3 - Build WAR File'
script {
def dL1 = "FROM jboss/wildfly"
def dL2 = "ADD ./war/TomorrowInlineFilter.war /opt/jboss/wildfly/standalone/deployments/"
def dL3 = "RUN /opt/jboss/wildfly/bin/add-user.sh admin abc123ABC## --silent"
def dL4 = "USER root"
def dL5 = "RUN mkdir /Tomorrow"
def dL6 = "RUN chmod 777 /Tomorrow"
def dL7 = "ADD ./Tomorrow /Tomorrow"
writeFile file: "./docker/dockerfile", text: "${dL1}\r\n${dL2}\r\n${dL3}\r\n${dL4}\r\n${dL5}\r\n${dL6}\r\n${dL7}"
}
sh 'docker build -t tomorrow/jboss ./docker/'
}
}

Validate Docker Image

Following successful pipeline execution. The image tomorrow/jboss is available.

#docker image list
REPOSITORY    TAG       IMAGEID        CREATED             SIZE
tomorrow/jboss     latest    b1491713e153   21 minutes ago      826MB

Verify the image runs correctly with the Tomorrow Software WAR file installed

#docker run tomorrow/jboss
=========================================================================
  JBoss Bootstrap Environment
  JBOSS_HOME: /opt/jboss/wildfly
  JAVA: /usr/lib/jvm/java/bin/java
  JAVA_OPTS:  -server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman -Djava.awt.headless=true  --add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED --add-exports=jdk.unsupported/sun.reflect=ALL-UNNAMED --add-modules=java.se
=========================================================================
01:27:28,176 INFO  [org.jboss.modules] (main) JBoss Modules version 1.9.0.Final

01:27:35,592 INFO  [org.jboss.as.clustering.infinispan] (ServerService Thread Pool -- 74) WFLYCLINF0002: Started client-mappings cache from ejb container
01:27:35,756 INFO  [org.wildfly.extension.undertow] (ServerService Thread Pool -- 75) WFLYUT0021: Registered web context: '/TomorrowInlineFilter' for server 'default-server'
01:27:35,868 INFO  [org.jboss.as.server] (ServerService Thread Pool -- 43) WFLYSRV0010: Deployed "TomorrowInlineFilter.war" (runtime-name : "TomorrowInlineFilter.war")
01:27:35,946 INFO  [org.jboss.as.server] (Controller Boot Thread) WFLYSRV0212: Resuming server

A final sanity check to ensure that the deployed BasicWebTrial configuration is correctly deployed in the /Tomorrow folder of the image and matches the original software folder investigated.

#docker exec -i 12ad580d409c ls -la /Tomorrow
total 20120
drwxrwxrwx.  3 root root     4096 Sep 15 01:00 .
drwxr-xr-x. 17 root root     4096 Sep 15 01:27 ..
-rw-rw-r--.  1 root root     4092 Sep 15 01:00 ActiveRules.xml
-rw-rw-r--.  1 root root     4753 Sep 15 01:00 BasicWebLister.xml
-rw-rw-r--.  1 root root     4092 Sep 15 01:00 BasicWebTrial.xml
-rw-rw-r--.  1 root root 20539238 Sep 15 01:00 GeoLiteCity.dat
-rw-rw-r--.  1 root root    33584 Sep 15 01:00 errors.properties
drwxrwxr-x.  3 root root       19 Sep 15 01:00 resources
#cat HOME/UATServer1/ActiveRules.xml | grep ^version
version="2019-09-14 20:21:34.197"
#docker exec -i 12ad580d409c cat /Tomorrow/ActiveRules.xml | grep ^version
version="2019-09-14 20:21:34.197"

Including a Database Driver

Where a configuration needs to connect to an external database, the JDBC driver file will need to be included into the Pipeline Stage-3 (WAR File) and a shell command to move the file from the configuration base directory to the staging folder.

The following example shows the updates required to include a Postgres JDBC driver as part of the build process.

Include the EDB driver as a Data File into the configuration as per below.

As part of the extract from console function the JDBC jar file needs to be included and copied to the target jars directory and then added to the WAR file create task.

// move the JDBC driver out of the way
sh "mv ${dockerDir}/Tomorrow/edb-jdbc18.jar ${dockerDir}/jars"

def wL1 = "<?xml version=\"1.0\" ?><project name=\"InlineFilter\"

def wL4_jdbc = "<lib dir=\"../jars\"><include name=\"edb-jdbc18.jar\"/></lib>"

writeFile file: "./docker/war/InlineFilterBuild.xml", text: "${wL1}${wL2}${wL3}${wL4}${wL4_jdbc}${wL5}${wL6}"

Last updated

General Website Terms & Conditions and Privacy Policy

Terms of UsePrivacy Policy

Contact Us

Get Help

© Copyright TomorrowX 2024 Composable Architecture Platform and Connected Agile are trademarks and servicemarks of TomorrowX .