Sunday, May 23, 2010

Creating On-Demand Demonstration Sites for Java Based Systems using EC2

If you have developed web-based Java systems and are a small time shop, you will have encountered the issue of how to showcase your work given the relatively higher costs of Java hosting compared to Ruby, PHP and Python (Google App Engine). Did I mention the inexperience of many shops that try to provide Java hosting outside of Virtual Private Servers? Ever counted how many times you need to restart Tomcat when debugging deployment? After recently attending an Amazon Web Services meetup (where I got 50$ in AWS credit), I decided to give it a go.

The Requirements
The application in question has the following specs:
  1. Runs on Java 1.5+, Apache Tomcat 5.5.x+
  2. MySql
In addition to these 'undemanding' technical requirements, I've decided the following for prospective users of my system:
  • Demos should only be created when a propsective client requests them. I only want to pay when a real opportunity is present.
  • Prospective clients are to have individual instances. No sharing of instances or data.
  • Prospective clients are to have unlimited time trials. Their test data should also be retained should they chose to go ahead with using the system.
  • Provisioning of new instances should be automated with no human actions required (except of course the prospective client request).
I've managed to get it working with the following architecture:



As can be seen from above, the user requests an instance from my website. A request is sent using a PHP library for EC2 to create an instance based on a prepared image stored in Amazon S3. The user can then access this instance [n] through its public dns once the instance is up and running. Sounds simple enough?

The details for getting all this up and running is very involving and writing a tutorial for all the steps would be quite consuming given the information for this already exists elsewhere. What I will outline here are links to the tutorials and web resources I used to get this going and point out some of the challenges I faced i.e. things not pointed out in the tutorials and generally problems I had with the implementation.

Creating an Amazon AWS Account
This is off course the easiest part of the setup. Here's a presentation by Simone Brunozzi (AWS Evangelist) on how to sign up. I suggest playing around with EC2 instances before carrying on and Elastic Fox is an excellent Firefox plugin which you can use to manage your instances. When I was working on this, ElasticFox did not come preconfigured with the APAC region. This is easily fixed. Other minor stumbles include changing the permissions for the .pem files (chmod 0600 ...) otherwise ssh won't use the key to connect to the instances (Another gripe I had was the fact that the wizard for launching an instance on ElasticFox is to big to display on my MacBook even at top resolution).

Preparing your AMI Image
Hopefully by now you are familiar with what an AMI image is. Here's an excellent tutorial(which links to an existing Fedora 8 image with almost everything required to run java) on how to prepare your image on EC2. I opted to have MySql storing the information on the instance instead of on a Elastic Block Storage device because it is expected that the instances will be running for the life of the user trial. This is a simplification I chose otherwise I would need to have an EBS for each instance which is an excessive complication. However, should the instance terminate unexpectedly, the user would lose their data.

The MySql database for my application is created using a script that is 120MB. It has a lot of sample data. I uploaded it using Cyberduck for MacOS using SFTP.

Creating an S3 Bucket
S3 is AWS simple storage service. You need to have a bucket created. You need to make a decision as to which availability zone you want to run your instance from because buckets are not shared between instances. The image referred to in the preparing your AMI image tutorial is available in the us regions whereas I wanted to have my instance running of the newly minted Singapore region. I used the S3 Fox Organizer plugin to create my bucket and its a nice plugin overall to manage your S3 storage.

Automating the Creation of Instances
Once you are happy with the Image, you need a way of remotely creating instances. My website is currently running on Joomla! so I needed a PHP way of doing this. There is a PHP client library as part of the sample code and it works like a charm as well as provides sample code. For my purposes I only needed to execute the "runInstances" command to create the instance and the "describeInstances" command to check the status of the machine and get the public dns of the site in order to create the url to show the user.

Create Instance

  1. include_once ('/<path-to-the-ec2-library>/Amazon/EC2/Samples/.config.inc.php');
  2. $service = new Amazon_EC2_Client(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
  3. try
  4. {
  5. $response = $service->runInstances(array('ImageId' => '<your-image-id>', 'MinCount' => '1', 'MaxCount' => '1'));
  6. if ($response->isSetRunInstancesResult()) {
  7. $runInstancesResult = $response->getRunInstancesResult();
  8. if ($runInstancesResult->isSetReservation()) {
  9. $reservation = $runInstancesResult->getReservation();
  10. $runningInstanceList = $reservation->getRunningInstance();
  11. $instance_id = 'NA';
  12. foreach ($runningInstanceList as $runningInstance) {
  13. if ($runningInstance->isSetInstanceId())
  14. {
  15. $instance_id = $runningInstance->getInstanceId();
  16. $state = 'pending';
  17. $response = $service->describeInstances(array('InstanceId' => $instance_id));
  18. if ($response->isSetDescribeInstancesResult()) {
  19. $describeInstancesResult = $response->getDescribeInstancesResult();
  20. $reservationList = $describeInstancesResult->getReservation();
  21. foreach ($reservationList as $reservation) {
  22. $runningInstanceList = $reservation->getRunningInstance();
  23. foreach ($runningInstanceList as $runningInstance) {
  24. if ($runningInstance->isSetInstanceState()) {
  25. $instanceState = $runningInstance->getInstanceState();
  26. $state = $instanceState->getName();
  27. if ($runningInstance->isSetPublicDnsName())
  28. {
  29. }
  30. }
  31. }
  32. }
  33. }
  34. }
  35. }
  36. }
  37. }
  38. }
  39. catch (Amazon_EC2_Exception $ex)
  40. {
  41. echo("Caught Exception: " . $ex->getMessage() . "
  42. ");
  43. echo("Response Status Code: " . $ex->getStatusCode() . "
  44. ");
  45. echo("Error Code: " . $ex->getErrorCode() . "
  46. ");
  47. echo("Error Type: " . $ex->getErrorType() . "
  48. ");
  49. echo("Request ID: " . $ex->getRequestId() . "
  50. ");
  51. echo("XML: " . $ex->getXML() . "
  52. ");
  53. exit();
  54. }
Line 8 is where the instance is created. Line 33 and 36 get the state of the created instance and the public dns name respectively. I've experienced wait periods of up to 5 minutes from creating the instance to when its fully up and running, therefore you need to find a way of either doing this check asynchronously. It was a touch of irony, when my first thought was to execute a "popen" call so that the process could run in the background, only to discover "popen" is disabled by my current hosting providers. How long till I move my website to run on its own EC2 instance where I can do whatever I want?

1 comment:

Mike Bailey said...

Thanks for sharing your initial experiences with EC2. Have you thought about how to retire instances?