Running Standalone Web Applications on Cloud Foundry

May 11, 2012 Jennifer Hickey

featured-cf-genericIn this final post of the four-part series on deploying standalone apps to Cloud Foundry, we will explore how to build and deploy JVM-based web applications that aren’t packaged as traditional WAR files. This includes applications that are built on top of an NIO Framework like Grizzly or Netty (notable frameworks include Blue Eyes and vert.x) and applications that ship their own container, such as an embedded Jetty server.

Deploying a Spray Application to Cloud Foundry

Spray is a suite of lightweight Scala libraries for building and consuming RESTful web services on top of Akka. Let’s deploy the Spray simple-http-server example that uses spray-can: a low-level, low-overhead, high-performance, fully asynchronous HTTP/1.1 server.

mycomp$: git clone git://github.com/spray/spray.git
mycomp$: cd spray/examples/spray-can/simple-http-server

We will use the sbt-package-dist plugin to package the app and all of its dependencies into a Zip file that we can push to Cloud Foundry. Therefore, we need to add the following files to the simple-http-server directory:

build.sbt:

import com.twitter.sbt._ seq(StandardProject.newSettings: _*) packageDistZipName := "simple-http-server.zip" organization := "cc.spray" name := "simple-http-server" version := "0.1.0-SNAPSHOT" scalaVersion := "2.9.1" resolvers ++= Seq( "Typesafe repo" at "http://repo.typesafe.com/typesafe/releases/", "spray repo" at "http://repo.spray.cc/" ) libraryDependencies ++= Seq( "cc.spray" % "spray-server" % "1.0-M1", "cc.spray" % "spray-can" % "1.0-M1", "com.typesafe.akka" % "akka-actor" % "2.0" )

project/plugins.sbt:

addSbtPlugin("com.twitter" %% "sbt-package-dist" % "1.0.0") resolvers += "twitter-repo" at "http://maven.twttr.com"

project/build.properties:

sbt.version=0.11.2

Next, we need to modify Main.scala to start the HTTP server on the host and port provided by Cloud Foundry:

server ! HttpServer.Bind(Option(System.getenv("VCAP_APP_HOST")).getOrElse("localhost"), Option(System.getenv("VCAP_APP_PORT")).getOrElse("8080").toInt)

Now we are ready to build and deploy the sample!

mycomp$: sbt clean compile package-dist
mycomp$: vmc push simple-http-server --path=dist/simple-http-server/simple-http-server.zip
Detected a Standalone Application, is this correct? [Yn]:
1: java
2: node
3: node06
4: ruby18
5: ruby19
Select Runtime [/java]:
Selected java
Start Command: java $JAVA_OPTS -jar simple-http-server_2.9.1-0.1.0-SNAPSHOT.jar
Application Deployed URL [None]: simple-http-server.${target-base}
Memory reservation (128M, 256M, 512M, 1G, 2G) [512M]:
How many instances? [1]:
Create services to bind to 'simple-http-server'? [yN]:
Would you like to save this configuration? [yN]: y
Manifest written to manifest.yml.
Creating Application: OK
Uploading Application:
Checking for available resources: OK 
Processing resources: OK
Packing application: OK
Uploading (248K): OK
Push Status: OK
Staging Application 'simple-http-server': OK
Starting Application 'simple-http-server': OK

So we’ve pushed the simple-http-server Zip file as a standalone app with a Java runtime. We gave the command “java $JAVA_OPTS -jar simple-http-server_2.9.1-0.1.0-SNAPSHOT.jar” to start the server, as sbt-package-dist creates an executable jar file. Notice the use of the JAVA_OPTS environment variable. When we deploy this app, Cloud Foundry will set JAVA_OPTS to a min and max heap size based on the memory reservation we provide. If we are running against Micro Cloud Foundry or a local vcap setup, remote debug options will also be added to JAVA_OPTS if we push or start the app with –debug.

That’s right, you can remote debug your standalone JVM applications with your favorite IDE. Since “simple-http-server” needs a web port, we provided a URL to use. Notice the use of the ${target-base} variable for the domain. This will allow us to reuse the generated manifest against multiple clouds (such as public or Micro Cloud Foundry). Let’s visit the web page and confirm that the app is up and running:

Looks like we are in business with spray! Note that you can access this complete example here.

Deploying an Embedded Jetty Server to Cloud Foundry

Since its launch, Cloud Foundry has allowed you to easily deploy a wide variety of web applications to Tomcat. We take care of configuring and starting the container, you bring the web app! However, sometimes you may want to bundle your own container or web server. Standalone app support allows you to do this. Let’s see an example using

Unfiltered, a toolkit for servicing HTTP requests in Scala. We will start by using giter8 to create a simple project template:

mycomp$: g8 softprops/unfiltered
This template generates an Unfiltered project. By default it depends on "unfiltered-jetty". For AJP support, set unfiltered_module to "unfiltered-jetty-ajp".
version [0.1.0-SNAPSHOT]:
name [My Web Project]:
cf-unfiltered-sample unfiltered_version [0.6.1]:
Applied softprops/unfiltered.g8 in cf-unfiltered-sample
mycomp$: cd cf-unfiltered-sample

We need to introduce the same sbt-package-dist build settings as the previous example. Add the following to the top of build.sbt:

 import com.twitter.sbt._ seq(StandardProject.newSettings: _*) packageDistZipName := "cf-unfiltered-sample.zip" 

And create the plugins.sbt and build.properties files in the project directory as outlined above. Finally, we need to modify Example.scala to start Jetty on the port provided by Cloud Foundry:

val http = unfiltered.jetty.Http(Option(System.getenv("VCAP_APP_PORT")).getOrElse("8080").toInt)

And we need to modify avsl.conf to write the log file to a location relative to the app’s working directory:

  [handler_h1] ... path: log ...

Now we are ready to build and deploy the sample!

mycomp$: sbt clean compile package-dist
mycomp$: vmc push cf-unfiltered-sample --path=dist/cf-unfiltered-sample/cf-unfiltered-sample.zip
Detected a Standalone Application, is this correct? [Yn]:
1: java
2: node
3: node06
4: ruby18
5: ruby19
Select Runtime

[/java] : Selected java Start Command: java $JAVA_OPTS -jar cf-unfiltered-sample_2.9.1-0.1.0-SNAPSHOT.jar Application Deployed URL [None]: cf-unfiltered-sample.${target-base} Memory reservation (128M, 256M, 512M, 1G, 2G) [512M]: How many instances? [1]: Create services to bind to 'cf-unfiltered-sample? [yN]: Would you like to save this configuration? [yN]: y Manifest written to manifest.yml. Creating Application: OK Uploading Application: Checking for available resources: OK  Processing resources: OK Packing application: OK Uploading (248K): OK Push Status: OK Staging Application 'cf-unfiltered-sample': OK Starting Application 'cf-unfiltered-sample': OK

The answers we gave here are pretty much identical to those given in the first section. We provisioned a Java runtime, provided a start command that includes JAVA_OPTS, and supplied a URL. Looks like the app is up!

You can check out this complete example here.

Conclusion

In this final installment of the four-part series, we introduced new support for standalone applications and showed some examples of common uses. We would love to hear your use cases and suggestions for enhancing this support. Please visit the Forums or JIRA, or submit a pull request. We look forward to seeing your new standalone apps!

– Jennifer Hickey The Cloud Foundry Team
Don’t have a Cloud Foundry account yet? Sign up for free today

About the Author

Biography

More Content by Jennifer Hickey
Previous
The Future of Web Design in London
The Future of Web Design in London

I'm very excited to head to London next week to speak Code Literacy for Designers at the always-excellent F...

Next
Xtreme Labs On Building Apps with Cascades at BlackBerry 10 Jam
Xtreme Labs On Building Apps with Cascades at BlackBerry 10 Jam

We were down in Orlando discussing building apps with BlackBerry Cascades with Christopher Smith, VP Handh...