Recently I was working on a proof-of-concept web application that I wanted to deploy to a public cloud for a quick demo.

I decided to use Amazon as I already had experience with it. Amazon offers several different ways to deploy a Java web application.

Amazon EC2

EC2 gives us the flexibility to install and configure whatever we want to on the box. This is a very flexible solution for someone who wants to take controll over how their application is deployed and running, but it’s drawback is that we have to do most of the server installation & configuration and the application deploy tasks by ourselves.

AWS Elastic Beanstalk

The Elastic Beanstalk is an easy-to-use service that automatically handles deployment, auto-scaling, load-balancing and health monitoring. Using Elastic Beanstalk anyone can deploy a web application to the Amazon cloud with just a few clicks.

I decided to go with the quick and easy Elastic Beanstalk option…

Elastic Beanstalk has various ways to deploy Java applications:

  1. Using Docker
  2. Deploying a war file to a Tomcat server
  3. Deploying fatjar executed from the command line

In this post I’m going to cover the option using a fatjar, which is basically a single jar file that has all classes and jar dependencies bundled in it.

To make this working in Amazon, the jar file has to be placed inside a zip file.

Create JAR and ZIP files

In this post I’m using Maven to create both the jar and the zip files discussed above. Let’s walk through a sample pom.xml file to see how it’s done:

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  ...
  <groupId>com.kaviddiss</groupId>
  <artifactId>spring-boot-aws-beanstalk</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
  ...
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.2.RELEASE</version>
    <relativePath />
    <!-- lookup parent from repository -->
    </parent>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    ...
  </dependencies>
 
  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      ...
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin 
       <plugin>
      <!-- NOTE: We don't need a groupId specification because the group is org.apache.maven.plugins ...which is assumed by default. -->
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.6</version>
        <executions>
          <execution>
            <id>make-zip</id>
            <!-- this is used for inheritance merges -->
            <phase>package</phase>
            <!-- bind to the packaging phase -->
            <goals>
              <goal>
                single
              </goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <appendAssemblyId>false</appendAssemblyId>
          <descriptors>
            <descriptor>src/assembly/zip.xml</descriptor>
          </descriptors>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

This file is based on a pom.xml file generated for Spring Boot web applications at http://start.spring.io/, and it includes a few additional changes:

  1. Make sure the packaging tag is set to jar
  2. The spring-boot-maven-plugin will take care of creating the jar file including all jar dependency inside the file itself
  3. Configure the maven-assembly-plugin to generate a zip file from the jar file using the src/assembly/zip.xml descriptor file

After configuring the maven-assembly-plugin in the pom.xml file, we’ll also need to configure the zip.xml descriptor that tells the assembly plugin how to construct the zip file itself.

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
   <id>zip</id>
   <formats>
     <format>zip</format>
   </formats>
   <includeBaseDirectory>false</includeBaseDirectory>
   <fileSets>
     <fileSet>
       <directory>${project.build.directory}</directory>
       <includes>
         <include>${project.artifactId}.jar</include>
       </includes>
       <outputDirectory>.</outputDirectory>
    </fileSet>
   </fileSets>
</assembly>

As you can see above, we configured the output to be zip, which is one of the many supported formats.

We also configured to include the jar file in the top level directory of the zip file. And that’s all needed by Amazon to run the application from the command line,

Sample microservice using Spring Boot

To be able to test the maven configuration, I created a simple Spring Boot web application (see below).

Application.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@SpringBootApplication
@Controller
public class Application {    
  @RequestMapping(value = "/hello")   
  public @ResponseBody String helloWorld() {   
    return "Hello, World!";   
  }     
  
  public static void main(String[] args) {   
    SpringApplication.run(Application.class, args);    
  }
}

This Application class serves the main class of the web application and will be the entry point when running the fatjar from the command line

Deploy to Elastic Beanstalk

If you haven’t signed up for AWS Elastic Beanstalk yet, you can follow this link: https://console.aws.amazon.com/elasticbeanstalk.

 

aws-elasticbeanstalk-1

Select Amazon Elastic Beanstalk Platform

Once inside the console, click on create new environment for application. Then click on Create web server select Java in the platform dropdown and click Launch Now.

Elastic Beanstalk Environment Variables

Set Environment Variable

AWS configures an nginx proxy server to forward requests to our application running on port 8080. In order to tell nginx about the port 8080, in Configuration -> Software Configuration add an Environment Variable with key and value set to PORT=8080.
And that’s it. If everything went well, you should be able to access the sample web application  on AWS!

 

  • zcsongor

    Great article, thanks! Tried w/o zipping, works as well.

  • Viktor Csomor

    To avoid the port configuration simply add the following to the application.yml or the application.properties file .

    application.yml
    server:
    port: ${PORT}

    application.properties
    server.port=${PORT}

    • David Kiss

      Nice! Thanks for sharing this trick

  • Anirudh Mathad

    I just built your project out of github and tried to deploy it. I don’t seem to get the response back.

    • Anirudh Mathad

      Hadn’t enabled inbound traffic ports for HTTP. Got it! Works like a charm.