OpenShift Deployment


December 5, 2013 Maithilish

12.4. OpenShift Deployment

Even though, we developed a fairly complicated GWT application and deployed it to App Engine, surprisingly we never discussed about build cycle. Google Plugin for Eclipse (GPE) was building the application in background. But, when it comes to OpenShift, we have to build and deploy.
Steps to build a GWT application with JDO are
  • compile the java classes with javac.
  • enhance persistence classes with JDO Enhancer.
  • compile GWT module with GWT Compiler, which compiles java classes to JavaScript.
  • pack everything as a war archive and deploy it to app server.
There are a couple of ways for OpenShift Deployment; push the application source to OpenShift and build the application on server or; build the application locally and push the war to OpenShift.
Build on OpenShift

Recommended way to deploy the application is to push the source to OpenShift and then build the war on server. Source is pushed to server with

$ cd <app directory>
$ git commit -am "some change log"
$ git push
Cloned application folder contains a pom.xml, which contains a profile named openshift. When source is pushed to OpenShift, this profile is executed which builds the application and creates a war.
There are some difficulties to implement this.
  • profile in maven pom requires modifications to add JDO enhancer and GWT compile.
  • requires GWT SDK jars on server to compile the GWT module.
  • requires major changes to project directory structure to make it in line with maven project structure.
  • GWT complier requires heavy resources and OpenShift Small Gear is unable to handle this requirement as reported in OpenShift forums.
While the first three issues are manageable, the last one is difficult to overcome.
Build locally

Another way, which is easy to implement, is to build the project locally and then push the war to OpenShift.

We use Ant to build the project. Add the project build file – build.xml to Ant View which shows the following targets.
To compile classes, build requires GWT and GAE SDK and in build.xml, set the path to SDK on your system.
build.xml

        <!-- Configure path to GWT and GAE SDK - !! Change these !! -->
        <property name="gwt.sdk" location="/orange/apps/google/gwt/gwt-2.5.0" />
        <property name="gae.sdk" location="/orange/apps/google/gae/appengine-java-sdk-1.7.5" />

Target enhance enhances the persistence classes.
build.xml

        <target name="enhance" depends="javac" description="Enhance JDO">

                <!-- the classpath to enhance -->
                <path id="enhancer.classpath">
                        <path refid="project.lib.path" />
                        <path refid="project.class.path" />
                </path>

                <!-- define the task enhancer -->
                <taskdef name="nucleusenhancer" classpathref="enhancer.classpath" classname="org.datanucleus.enhancer.tools.EnhancerTask" />

                <!-- enhance -->
                <nucleusenhancer classpathref="enhancer.classpath" />

        </target>

Target gwtc compiles the GWT module using GWT complier.
build.xml

        <target name="gwtc" depends="javac,enhance" description="GWT compile to JavaScript">
                <java failonerror="true" fork="true" classname="com.google.gwt.dev.Compiler">
                        <classpath>
                                <pathelement location="src" />
                                <path refid="project.class.path" />
                                <path refid="project.lib.path" />
                                <path refid="gwt.sdk.path" />
                                <path refid="gwt.validation.path" />
                        </classpath>
                        <!-- add jvmarg -Xss16M if StackOverflowError -->
                        <jvmarg value="-Xmx256M" />
                        <!-- gwt args -->
                        <arg value="-war" />
                        <arg value="war" />
                        <!-- module -->
                        <arg line="in.fins.fins" />
                </java>
        </target>

All you have to do is to run target war, which builds the project and creates fins.war in project folder.
Deploy to OpenShift. To deploy the war to OpenShift execute following commands in cloned application folder – demo.

$ cd <cloned application folder - demo>
$ cp <workspace project dir>/fins.war webapps
$ git add webapps/fins.war
$ rm pom.xml
$ git rm pom.xml
$ git commit -am "project war added"
$ git push

From project directory fins.war is copied to webapps directory of demo folder (cloned application folder) and then a git add to update the git index. Next, we remove pom.xml to disable maven build on OpenShift. If this file exists, then OpenShift tries to build the application when code is pushed to server. Git commit updates the local repository with changes. Finally, git push uploads the changes and fins.war to OpenShift git repository.
Now Fins is accessible from http://demo-finsdemo.rhccloud.com/fins. To access fins from http://demo-finsdemo.rhccloud.com/ change the name of war to ROOT.war.

Git Revisions

Git Repository holds all revisions of war file, which may soon exhaust the 1GB storage limit. Clean up the Git repo, application’s logs and tmp directories to free up the space with

$ rhc app tidy demo

Scaled Applications

Fins demo application that we just created is a non-scaled application, to which OpenShift allots one Gear. When load increases, response may start to degrade. OpenShift allows application scaling, which provides for the automatic allocation of resources based on demand. When application is scaled, OpenShift adds a HAProxy cartridge to the application, which listens to incoming requests and pass on the request to web cartridge. When HAProxy detects overload, it alerts OpenShift, which starts a new web cartridge on a additional gear to handle the request.

Scaled application is created by passing -s to create action.

$ rhc app create demo jbossews-1.0 -s

Application type – Scaled or Non-Scaled, has to indicated at creation and it is not possible to convert from one to another once app is created.
MySQL cartridge is added to application as being done earlier. It is not possible to add phpMyAdmin to a scaled application. In scaled application, database cartridge gets it own dedicated gear.

$ rhc cartridge add mysql-5.1 -a demo

Scaled Application
Figure 12.3. Scaled Application


Initially, OpenShift allocates two gears to the scaled demo application. The first gear holds fins code, JBoss EWS cartridge and HAProxy cartridge, and the second gear holds MySQL cartridge. When load crosses certain threshold, it allots the third gear, which holds fins code and second instance of JBoss EWS and load is distributed between first and third gear.
There is no change in build and deployment process. In case, the war is named as fins.war then you need to modify haproxy.cfg file as follows.

$ rhc app ssh demo
> vi haproxy/conf/haproxy.cfg      // edit with vi editor

search for line option httpchk GET / and change it to option httpchk GET /fins . HAProxy uses this option to check the health of http server. If this is not proper, then app shows HAProxy Statistics Report, with a down local-gear. This change is not required if war is named as ROOT.war.
Restart the application with

$ rhc app restart demo

Next we set up Tomcat and Eclipse to develop the application locally.