{"id":197,"date":"2010-03-10T06:01:03","date_gmt":"2010-03-10T06:01:03","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2010\/03\/10\/running-java-ee-applications-on-amazon-ec2\/"},"modified":"2025-02-01T22:48:57","modified_gmt":"2025-02-01T22:48:57","slug":"running-java-ee-applications-on-amazon-ec2","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/running-java-ee-applications-on-amazon-ec2\/","title":{"rendered":"How to Run\/Deploy Java EE applications on Amazon EC2?"},"content":{"rendered":"<h1><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-4109 aligncenter\" src=\"http:\/\/www.scmgalaxy.com\/tutorials\/wp-content\/uploads\/2010\/03\/java-ee-applications-on-ama.png\" alt=\"running-java-ee-applications-on-amazon-ec2\" width=\"600\" height=\"400\" srcset=\"https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2010\/03\/java-ee-applications-on-ama.png 600w, https:\/\/www.devopsschool.com\/blog\/wp-content\/uploads\/2010\/03\/java-ee-applications-on-ama-300x200.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/h1>\n<h1>Running Java EE applications on Amazon EC2: deploying to 20 machines with no money down<\/h1>\n<p>Computer hardware has traditionally been a scarce, expensive resource. In the early days of computing developers had to share a single machine. Today each developer usually has their own machine but it\u2019s rare for a developer to have more than one. This means that running performance tests often involves scavenging for machines. \u00a0Likewise, replicating even just part of a production environment is a major undertaking. With <a href=\"http:\/\/www.amazon.com\/gp\/browse.html?node=201590011\" target=\"_blank\" rel=\"noopener\">Amazon\u2019s Elastic Compute Cloud (EC2)<\/a>, however, things are very different. A set of Linux servers is now just a web service call away. Depending on the <a href=\"http:\/\/www.amazon.com\/gp\/browse.html?node=370375011\" target=\"_blank\" rel=\"noopener\">type of the servers<\/a> you simply pay 10-80 cents per server per hour for up to 20 servers! No more upfront costs or waiting for machines to be purchased and configured.<\/p>\n<p>To make it easier for enterprise Java developers to use EC2, I have created EC2Deploy.\u00a0 It\u2019s a Groovy framework for deploying an enterprise Java application on a set of Amazon EC2 servers. EC2Deploy provides a simple, easy to use API for launching a set of EC2 instances; configuring MySQL, Apache and one or more Tomcat servers; and deploying one or more web applications. In addition, it can also run JMeter and collect performance metrics.<\/p>\n<p>Here is an example script that launches some EC2 instances; configures MySQL with one slave, Tomcat and Apache; deploys a single web application on the Tomcat server; and runs a JMeter test with first one thread and then two.<\/p>\n<pre>class ClusterTest extends GroovyTestCase {<\/pre>\n<pre>\u00a0 void testSomething() {<\/pre>\n<pre>\u00a0\u00a0\u00a0 AWSProperties awsProperties = new<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 AWSProperties(\"\/\u2026\/aws.properties\")<\/pre>\n<pre><\/pre>\n<pre>\u00a0\u00a0\u00a0 def ec2 = new EC2(awsProperties)<\/pre>\n<pre><\/pre>\n<pre>\u00a0\u00a0\u00a0 def explodedWar = '\u2026\/projecttrack\/webapp\/target\/ptrack'<\/pre>\n<pre><\/pre>\n<pre>\u00a0\u00a0\u00a0 ClusterSpec clusterSpec =<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new ClusterSpec()<\/pre>\n<pre>\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.schema(\"ptrack\", [\"ptrack\": \"ptrack\"],<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [\"src\/test\/resources\/testdml1.sql\",<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"src\/test\/resources\/testdml2.sql\"])<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .slaves(1)<\/pre>\n<pre>\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.tomcats(1)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .webApp(explodedWar, \"ptrack\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .catalinaOptsBuilder({builder, databasePrivateDnsName -&gt;<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.arg(\"-Xmx500m\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"com.sun.management.jmxremote\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"com.sun.management.jmxremote.port\", 8091)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0 builder.prop(\"com.sun.management.jmxremote.authenticate\",<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 false)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0builder.prop(\"com.sun.management.jmxremote.ssl\", false)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"ptrack.application.environment\", \"ec2\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"log4j.configuration\",<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"log4j-minimal.properties\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"jdbc.db.server\", databasePrivateDnsName)})<\/pre>\n<pre><\/pre>\n<pre>\u00a0\u00a0\u00a0 SimpleCluster cluster = new SimpleCluster(ec2, clusterSpec)<\/pre>\n<pre><\/pre>\n<pre>\u00a0\u00a0\u00a0 cluster.loadTest(\"\u2026\/projecttrack\/functionalTests\/jmeter\/SimpleTest.jmx\",<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [1, 2])<\/pre>\n<pre><\/pre>\n<pre>\u00a0\u00a0\u00a0 cluster.stop()<\/pre>\n<pre>\u00a0 }<\/pre>\n<pre>}<\/pre>\n<p>Let\u2019s look at each of the pieces.<\/p>\n<p>First, we need to configure the framework as follows:<\/p>\n<pre>\u00a0\u00a0\u00a0 AWSProperties awsProperties = new<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 AWSProperties(\"\/\u2026\/aws.properties\")<\/pre>\n<pre>\u00a0\u00a0\u00a0 def ec2 = new EC2(awsProperties)<\/pre>\n<p>The aws.properties file contains various properties including the Amazon WS security credentials and the EC2 AMI (i.e. OS image) to launch. All servers use my EC2 appliance AMI that has Java, MySQL, Apache, Tomcat, Jmeter and some other useful tools pre-installed.<\/p>\n<p>Next we need to configure the servers:<\/p>\n<pre>\u00a0\u00a0\u00a0\u00a0 ClusterSpec clusterSpec =<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 new ClusterSpec()<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .schema(\"ptrack\", [\"ptrack\": \"ptrack\"],<\/pre>\n<pre>\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0[\"src\/test\/resources\/testdml1.sql\",<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"src\/test\/resources\/testdml2.sql\"])<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .slaves(1)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0.tomcats(1)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0.webApp(explodedWar, \"ptrack\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0.catalinaOptsBuilder({builder, databasePrivateDnsName -&gt;<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.arg(\"-Xmx500m\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"com.sun.management.jmxremote\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"com.sun.management.jmxremote.port\", 8091)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0 builder.prop(\"com.sun.management.jmxremote.authenticate\",<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 false)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0builder.prop(\"com.sun.management.jmxremote.ssl\", false)<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"ptrack.application.environment\", \"ec2\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0builder.prop(\"log4j.configuration\",<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"log4j-minimal.properties\")<\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 builder.prop(\"jdbc.db.server\", databasePrivateDnsName)})<\/pre>\n<pre><\/pre>\n<pre>\u00a0\u00a0\u00a0\u00a0 SimpleCluster cluster = new SimpleCluster(ec2, clusterSpec)<\/pre>\n<p>This code first creates a ClusterSpec, which defines the configuration of the machines and the applications:<\/p>\n<ul>\n<li>schema() \u2013 specifies the name of the database schema to create; names of the users and their passwords; the DML scripts to execute once the database has been create<\/li>\n<li>slaves() \u2013 specifies how many MySql slaves to create<\/li>\n<li>tomcats() &#8211; specifies how many Tomcats to run.<\/li>\n<li>webApp() &#8211; configures a web application. This method takes two parameters: the path to the exploded WAR directory (conveniently created by Maven) and the context to deploy the web application under.<\/li>\n<li>catalinaOptsBuilder() \u2013 supplies a closure that takes a builder and the DNS name of the MySQL server as arguments and returns the CATALINA_OPTS used to launch Tomcat. It\u2019s primary purpose is to configure the web application(s) to use the correct database server<\/li>\n<\/ul>\n<p>It then creates a cluster with that specification.<\/p>\n<p>We then start the cluster:<\/p>\n<pre>\u00a0\u00a0\u00a0 cluster.start()<\/pre>\n<p>At this point EC2Deploy will:<\/p>\n<ol>\n<li>Launch the EC2 instances running my appliance AMI.<\/li>\n<li>Initialize the MySql master database<\/li>\n<li>Create the MySql slave<\/li>\n<li>Create the database schema and the users<\/li>\n<li>Run any DML scripts (these are cached on S3 in a bucket called \u201ctmp&#8211;dml\u201d for the reasons described next)<\/li>\n<li>Upload the web applications to <a href=\"http:\/\/www.amazon.com\/gp\/browse.html?node=16427261\" target=\"_blank\" rel=\"noopener\">Amazon S3 (Simple Storage Service)<\/a> where they are cached in order to avoid time consuming uploads (over slow DSL connections, for example). EC2Deploy only uploads new and changed files, which means that the bulky 3<sup>rd<\/sup> party libraries are only uploaded once. Each web application is stored in an S3 bucket called -tmp-war. If this bucket does not exist you will see some warning messages and the bucket will be created.<\/li>\n<li>Deploy the web applications on each of the Tomcat servers<\/li>\n<li>Configure Apache to load balance across the Tomcat servers<\/li>\n<\/ol>\n<p>Once the cluster is started we can run a JMeter load test:<\/p>\n<pre>\u00a0\u00a0\u00a0 cluster.loadTest(\"\u2026\/projecttrack\/functionalTests\/jmeter\/SimpleTest.jmx\", [1, 2])<\/pre>\n<p>The first argument specifies the test to run and the second argument is a list of JMeter thread counts. In this example, EC2deploy first runs the load test with one thread and then two threads. For each test run, it generates a report describing CPU utilization for each machine, average response time and throughput.<\/p>\n<p>Finally, we stop the EC2 instances:<\/p>\n<p>cluster.stop()<\/p>\n<p>As you can see, EC2Deploy makes it pretty easy to deploy and test your enterprise Java application. I\u2019ve used it to clone a production environment and run load tests. NOTE 1\/28\/08: The source code EC2Deploy along with a very cool Maven plugin is now <a href=\"http:\/\/www.chris-richardson.blog-city.com\/ec2deploy_and_the_cloud_tools_maven_plugin_are_now_available.htm\" target=\"_blank\" rel=\"noopener\">available<\/a> !<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Running Java EE applications on Amazon EC2: deploying to 20 machines with no money down Computer hardware has traditionally been a scarce, expensive resource. In the early days of computing developers had to share a single machine. Today each developer usually has their own machine but it\u2019s rare for a developer to have more than&#8230;<\/p>\n","protected":false},"author":1,"featured_media":4109,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_joinchat":[],"footnotes":""},"categories":[5633],"tags":[3354,310,162,3357,3359,365,1122,3113,3361,3360,1806,173,3353,3358,3356,562,938,3355,213],"class_list":["post-197","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aws","tag-amazon-ec2","tag-application","tag-aws","tag-deploy","tag-deploy-java-ee-app-on-amazon-ec2","tag-ec2deploy","tag-guide","tag-how-to","tag-how-to-deploe-java-ee-app-on-ec2","tag-how-to-run-java-ee-app-on-ec2","tag-instruction","tag-java","tag-java-ee","tag-java-ee-app-on-ec2","tag-java-ee-application-on-amazon-ec2","tag-push","tag-reference","tag-run-java-ee-applications-on-amazon-ec2","tag-tutorial"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/197","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=197"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/197\/revisions"}],"predecessor-version":[{"id":4110,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/197\/revisions\/4110"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/4109"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=197"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=197"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=197"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}