Thursday 28 November 2013

Java WAR deployment options on AWS Elastic Beanstalk

Introduction

Elastic Beanstalk deployment is pretty cool for interpreted languages like Python, Ruby, or PHP where all you need to do is a "git aws.push" to deploy the latest version of your application. The AWS Toolkit for Eclipse is also great for Java deployments but what if you want to deploy a manually built WAR? This post lists a few of the options available. It assumes that you have already created an Elastic Beanstalk application using these instructions. The example uses an application name of war-test and a WAR file named sample.war (kindly provided by Apache Tomcat here).

Option 1 - AWS Console

Pretty simple, select your Beanstalk application and click the "Upload and Deploy" button. Select the WAR file and give it a version name, a few minutes later your new version is up and running.

In the background the file is uploaded to an S3 bucket, a new application version linked to the bucket/object and a deployment triggered.

Option 2 - Command line

This is pretty much the same approach as for the AWS Console upload except that you need to manually perform each of the steps using the AWS CLI tools.

Step 1: Find the S3 bucket to upload the file to, this can be done as follows:

aws elasticbeanstalk describe-application-versions --application-name war-test

Which will print something like:
{
    "ApplicationVersions": [
        {
            "ApplicationName": "war-test",
            "VersionLabel": "git-db96ef73b33ba5ae515907c586d133b26b3489b6-1385637920942",
            "Description": "First commit",
            "DateCreated": "2013-11-28T11:25:21.596Z",
            "DateUpdated": "2013-11-28T11:25:21.596Z",
            "SourceBundle": {
                "S3Bucket": "elasticbeanstalk-us-east-1-XXXXXX",
                "S3Key": "git-db96ef73b33ba5ae515907c586d133b26b3489b6-1385637920942.zip"
            }
        },
        {
            "ApplicationName": "war-test",
            "VersionLabel": "Sample Application",
            "SourceBundle": {
                "S3Bucket": "elasticbeanstalk-us-east-1",
                "S3Key": "GenericSampleApplication"
            },
            "DateUpdated": "2013-11-28T11:25:12.781Z",
            "DateCreated": "2013-11-28T11:25:12.781Z"
        }
    ]
}


You are interested in is the "elasticbeanstalk-us-east-1-XXXXXX" bucket (where XXXXXX represents your bucket identifier), use this as the destination for your WAR file. You can probably also use your own (custom bucket) but I have not checked what permissions are needed to allow Elastic Beanstalk to access the files.

Step 2: Copy your WAR file to the S3 bucket identified in Step 1. Using the CLI tools again:

aws s3 cp ./sample.war s3://elasticbeanstalk-us-east-1-XXXXXX/s3-sample.war

Step 3: Create an application version:

aws elasticbeanstalk create-application-version --application-name war-test --version-label s3-upload --source-bundle S3Bucket=elasticbeanstalk-us-east-1-XXXXXX,S3Key=s3-sample.war

Step 4: Identify the environment to update

aws elasticbeanstalk describe-environments --application-name war-test

Which returns something like:

{
    "Environments": [
        {
            "ApplicationName": "war-test",
            "EnvironmentName": "war-test-env",
            "VersionLabel": "git-dd7d815e8251acae3560158b169d652d66479bc1-1385644793798",
            "Status": "Ready",
            "EnvironmentId": "e-bwjydyebw9",
            "EndpointURL": "54.204.44.36",
            "SolutionStackName": "64bit Amazon Linux 2013.09 running Tomcat 7 Java 7",
            "CNAME": "war-test-env-bffkznzafh.elasticbeanstalk.com",
            "Health": "Green",
            "DateUpdated": "2013-11-28T13:20:51.828Z",
            "DateCreated": "2013-11-28T11:25:29.308Z"
        }
    ]
}


Note the value of the EnvironmentName (war-test-env in this example)

Step 5: Update the environment

aws elasticbeanstalk update-environment --environment-name war-test-env --version-label s3-upload

Which will return something like:


{
    "ApplicationName": "war-test",
    "EnvironmentName": "war-test-env",
    "VersionLabel": "s3-upload",
    "Status": "Updating",
    "EnvironmentId": "e-bwjydyebw9",
    "EndpointURL": "54.204.44.36",
    "SolutionStackName": "64bit Amazon Linux 2013.09 running Tomcat 7 Java 7",
    "CNAME": "war-test-env-bffkznzafh.elasticbeanstalk.com",
    "Health": "Grey",
    "DateUpdated": "2013-11-28T14:13:42.836Z",
    "DateCreated": "2013-11-28T11:25:29.308Z",
    "Resources": {}
}


Rerun step 4 until the Health reflects as "Green" which indicates your updated application has been deployed (but does not neccessarily mean it is working).


Option 3 - git aws.push

This is a bit of hack (storing compiled binary files in git) but is still quite cool:

Step 1: Unzip your WAR file into the directory that you ran "eb init" in

unzip sample.war -d war-test/

Step 2: Add and commit code to git (in the eb init directory again

cd war-test
git add .
git commit -m "Some comment" .

Step 3: Deploy

git aws.push

Conclusion

There are probably other ways of doing this, feel free to add a comment if you find a more elegant solution. Some of the approaches may also work with .NET applications although I have not tested them.