A first Clojure app on OpenShift

Steve Citron-Pousty came to introduce RedHat’s OpenShift to the Clojure dojo at Liverpool GeekUp recently. I decided to put a couple of demonstration apps together so people at the dojo could get started.

A really quick start is to create a Noir web app.  This is based on a great post by Siscia Tech but updated because OpenShift has a little a bit since that was written. The full code for my take on Siscia’s app is available on my GitHub account here.

First things first

If you don’t already have a free OpenShift account then you need to sign up. Once you’ve created an account you should then install the command line tools for your system. You will also need the git command. That is installed with some of the command line tools downloads from OpenShift or you may have to install it yourself.

Finally, we’re going to use leiningen to help build our Clojure applications. Download the script from the website as it describes and make sure it is executable. Once downloaded, type:
/path/to/lein
in a terminal window and leiningen will self-install, downloading all the necessary jar files.

Creating an app

Once you’ve installed the tools you’ll have a command named rhc. You get help by typing: rhc help in a terminal window.

Clojure isn’t a supported language in OpenShift so we’re going to use a DIY cartridge for our application. To create an app called ‘examplenoir’ we use the command:
rhc app create -a examplenoir -t diy
it will ask you for your password then you should see something like:

Using diy-0.1 (Do-It-Yourself) instead of 'diy'
Creating application 'examplenoir'
==================================
Namespace: holgate
 Gear Size: default
 Cartridge: diy-0.1
 Scaling: no
Your application's domain name is being propagated worldwide (this might take a
minute)...
Cloning into 'examplenoir'...
done
examplenoir @ http://examplenoir-holgate.rhcloud.com/
=====================================================
 Application Info
 ================
 Gear Size = small
 UUID = 2773e93681c64b30807d869e4d1e2925
 Created = 12:11 PM
 SSH URL =
ssh://2773e93681c64b30807d869e4d1e2925@examplenoir-holgate.rhcloud.com
 Git URL =
ssh://2773e93681c64b30807d869e4d1e2925@examplenoir-holgate.rhcloud.com/~/git/exa
mplenoir.git/
 Cartridges
 ==========
 diy-0.1
RESULT:
Application examplenoir was created.
Disclaimer: This is an experimental cartridge that provides a way to try
unsupported languages, frameworks, and middleware on Openshift.

At this point you can clone the code into your local workspace (which we will refer to as ‘MY_WORKSPACE’) with git using the URL given in the output from your ‘create’ command. So for this case we have:
git clone ssh://2773e93681c64b30807d869e4d1e2925@examplenoir-holgate.rhcloud.com/~/git/examplenoir.git/

Cloning into 'examplenoir'...
remote: Counting objects: 25, done.
remote: Compressing objects: 100% (21/21), done.
remote: Total 25 (delta 1), reused 25 (delta 1)
Receiving objects: 100% (25/25), 7.48 KiB, done.
Resolving deltas: 100% (1/1), done.

which will create a directory named ‘examplenoir’. Change directory into your app:
cd examplenoir
and list the contents:
ls

README diy misc

Because we created a DIY app, our code is going to be created in the ‘diy’ directory. So change into that folder then we’ll use leiningen to create a new web app based on noir.

First though, you’ll see two files in the ‘diy’ directory that OpenShift provides by default. We don’t need them so you can delete them.
cd diy
ls

index.html testrubyserver.rb

rm -f testrubyserver.rb index.html

Now create our noir web app, which we will again call ‘examplenoir’
lein new noir examplenoir
This creates a working project template for us. If we change directory again we can see what has been created:
cd examplenoir/
ls

README.md project.clj resources src test

For now, we don’t need to worry what these files and directories are for, except that everything we need for a our basic application is right here. We can run this with:
lein run
and you should see:

Starting server...
2013-01-31 17:38:23.403:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
2013-01-31 17:38:23.404:INFO::jetty-6.1.25
Server started on port [8080].
You can view the site at http://localhost:8080
#<Server Server@75e13ce3>
2013-01-31 17:38:23.472:INFO::Started SocketConnector@0.0.0.0:8080

As it says, you can just open up your web browser to http://localhost:8080 to see the page.

Screen Shot of web browser showing page at localhost:8080

Screen Shot of web browser showing page at localhost:8080

Modifying the app

Before we can deploy the application to OpenShift, we need to make a couple of minor changes. Firstly we need to tell OpenShift how to start and stop a Clojure application and set some environment variables. Then we need to add leiningen to our application so that it can run Clojure. Finally, we have to modify the code to pick up the environment variables that tell the built-in webserver (jetty) where to run.

The start and stop scripts are stored in ‘.openshift/action_hooks/’ which is under the top-level of the application (where we initially cloned it):
cd $MY_WORKSPACE/examplenoir/
ls -a

. .git .openshift misc
.. .gitignore README diy

Then edit ‘.openshift/action_hooks/start’ so that it reads as follows:
#!/bin/bash
# The logic to start up your application should be put in this
# script. The application will work only if it binds to
# $OPENSHIFT_INTERNAL_IP:8080
# save as .openshift/action_hooks/start
export HTTP_CLIENT="wget --no-check-certificate -O"
export PORT=$OPENSHIFT_INTERNAL_PORT
export HOST=$OPENSHIFT_INTERNAL_IP
export HOME=$OPENSHIFT_DATA_DIR/home
export LEIN_JVM_OPTS=-Duser.home=$HOME
export APPDIR="examplenoir"
export LEIN_REPL_HOST=$HOST
cd $OPENSHIFT_REPO_DIR/diy/$APPDIR
$OPENSHIFT_REPO_DIR/bin/lein deps
$OPENSHIFT_REPO_DIR/bin/lein run >${OPENSHIFT_DIY_LOG_DIR}/lein.log 2>&1 &
disown

Now edit ‘.openshift/action_hooks/stop’ so that it reads:
#!/bin/bash
# The logic to stop your application should be put in this script.
# save as .openshift/action_hooks/stop
kill `ps -ef | grep 'clojure' | grep -v 'grep clojure' | awk '{ print $2 }'` >${OPENSHIFT_DIY_LOG_DIR}/stop.log 2>&1
exit 0

Next we need to add leiningen. Again in the top-level directory of the application, make a sub-directory named ‘bin’ and add the leiningen script and make it executable:
cd $MY_WORKSPACE/examplenoir/
mkdir bin
cd bin
curl https://raw.github.com/technomancy/leiningen/stable/bin/lein > lein
chmod +x lein

Finally we need to edit the Clojure code. Normally jetty runs on the localhost (127.0.0.1) on port 8080. On OpenShift, we have to use the $OPENSHIFT_INTERNAL_IP and $OPENSHIFT_INTERNAL_PORT instead. These are set as environment variables in the startup script and aliased to $HOST and $PORT. We just need to alter the server code:
cd $MY_WORKSPACE/examplenoir/diy/examplenoir/src/examplenoir
ls

models server.clj views

Now edit ‘server.clj’ with your favourite editor and add the ‘host’ line and ‘jetty-options’ so that it reads:
(ns examplenoir.server
(:require [noir.server :as server]))
(server/load-views-ns 'examplenoir.views)
(defn -main [& m]
(let [mode (keyword (or (first m) :dev))
port (Integer. (get (System/getenv) "PORT" "8080"))
host (get (System/getenv) "HOST" "127.0.0.1")]
(server/start port {:mode mode
:ns 'examplenoir
:jetty-options {:host host}})))

Deployment

Having made all these changes we now need to tell git to update the repository. Running:
git commit -a
should open up a text editor where you can add something like:

Initial commit

We are now ready to deploy the application to OpenShift:

git push

Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 548 bytes, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: restart_on_add=false
remote: Done
remote: restart_on_add=false
remote: Running .openshift/action_hooks/pre_build
remote: Running .openshift/action_hooks/build
remote: Running .openshift/action_hooks/deploy
remote: hot_deploy_added=false
remote: Downloading Leiningen to /var/lib/openshift/2773e93681c64b30807d869e4d1e2925/app-root/data//home/.lein/self-installs/leiningen-2.0.0-standalone.jar now...
remote: --2013-01-31 13:09:34-- https://leiningen.s3.amazonaws.com/downloads/leiningen-2.0.0-standalone.jar
remote: Resolving leiningen.s3.amazonaws.com... 72.21.195.98
remote: Connecting to leiningen.s3.amazonaws.com|72.21.195.98|:443... connected
remote: HTTP request sent, awaiting response... 200 OK
remote: Length: 13227743 (13M) [application/java-archive]
remote: Saving to: `/var/lib/openshift/2773e93681c64b30807d869e4d1e2925/app-root/data//home/.lein/self-installs/leiningen-2.0.0-standalone.jar.pending'
remote:
remote: 0K .......... .......... .......... .......... .......... 0% 7.19M 2s

<snip>

remote: 12900K .......... ....... 100% 10.5M=3.0s
remote:
remote: 2013-01-31 13:09:37 (4.26 MB/s) - `/var/lib/openshift/2773e93681c64b30807d869e4d1e2925/app-root/data//home/.lein/self-installs/leiningen-2.0.0-standalone.jar.pending' saved [13227743/13227743]
remote:
remote: Retrieving org/clojure/clojure/1.4.0/clojure-1.4.0.pom from central

<snip>

remote: Done
remote: Running .openshift/action_hooks/post_deploy
To ssh://2773e93681c64b30807d869e4d1e2925@examplenoir-holgate.rhcloud.com/~/git/examplenoir.git/
bd64a1d..2e1d6aa master -> master

All being well, after we’ve given jetty a minute or two to start running we should be able to open up our browser on our apps page (accessible through the OpenShift web console) and see the same Noir page as before:

Screen Shot of the examplenoir app deployed on OpenShift

Screen Shot of the examplenoir app deployed on OpenShift

And there is our first cloud deployed app!

Let me know if I’ve missed anything and I’ll do my best to help.

About these ads

About simonholgate

I'm CEO of Sea Level Research Ltd (www.sealevelresearch.com) - a Liverpool, UK based startup that uses machine learning to predict sea level surges and optimise shipping movements into and out of port. I'm an oceanographer and I'm also a Clojure developer who is interested in democracy and Big Data.
This entry was posted in Clojure, openshift and tagged , , , , . Bookmark the permalink.

2 Responses to A first Clojure app on OpenShift

  1. Dmitri says:

    Nice article, just a note that Noir has now been deprecated (http://blog.raynes.me/blog/2012/12/13/moving-away-from-noir/), and the current recommended approach is to use Compojure/Ring combination. All the good stuff from Noir, such as sessions, validation, etc. is still available via lib-noir which is being actively developed.

    One nice thing about Noir was that it provided a good template with batteries included. I’ve been working on a similar template and documentation for the above combination which is available here http://www.luminusweb.net/

    • simonholgate says:

      Thanks for the comment, Dmitri. Yes, I was aware of Noir being deprecated but it made a very easy way of demonstrating an app in a couple of lines. As you say, batteries were included :) I’ll definitely take a look at your Ring/Compojure template. Maybe I’ll post an example using that approach as well.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s