Fabio Maffioletti


09 Dec 2015

Deploy a Java 8 Spring Boot application on a DIY Openshift cartridge

As at the time of this writing Openshift DIY cartridge comes with OpenJDK Java 7 installed. During the migration of JSONDoc from AppFog to Openshift, I wanted to use Oracle Java 8 instead, so here are the steps I took to do that.

Have a Spring Boot application

I just created a very simple Spring Boot project with name bootjava8 in my workspace and added a rest controller in it.

package me.fabiomaffioletti.bootjava8;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class Bootjava8Application {

    public static void main(String[] args) {
        SpringApplication.run(Bootjava8Application.class, args);
    }

    @RestController
    static class Bootjava8Controller {

        @RequestMapping("/")
        public ResponseEntity<String> bootjava8() {
            return ResponseEntity.ok("I'm running on Oracle Java 8");
        }

    }
}

Create a DIY app on OpenShift

Precondition for this is that you have the rhc client installed. It's very easy to manage your applications with that. So, once you are ready, open a terminal, move to the /tmp directory and create an DIY application:

rhc create-app bootjava8 diy-0.1

You should see something like this on your shell:

Your application 'bootjava8' is now available.

  URL:        http://bootjava8-fabiomaffioletti.rhcloud.com/
  SSH to:     566982c489f5cfaac2000085@bootjava8-fabiomaffioletti.rhcloud.com
  Git remote: ssh://566982c489f5cfaac2000085@bootjava8-fabiomaffioletti.rhcloud.com/~/git/bootjava8.git/
  Cloned to:  /private/tmp/bootjava8

Now move to the the Spring application directory and add the remote OpenShift repository in this way:

git init
git remote add openshift -f ssh://566982c489f5cfaac2000085@bootjava8-fabiomaffioletti.rhcloud.com/~/git/bootjava8.git/

OpenShift will update the repository:

Updating openshift
remote: Counting objects: 25, done.
remote: Compressing objects: 100% (20/20), done.
remote: Total 25 (delta 1), reused 25 (delta 1)
Unpacking objects: 100% (25/25), done.
From ssh://bootjava8-fabiomaffioletti.rhcloud.com/~/git/bootjava8
 * [new branch]      master     -> openshift/master

Now you can merge from the OpenShift repository like this:

git merge openshift/master -s recursive -X ours

And as result in the project directory, there should be an .openshift directory, that is important, and some other directories (diy, misc) that you can delete or put into .gitignore.

Create OpenShift action hooks

Next step is to create three action hooks, that OpenShift will execute every time something is pushed to its git repository. I'll call them in this way:

  • build: to install Oracle Java 8 and Maven
  • start: to start the application
  • stop: to stop the application

Those action hooks will be created in the .openshift/action_hooks directory.

The build action hook

Copy the start action hook. Call it build.

cp .openshift/action_hooks/start .openshift/action_hooks/build

Edit the build action hook and put there the instructions to install Maven and Oracle Java 8:

#!/bin/bash
cd $OPENSHIFT_DATA_DIR

if [ ! -d apache-maven-3.3.3 ]; then
  wget http://www.eu.apache.org/dist/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz
  tar -zxf apache-maven-3.3.3-bin.tar.gz
fi

if [ ! -d jdk1.8.0_65 ]; then
  wget --no-check-certificate --no-cookies --header "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u65-b16/jdk-8u65-linux-i586.tar.gz
  tar -zxf jdk-8u65-linux-i586.tar.gz
fi

With these Maven and Oracle Java 8 will be installed in the $OPENSHIFT_DATA_DIR directory. The installation will run only the first time the project is pushed to the OpenShift git repository.

The start action hook

Next, edit the start action hook. This will set some environment variables and start the executable Spring Boot jar.

#!/bin/bash
export JAVA_HOME=$OPENSHIFT_DATA_DIR/jdk1.8.0_65
export PATH=$JAVA_HOME/bin:$PATH

$OPENSHIFT_DATA_DIR/apache-maven-3.3.3/bin/mvn -f $OPENSHIFT_REPO_DIR/pom.xml clean package -s $OPENSHIFT_REPO_DIR/.openshift/settings.xml

nohup java -jar -Dserver.port=${OPENSHIFT_DIY_PORT} -Dserver.address=${OPENSHIFT_DIY_IP} $OPENSHIFT_REPO_DIR/target/*.jar > ${OPENSHIFT_DIY_LOG_DIR}/bootjava8.log 2>&1 &

Create a file named settings.xml in the .openshift directory and put this content into it:

<settings>
    <localRepository>$OPENSHIFT_DATA_DIR</localRepository>
</settings>

This will tell OpenShift to use the $OPENSHIFT_DATA_DIR as Maven repository.

The stop action hook

Last action hook is the stop one. It contains instructions on how to stop the java process.

#!/bin/bash
source $OPENSHIFT_CARTRIDGE_SDK_BASH
PID=$(ps -ef | grep java.*\.jar | grep -v grep | awk '{ print $2 }')
if [ -z "$PID" ]
then
    client_result "Application is already stopped"
else
    kill $PID
fi

Push to the OpenShift remote

This is it. Whenever you push something on the openshift remote, the action hooks will be executed and the application will be stopped, built and started. Just create a .gitignore file. Mine contains:

.classpath
.mvn/
.project
.settings/
mvnw
mvnw.cmd
target/

And then add, commit and push to the openshift remote:

git add --all
git commit -m "Initial commit"
git push openshift master

The application will build, run its tests and start. It is possible to tail the logs by doing:

rhc tail bootjava8

That will output something like:

==> app-root/logs/bootjava8.log <==
2015-12-10 09:31:53.448  INFO 157638 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2015-12-10 09:31:53.843  INFO 157638 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-12-10 09:31:53.843  INFO 157638 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-12-10 09:31:54.038  INFO 157638 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2015-12-10 09:31:54.919  INFO 157638 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2015-12-10 09:31:55.329  INFO 157638 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2015-12-10 09:31:55.340  INFO 157638 --- [           main] m.f.bootjava8.Bootjava8Application       : Started Bootjava8Application in 17.702 seconds (JVM running for 19.629)
2015-12-10 09:32:12.568  INFO 157638 --- [129-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2015-12-10 09:32:12.568  INFO 157638 --- [129-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2015-12-10 09:32:12.709  INFO 157638 --- [129-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 140 ms

At the end the application will be available on http://bootjava8-fabiomaffioletti.rhcloud.com/

Resources

Source code is available here

comments powered by Disqus