Hosting your SBT-built Java project on RedHat’s OpenShift platform
If you’re more of an OpenShift than Heroku fan, here’s how you can get your SBT-built Java project onto OpenShift. OpenShift has fewer dynos (“gears”) at the free tier (only 3) but they idle after 24 hours instead of 1, and you get 1gb of disk storage to play with. They’ve also got a wide number of supported technologies you can run, be they languages, databases or servers. And “You could do OpenShift now and Docker will be our container tech in the new release this year” says @TheSteve0.
You’ll need a DIY cartridge, and an SBT-built Java project which uses the SBT native packager (like this one here).
OpenShift uses a set of action hooks to control what happens when you perform a Git Push. The problem is that SBT uses directories all over the filesystem and you’ll end up with the following errors when pushing a normal SBT project.
remote: Building git ref 'master', commit d66a2bd remote: java.io.IOException: No such file or directory remote: at java.io.UnixFileSystem.createFileExclusively(Native Method) remote: at java.io.File.createNewFile(File.java:1006) remote: at xsbt.boot.Locks$.apply0(Locks.scala:34) remote: at xsbt.boot.Locks$.apply(Locks.scala:28) remote: at xsbt.boot.Launch.locked(Launch.scala:238) remote: at xsbt.boot.Launch.app(Launch.scala:147) remote: at xsbt.boot.Launch.app(Launch.scala:145) remote: at xsbt.boot.Launch$.run(Launch.scala:102) remote: at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35) remote: at xsbt.boot.Launch$.launch(Launch.scala:117) remote: at xsbt.boot.Launch$.apply(Launch.scala:18) remote: at xsbt.boot.Boot$.runImpl(Boot.scala:41) remote: at xsbt.boot.Boot$.main(Boot.scala:17) remote: at xsbt.boot.Boot.main(Boot.scala) remote: Error during sbt execution: java.io.IOException: No such file or directory remote: An error occurred executing 'gear postreceive' (exit code: 1) remote: Error message: CLIENT_ERROR: Failed to execute action hook 'build' for 123456789abcdef application xyz |
To build your SBT application, you’ll need an .openshift/action_hooks/build file containing
#!/bin/bash cd $OPENSHIFT_REPO_DIR mkdir -p $OPENSHIFT_REPO_DIR/openshift_fakehome ./sbt -Duser.home=$OPENSHIFT_REPO_DIR/openshift_fakehome clean stage |
This tells SBT to use a different (and writeable) home directory within the repository.
To start the DropWizard application, your .openshift/action_hooks/start file should contain
#!/bin/bash nohup $OPENSHIFT_REPO_DIR/target/universal/stage/bin/your_app_name_here -Ddw.server.connector.bindHost=$OPENSHIFT_DIY_IP -Ddw.server.connector.port=$OPENSHIFT_DIY_PORT server $OPENSHIFT_REPO_DIR/config/local.yml & echo $! > $OPENSHIFT_REPO_DIR/pid.pid |
This binds the DropWizard service to the IP and port that the DIY cartridge requires you to bind to. We also store the process ID of this so we can kill it later.
And to kill the process (eg as part of a new git push), your .openshift/action_hooks/stop file should contain
#!/bin/bash source $OPENSHIFT_CARTRIDGE_SDK_BASH echo Killing PID $(cat $OPENSHIFT_REPO_DIR/pid.pid) kill $(cat $OPENSHIFT_REPO_DIR/pid.pid) rm $OPENSHIFT_REPO_DIR/pid.pid exit 0 |
This reads the process ID to kill from the file and removes the file.
My only issue at the moment is that my Git Push frequently times out.
... log snipped ... remote: [info] Compiling 9 Java sources to /var/lib/openshift/xyz/app-root/runtime/repo/target/scala-2.10/classes... remote: [info] Main Java API documentation to /var/lib/openshift/xyz/app-root/runtime/repo/target/scala-2.10/api... Connection to abc-xyz.rhcloud.com closed by remote host. fatal: The remote end hung up unexpectedly |
This requires me to push a new commit to kickstart the build. My SSH session to the same box is also disconnected at the same time, so I don’t know what happens there.