samedi 13 juin 2015

Running Java applications on CloudFoundry

Introduction

CloudFoundry v2 uses Heroku buildpacks to package droplet on which an application will run. But before, CF checks among the locally available buildpacks which one can be used to prepare the application runtime. The buildpack contract is composed of the following scripts (that can be written in shell, python, ruby, etc):
  • Detect: checks if this buildpack is suitable for the submitted application,
  • Compile: prepares the runtime environment of the application,
  • Release: finally launches the application

Applications with single file

Java applications whether a standalone or web are managed by the java-buildpack. In case a manifest.yml is used to submit the application, then for Web applications or executable jar it may looks like:
---
applications:
- name: APP_NAME
  memory: 4G
  disk_quota: 2G
  timeout: 180
  instances: 1
  host: APP_NAME-${random-word}
  path: /path/to/war/file.war or /path/to/executable/file.jar

The java-buildpack will check if the file is a .war to launch Tomcat container, or an executable jar to look for the mainClass in META-INF/MANIFEST.MF.

Applications with many files

In case the application is composed of multiple files (jars, assets, configs, etc.) the java-buildpack won't be able to automatically detect what appropriate container to use. We need:
1. For the Detect phase to choose which container is appropriate (here the java-main): Clone the java-buildpack and set the java_main_class property in config/java_main.yml.

2. In the manifest: indicate the path to the folder containing all artifacts that should be download  to the droplet at the Compile phase.

3. In the manifest: set the command that will be used at the Release phase to launch the application. 

An example of java_main.yml file:
---
java_main_class: package.name.ClassName

An example of a manifest.yml file:
---
applications:
- name: APP_NAME
  memory: 2G
  timeout: 180
  instances: 1
  host: APP_NAME-${random-word}
  path: ./
  buildpack: http://url/to/custom/java-buildpack
  command: $PWD/.java-buildpack/open_jdk_jre/bin/java -cp $PWD/*:. -Djava.io.tmpdir=$TMPDIR package.name.ClassName

Application submission

$ cf push to submit an application
$ cf logs APP_NAME to access the application logs
$ cf events APP_NAME to access CF events related to this application
$ cf files APP_NAME to access the VCAP user home where the application files are stored

Troubleshooting

If the application fails to start for some reason (you may see no logs), you can check what command was used to launch the application as follows:
$ CF_TRACE=true cf app app_name | grep "detected_start_command"

Note 
  • Uploaded jar files are extracted under /home/vcap/app/APP_NAME in the droplet.
  • for executable jar, we need to accept traffic on the port given by CF which is in the VCAP_APP_PORT environment variable. Otherwise CF will think that the application has failed to start and thus shut it down.
  • to check if a java program is running on CloudFoundry:
import org.cloudfoundry.runtime.env.CloudEnvironment;
...
CloudEnvironment cloudEnvironment = new CloudEnvironment();
if (cloudEnvironment.isCloudFoundry()) {
    // activate cloud profile      
    System.out.println("On A cloudfoundry environment");
}else {
    System.out.println("Not on A cloudfoundry environment");
}

Resources:
  • Standalone (non-web) applications on Cloud Foundry - link