The new standalone framework support greatly increases the number of different types of non-Web applications that can run on Cloud Foundry, including application servers. This tutorial will walk you through the steps to deploy a “hello world” application in a Tomcat 7 container on Cloud Foundry. Currently, Cloud Foundry leverages Tomcat 6 to host Java web applications. While the team is working to support Tomcat 7 as a first-class container, it is very straightforward to use the standalone application support to run Tomcat 7 in the meantime, which is particularly useful for applications that leverage Servlet 3.0. The basic outline involves installing your application into a local Tomcat 7 instance, making minor modifications to the configuration and pushing the entire contents of Tomcat 7 and your application to Cloud Foundry as a standalone application.
Step 1 – Download Apache Tomcat
Download Apache Tomcat 7 to the location where you will use the vmc command line tool. If you do not have vmc, then follow these instructions to install it. I downloaded Apache 7.0.27, which is currently the latest version 7.0 release and the file name is apache-tomcat-7.0.27.zip. All of the commands throughout this tutorial will assume that the present working directory is the Tomcat 7 base directory.
Step 2 – Extract Tomcat and Update Permissions
Extract the tomcat zip file to a local directory. I changed the permissions of the bin/*.sh scripts to have executable permissions.
unzip apache-tomcat-7.0.27.zip cd apache-tomcat-7.0.27 chmod +x bin/*.sh
Linux and OSX users should be able to test the scripts on their local systems before pushing them to Cloud Foundry’s Ubuntu-based server environment. Unfortunately, Windows users cannot test the bin/startup.sh script changes locally first, but the modifications are really quite simple.
Step 3 – Edit Startup Scripts
bin/startup.sh
Tomcat is typically started with the bin/startup.sh script. In order for Tomcat to use the same shell that invokes startup.sh instead of spawning a new shell, change the execution argument in the last line of startup.sh from “start
” to “run
“:
exec "$PRGDIR"/"$EXECUTABLE" start "$@"
to:
exec "$PRGDIR"/"$EXECUTABLE" run "$@"
bin/catalina.sh
Instead of using a pre-defined static port, we would like Tomcat 7 to use the port assigned by Cloud Foundry, which will be stored in the VCAP_APP_PORT
environment variable when deployed. Place the following bash code near the top of catalina.sh
after the initial comments. Just so that we can run this locally as well without modifying the code, this code will assign a static port number of 8080 if the dynamic port is not available as an environment variable.
# USE VCAP PORT IF IT EXISTS, OTHERWISE DEFAULT TO 8080 if [ -z ${VCAP_APP_PORT} ]; then export VCAP_APP_PORT=8080 fi export JAVA_OPTS="-Dport.http.nonssl=$VCAP_APP_PORT $JAVA_OPTS"
Step 4 – Edit Tomcat Configuration
conf/server.xml
Set the port attribute of the Server element to -1, which disables the Tomcat shutdown port. Cloud Foundry does not use the shutdown port because it issues a “kill -9 PID
” command to stop any standalone app instance. We want to avoid any potential port conflicts with other applications that are running on the same Droplet Execution Agent (DEA), so only using a single http port is the current recommendation for standalone applications running on Cloud Foundry.
Server port=”-1” command=”SHUTDOWN”
Since Cloud Foundry handles the load balancing for you without using the AJP connector, you should disable the AJP connector to ensure we do not get a port conflict by commenting out the section shown below.
Define an AJP 1.3 Connector on port 8009
The Connector element should use the port provided in the JAVA_OPTS
environment variable, which we have set previously in the catalina.sh script.
Connector port="${port.http.nonssl}" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"
At this point, I recommend trying the edits on your local server to see if Tomcat 7 starts up as expected. In order to test whether the VCAP_APP_PORT
is being used, I recommend using a command shell to assign a sample port such as 8082.
jbayer$ export VCAP_APP_PORT=8082 jbayer$ bin/startup.sh
The console should not return (it should block while Tomcat is running) and one of the last lines in the console output should be:
INFO: Starting ProtocolHandler ["http-bio-8082"]
If that is the case, you should be able to visit http://localhost:8082 to see if the welcome page is there.
At this point you may want to back up (zip) the entire Tomcat 7 directory with the customizations you have done thus far so you can reuse it on other applications later.
Step 5 – Install your application
In order to show a Tomcat 7 feature, I used Servlet 3.0 which now has support for Servlet annotations as shown below in the simple Servlet.
package tomcat7; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.*; @WebServlet("/Servlet3") public class Servlet3 extends HttpServlet { public Servlet3() { super(); } protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("Hello from Servlet 3.0!"); } }
Cloud Foundry uses the ROOT web application with Tomcat 6, so let’s replicate that same behavior for Tomcat 7.
First delete the existing ROOT
application.
jbayer$ rm –r webapps/ROOT
Now take your web application and explode it into the webapps/ROOT
location. If you have a .war file then the command looks like this:
jbayer$ unzip –d webapps/ROOT ~/dev/mytomcat7.war
Check your application locally to see if it functions properly.
Step 6 – Push the application to Cloud Foundry
Execute the vmc command from the Tomcat 7 base directory, selecting many of the default selections. Notice that vmc auto-detects that it is a “Standalone Application,” and you simply need to provide the startup script path and map an unique URL. Note that you will get an error if the URL is not unique.
jbayer$ vmc push mytomcat7 Would you like to deploy from the current directory? [Yn]: Detected a Standalone Application, is this correct? [Yn]: 1: java 2: node 3: node06 4: ruby18 5: ruby19 Select Runtime [java][/java]: 1 Selected java Start Command: bin/startup.sh Application Deployed URL [None]: mytomcat7.cloudfoundry.com Memory reservation (128M, 256M, 512M, 1G, 2G) [512M]: 256M How many instances? [1]: Bind existing services to 'mytomcat7'? [yN]: Create services to bind to 'mytomcat7'? [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 (23K): OK Push Status: OK Staging Application 'mytomcat7': OK Starting Application 'mytomcat7': OK
At the end of the push process, you will be offered the option to write the configuration to a manifest file. Here is the resulting manifest.mf file that got written to the Tomcat 7 base directory from our deployment. Note that it contains the startup command, bin/startup.sh
. By having this file present in the root directory vmc will read from this file and skip the interactive questions the next time you push this application.
--- applications: .: url: mytomcat7.cloudfoundry.com command: bin/startup.sh runtime: java framework: info: exec: description: Standalone Application mem: 64M name: standalone name: mytomcat7 instances: 1 mem: 256M
Conclusion
Other containers such as Jetty would follow a similar pattern as described above. Most applications should be able to use the existing frameworks Cloud Foundry makes available. Should the need arise to customize or bring your own container, Cloud Foundry standalone application support is a great option.
– James Bayer
The Cloud Foundry Team
Try Cloud Foundry on CloudFoundry.com for free