Wednesday, September 24, 2014

Deploying a Clojure app to Bluemix as a WAR file using the WebSphere Liberty buildpack

In a previous blog post, I talked about running a Clojure web app on IBM Bluemix using the Heroku buildpack for Clojure. This isn't the only way that you can run Clojure code on Bluemix, though. In this post, I'll talk about running the same Hello World application using the WebSphere Liberty Buildpack. This buildpack is built in to Bluemix and has the ability to run a web application, in this case packaged as a WAR file.

To begin, let's clone the Hello Clojure app from GitHub:
$ git clone git@github.com:cdpjenkins/hello-clojure.git
Cloning into 'hello-clojure'...
remote: Counting objects: 22, done.
Receiving objects: 100% (22/22), done.
Resolving deltas: 100% (5/5), done.
remote: Total 22 (delta 0), reused 0 (delta 0)
Checking connectivity... done.
This is the same Hello World app that featured in the previous blog post with one addition made to the project.clj:
(defproject hello-clojure "0.1.0-SNAPSHOT"
:description "FIXME: write description"
  :url "http://example.com/FIXME"
  :dependencies [[org.clojure/clojure "1.5.1"]
                 [compojure "1.1.6"]
                 [javax.servlet/servlet-api "2.5"]]
  :plugins [[lein-ring "0.8.11"]]
  :ring {:handler hello-clojure.handler/app
         :uberwar-name "hello-clojure.war"}
  :profiles
  {:dev {:dependencies [[ring/ring-jetty-adapter "1.1.0"]
                        [ring-mock "0.1.5"]]}}
  :min-lein-version "2.0.0")
I've added an uberwar-name key to the :ring section. This is the name of the generated WAR file that we'll generate. Also note that the version of lein-ring must be at least 0.8.11 in order to generate a conformant WAR in order to work with the Liberty buildpack.

Let's use the ring uberwar task to generate our WAR file.
$ lein ring uberwar
Created /Users/cdpj/GitProjects/hello-clojure/target/hello-clojure.war
END
Recall that an uberwar is a WAR file that bundles our webapp together with all of the dependencies.

Next, let's check that our Bluemix API endpoint is still set up from last time (IBMers using the internal Bluemix: your API endpoint won't be the same as this one):
$ cf login
API endpoint: https://api.ng.bluemix.net

Email> <snip>@uk.ibm.com

Password> 
Authenticating...
OK

Targeted org <snip>@uk.ibm.com

Targeted space dev     
API endpoint:   https://api.ng.bluemix.net (API version: 2.4.0)   
User:           <snip>@uk.ibm.com   
Org:            <snip>@uk.ibm.com   
Space:          dev   
Finally, it's a relatively simple matter to push our WAR to Bluemix. Note that this time, we don't use -b to specify a buildpack (since the WebSphere Liberty buildpack is built in to Bluemix). In addition, we use -p to specify the path of the artefact that we want to push, in this case the WAR file.
$ cf push hello-again-clojure -p target/hello-clojure.war 
Creating app hello-again-clojure in org <snip>@uk.ibm.com / space dev as <snip>@uk.ibm.com...
OK

Creating route hello-again-clojure.mybluemix.net...
OK

Binding hello-again-clojure.mybluemix.net to hello-again-clojure...
OK

Uploading hello-again-clojure...
Uploading app files from: target/hello-clojure.war
Uploading 5.2M, 812 files
OK

Starting app hello-again-clojure in org <snip>@uk.ibm.com / space dev as <snip>@uk.ibm.com...
OK
-----> Downloaded app package (5.0M)

-----> Liberty buildpack is starting to compile the droplet
-----> Buildpack Version: v1.4-20140908-1803
-----> Retrieving IBM 1.7.1 JRE (ibm-java-jre-7.1-1.0-pxa6470_27sr1fp2-20140828_01-sfj.tgz) ... (0.0s)
-----> Retrieving com.ibm.ws.liberty-2014.9.0.0-201409081803.tar.gz ... (0.0s)
         Installing archive ... (1.4s)
-----> Liberty buildpack has completed the compile step
-----> Uploading droplet (109M)

0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
0 of 1 instances running, 1 starting
1 of 1 instances running

App started

Showing health and status for app hello-again-clojure in org <snip>@uk.ibm.com / space dev as <snip>@uk.ibm.com...
OK

requested state: started
instances: 1/1
usage: 1G x 1 instances
urls: hello-again-clojure.mybluemix.net

     state     since                    cpu    memory         disk   
#0   running   2014-09-24 10:15:09 PM   0.0%   116.5M of 1G   149.4M of 1G   
That's it; the app is now running:
OK so once again, this isn't especially exciting but this process is equally applicable to larger and more complex applications as it is to the simple one that we deployed here. Using the WebSphere Liberty buildpack allows us to run our application on top of code that was specially designed for Bluemix and it allows us to build our application once, on the client, and then deploy the built application as one WAR file. Contrast this with the Heroku buildpack for Clojure which uploads Clojure source code to the server and then compiles it there. There is a third way to run Clojure on Bluemix, which is to build your app into a runnable jar file (together with an embedded web server such as Jetty). I might cover that briefly in a future blog post.

No comments: