Clojure on CloudFoundry

Fri 13 January 2012
  • 装备 tags:
  • clojure
  • cloudfoundry
  • web published: true comments: true

In this article, I will show you how to develop and deploy clojure web application on CloudFoundry. As you may know, CloudFoundry is an opensource PaaS backed by VMWare. Java, Ruby and Nodejs are officially supported. As a JVM language, clojure is born to be also available on this platform, although it's not listed.

CloudFoundry accepts a .war file for Java web application deployment. So you don't need the ring-jetty-adaptor and a procfile as heroku requires. To help your development and deployment, I strongly recommend the lein-ring plugin:

[cc lang="clojure"]
:dev-dependencies [[lein-ring "0.5.4"]]
[/cc]

CloudFoundry provides backend services like mysql, redis, mongodb and more. The connection information are stored as environment variables. Here you can find a subset of them.

Take mongodb as example, connection information (host, port, username and password) are encoded as JSON, stored in environment variables. You can get them with this function:
[cc lang="clojure"]
(defn mongo-config [key]
(if-let [services (System/getenv "VCAP_SERVICES")]
(let [services-dict (json/read-json services false)]
(-> services-dict
(get "mongodb-1.8")
first
(get "credentials")
(get key)))))
[/cc]

In the server bootstrap function, create the mongodb connection:
[cc lang="clojure"]
(defn app-init []
(def db-conn (make-connection
(or (mongo-config "db") "lazypress")
:host (or (mongo-config "hostname") "localhost")
:port (or (mongo-config "port") 27017)))
(when-not (nil? (mongo-config "username"))
(authenticate db-conn
(mongo-config "username")
(mongo-config "password")))
[/cc]
By adding check for nil, local databased is also supported. This is pretty convenience for local development. These environment variables are consistent on all cloudfoundry application, so it's possible to deploy the application on multiple accounts without any changes.

Then you can add your web stuff just like standard clojure web development. (If you are using compojure, place your static files under resource/public.)

Finally, package it. (Suppose your application is named as "lazypress")
[cc lang="bash"]
lein ring uberwar lazypress.war
[/cc]

Use the vmc tool to deploy it:
[cc lang="bash"]
vmc update lazypress
[/cc]

For more usage about the vmc tool, you can read this article.

So you have finished deploying your clojure web application to cloudfoundry.

Backed by spring and vmware, cloudfoundry is more Java-friendly than other PaaS like heroku. You don't have to start a Java process by yourself ("lein run" isn't a graceful way to start your app in product environment). And you don't have to worry about your web container settings (configure jetty with limited options via ring-jetty-adaptor). All you have to do is package the application as a portable war file, which you can deploy to tomcat, glassfish, and also cloudfoundry. The vmc tool could detect you war file and handle it correctly.