Automating Maven Project Deployments on AWS Elastic Beanstalk

Automating Maven Project Deployments on AWS Elastic Beanstalk

Maven on BeanstalkThis tutorial will show you how to use the ingenieux Beanstalker Maven Plugin to automate deployment of Maven Projects into Amazon Elastic Beanstalk. Apache Maven is a project management tool popular for Java Projects. Based on the concepts of Inversion of Control (IoC) and Convention over Configuration (CoC), it lets developers evolve project functionalities and behaviors with minimal effort, by storing the project metadata in a standard file format, the Project Object Model (POM), in a headless fashion, but compatible with all the major IDEs.

Ingenieux Beanstalker is a set of Maven Plugins for Amazon Elastic Beanstalk and Amazon Elastic MapReduce. As a Maven Plugin, it contains special classes (“mojos”) for interacting with the AWS Services.

Assumptions

This document assumes you’re familiar with the development of Java Web Applications (.war files) using Apache Maven from the Command Line Interface (CLI), as well as using the Elastic Beanstalk Service.

How Maven Projects Work

A Maven Project is a directory that contains a pom.xml file, declaring its coordinates. The minimum is the groupId (which is like a package name for an organization), an artifactId, a version number, an optional classifier and a packaging (defaults to “.jar”).

These are required in order to permit projects to be shared within an organization (aggregating or inheriting other ones) or even on the whole internet, via repositories like the Maven Central, as artifacts. Also, they can be installed into a cache of artifacts, the local repository, which is the directory .m2/repository on your user home directory.

In the next section, as an example, we will create the mywebapp project (which is the artifactId), with com.mycompany as its groupId, with 1.0-SNAPSHOT version, and it will have the war packaging.

Creating a Sample Project

Maven lets you employ a special kind of artifact (the “archetype” packaging) to help you bootstrap new projects. So let’s create a simple project to use. Of course, you can use your own existing project. You can use the archetype:generate mojo for that. This is an example transcription where I entered the values described previously, and simply accepted the defaults:

C:\projetos\workspaces\ingenieux>mvn archetype:generate -Dfilter=maven-archetype-webapp
[INFO] Scanning for projects…
[INFO] — maven-archetype-plugin:2.2:generate (default-cli) @ standalone-pom —
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: remote -> org.apache.maven.archetypes:maven-archetype-webapp (An archetype which contains a sample Maven Webapp project.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains):
: 1
Choose org.apache.maven.archetypes:maven-archetype-webapp version:
1: 1.0-alpha-1
2: 1.0-alpha-2
3: 1.0-alpha-3
4: 1.0-alpha-4
5: 1.0
Choose a number: 5: 5
Define value for property ‘groupId’: : com.mycompany
Define value for property ‘artifactId’: : mywebapp
Define value for property ‘version’: 1.0-SNAPSHOT: :
Define value for property ‘package’: com.mycompany: :
Confirm properties configuration:
groupId: com.mycompany
artifactId: mywebapp
version: 1.0-SNAPSHOT
package: com.mycompany
Y: :
[INFO] —————————————————————————-
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] —————————————————————————-
[INFO] Parameter: groupId, Value: com.mycompany
[INFO] Parameter: packageName, Value: com.mycompany
[INFO] Parameter: package, Value: com.mycompany
[INFO] Parameter: artifactId, Value: mywebapp
[INFO] Parameter: basedir, Value: C:\projetos\workspaces\ingenieux
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: C:\projetos\workspaces\ingenieux\mywebapp
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 43.684s
[INFO] Finished at: Fri Feb 24 02:32:11 GMT-03:00 2012
[INFO] Final Memory: 7M/17M
[INFO] ————————————————————————
C:\projetos\workspaces\ingenieux>

 ——————————————————————————————————————————–

So now we have created the mywebapp subdirectory with your new project contents. We can run the Jetty plugin, run a Tomcat, and test if it works:

C:\projetos\workspaces\ingenieux\mywebapp>mvn org.mortbay.jetty:jetty-maven-plugin::run
012-02-24 02:52:04.736:INFO:oejs.Server:jetty-8.1.1.v20120215
2012-02-24 02:52:04.905:INFO:oejpw.PlusConfiguration:No Transaction manager found – if your webapp requires one, please configure one.
2012-02-24 02:52:05.164:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/C:/projetos/workspaces/ingenieux/mywebapp/src/main/webapp/},file:/
C:/projetos/workspaces/ingenieux/mywebapp/src/main/webapp/
2012-02-24 02:52:05.165:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/C:/projetos/workspaces/ingenieux/mywebapp/src/main/webapp/},file:/
C:/projetos/workspaces/ingenieux/mywebapp/src/main/webapp/
2012-02-24 02:52:05.165:INFO:oejsh.ContextHandler:started o.m.j.p.JettyWebAppContext{/,file:/C:/projetos/workspaces/ingenieux/mywebapp/src/main/webapp/},file:/
C:/projetos/workspaces/ingenieux/mywebapp/src/main/webapp/
2012-02-24 02:52:05.231:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
 

Navigate to http://localhost:8080/ and you’ll see a “Hello World!” message. That said, let’s configure the project for Amazon Elastic Beanstalk deployment.

Editing the Project Object Model

First, create an S3 Bucket where you will store the .war files. In the example below, it’s named mywebapp-war-files. You can create it from the AWS Console, in the S3 Tab.

Once you do that, create a stub application which we will replace with ours next, by getting into the Elastic Beanstalk Tab in AWS Console and clicking in “Create New Application”

Pick a suitable name, and select “Use the Sample Application”, then click on “Continue”.

In AWS Elastic Beanstalk, clusters of your application are named “Environments”, and group EC2 Instances together behind an Elastic Load Balancer, each with its own “Environment URL” and Name. This screen lets you define the new environment definitions. Once you fill the marked fields and you’re satisfied with the settings you choose, click on “Continue”.

This screen lets you perform some additional Environment Settings: Defining the EC2 Instance Size, and the EC2 Key Pair (optional, but its useful when you need to log in into your instances, in order to troubleshoot). Also, for Health Check, you need to set an URL. Choose this one with extreme care: Pages which are slow to load will lead to instances being recycled. In extreme cases, supply an html page URL.

The final screen leads to confirmation and if successful, your application will be available in a few minutes.

So now let’s edit the pom.xml file and add the settings required for Elastic Beanstalk. To do so,  you need to declare the plugin and the AWS keys. Your pom.xml file should look similar to the one below (to make things simpler, look for the lines in bold).

<project xmlns=”http://maven.apache.org/POM/4.0.0″ xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
   xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd”>
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.mycompany</groupId>
   <artifactId>mywebapp</artifactId>
   <packaging>war</packaging>
   <version>1.0-SNAPSHOT</version>
   <name>mywebapp Maven Webapp</name>
   <url>http://maven.apache.org</url>
  <properties>
     <maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
     <beanstalk.versionLabel>${maven.build.timestamp}</beanstalk.versionLabel>
  </properties>
   <dependencies>
     <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
     </dependency>
   </dependencies>
   <build>
     <finalName>mywebapp</finalName>
     <plugins>
       <plugin>
          <groupId>br.com.ingenieux</groupId>
          <artifactId>beanstalk-maven-plugin</artifactId>
          <configuration>
            <accessKey>xxx</accessKey>
            <secretKey>yyy</secretKey>
            <applicationName>mywebapp</applicationName>
                <s3Bucket>mywebapp-war-files</s3Bucket>
<s3Key>${project.artifactId}/${project.build.finalName}-${maven.build.timestamp}.war</s3Key>
          </configuration>
       </plugin>
     </plugins>
   </build>
</project>

Replace the first four lines in the <configuration/> section with your keys, applicationName, and s3Bucket. In the command below, we will package the .war file, upload to S3, and create an application version (and the application itself) from a single line:

> mvn package beanstalk:upload-source-bundle beanstalk:create-application-version
[INFO] SUCCESS
[INFO] sourceBundle: {S3Bucket: mywebapp-war-files, S3Key: mywebapp/mywebapp-20120224033831.war, } [class: S3Location]
[INFO] versionLabel: 20120224033831 [class: String]
[INFO] description: mywebapp Maven Webapp [class: String]
[INFO] applicationName: mywebapp [class: String]
[INFO] dateCreated: Fri Feb 24 03:39:32 GMT-03:00 2012 [class: Date]
[INFO] dateUpdated: Fri Feb 24 03:39:32 GMT-03:00 2012 [class: Date]
[INFO] ————————————————————————
[INFO] BUILD SUCCESS
[INFO] ————————————————————————
[INFO] Total time: 54.484s
[INFO] Finished at: Fri Feb 24 03:39:26 GMT-03:00 2012
[INFO] Final Memory: 7M/17M
[INFO] ————————————————————————
C:\projetos\workspaces\ingenieux\mywebapp>
 

This means the application has a new version, and its available for deployment. You can open the “Elastic Beanstalk” tab on the AWS Console to confirm there is a new application and its version:

AWS Elastic Beanstalk

If you repeat the previous shell command, it will only create a new application version:

Repeat Shell Cmd for AWS Beanstalk

Now that we are keeping the versions for an application, you can deploy to instances from the console. But you can also integrate with your automated deployment process.

Redeploying Your Application

You can manually deploy your application by uploading the .war file, creating a new application version, and updating the environment. But you can automate that from Maven as well. The following command will deploy a new version of the application into your existing environment:

>mvn package beanstalk:upload-source-bundle beanstalk:create-application-version beanstalk:update-environment

However, redeploying the application incurs downtime, which might not be feasible. For this, there is the ”replace-environment” goal, which uses Amazon Elastic Beanstalk “Zero Downtime Deployment”, by creating a new parallel environment and switching cnames.

>mvn package beanstalk:upload-source-bundle beanstalk:create-application-version beanstalk:replace-environment

After a while, you’ll notice two different environments, the terminated environment (grayed out) and the new one that replaced it:

Terminate AWS Beanstalk Environment

What else can I do?

You can also restart the application server (mvn beanstalk:restart-application-server), rebuild the whole environment (mvn beanstalk:rebuild-environment), or terminate the environment (mvn terminate-environment).

Automating via Maven Build Profiles

The ingenieux Beanstalker plugin for Amazon Elastic Beanstalk was made not only for easy access from the command line, but also to automate the deployment using Continuous Integration Agents such as Jenkins and Bamboo.

In particular, it offers special features for rolling back application versions in running environments, as well as removing previous versions. You can automate this using Maven Build Profiles.

We suggest binding it to the “verify” phase, so it runs after packaging. Check the ingenieux beanstalker website for an overview of what is needed.

Next Steps

If you have looked closely at Maven Output, you might have noticed a warning for unencrypted passwords. You can either ignore it or find out how to encrypt them. It is also a good idea to review the beanstalker website, and subscribe to its user list at http://groups.google.com/group/beanstalker-users

About the Author

Aldrin Leal, Cloud Architect and Partner at ingenieux
Aldrin Leal works as an Architect and QA Consultant, specially for Cloud and Big Data cases. Besides his share of years worth between the trenches in projects ranging from Telecom, Aerospatial, Government and Mining Segments, he is also fond with a passion to meet new paradigms and figure a way to bring them into new and existing endeavours.

Contact Aldrin

 

Keywords: Amazon web services, Amazon AWS console, Amazon AWS instances, EC2 Service, Amazon Cloud Computing, S3 Storage, Elastic Beanstalk , Auto Scaling, S3 Bucket, Tomcat, Apache Maven Project

There is 1 comment .

You must be to post a comment.

* As a bonus, you'll receive our weekly newsletter!

Hitchhiker's Guide to The Cloud

Newvem's eBook for Cloud Operations