Automate deployment of Java Spring Boot apps to AWS Elastic Beanstalk
Fullstack Developer and Tech Author
The benefits of automating deployments for your Java Spring Boot application are undoubtable. Not only is it possible to set up images and run tests or compatibility checks before updating the production environment, but CI/CD providers like CircleCI take a step further by streamlining the entire delivery process from code changes to deployment.
Many teams assume that the specifics of their development stack or deployment process will make automation difficult to achieve. In this article, we will see how to easily implement a CI/CD pipeline for a Spring Boot application running on AWS Elastic Beanstalk. We’ll make use of the Elastic Beanstalk orb to simplify and accelerate project setup so you can start shipping new features right away.
Prerequisites
In addition to a basic understanding of Java and Spring Boot, you will need the following to get the most from this tutorial:
- A GitHub account
- A CircleCI account
- An AWS account
- AWS Elastic Beanstalk CLI installed on your computer
- Apache Maven installed on your system.
Cloning the demo project
To demonstrate how to automate deployments for your Spring Boot applications with CI/CD, we’ll be using a basic sample project, an exchange rate API with three endpoints:
S/N | Endpoint | Method | Function |
---|---|---|---|
1. | /currency | GET | Get all currencies supported by the API |
2. | /rates | GET | Get all the exchange rates for all the supported currencies |
3. | /rates/{currency} | GET | Get the exchange rates for a single currency |
You can clone the sample project by running the following command.
git clone https://github.com/CIRCLECI-GWP/spring-exchange-api-eb.git
Next, go to the root of the new folder created by the previous command (spring-exchange-api-eb
)
cd spring-exchange-api-eb
Now, issue the following command to build and run the project:
mvn -B -DskipTests clean package
mvn spring-boot:run
The mvn -B -DskipTests clean package
command will clear the target
directory if existed, builds the project and skip test during the build. Finally, the mvn spring-boot:run
command will run the project on the default port.
By default, your application will be served to port 8080. Navigate to http://127.0.0.1:8080/rates
in order to view the JSON response.
Add user with programmatic access
To successfully deploy your application to AWS, you need to create a user with the appropriate credentials and required permissions for deployment. Head to the AWS Add User page. Select a username and AWS access type as shown in the screenshot below.
Make sure you select Access key - Programmatic access as this will give you access to your Beanstalk environment via the CLI.
Next, to select permissions for the user, click Next: Permissions > Attach existing policies directly, then search and select the following policies:
AdministratorAccess-AWSElasticBeanstalk
: This grants the user an administrative permissions and allows them to gain direct access to resources they need to manage AWS Elastic Beanstalk applications.AmazonS3FullAccess
: This provides full access to all buckets via the AWS Management Console. It is important to include this policy because Elastic Beanstalk CLI will need to upload your source code file to Amazon S3 using multipart upload, especially if the size is greater than 7mb.
Click Next twice to create the new user.
You will be greeted with a success message along with your user credentials. This page is only displayed once, so make a note of the Access Key ID and the Secret access key, which you will need later on. Alternatively, you can download the provided .csv file, which contains the same credentials.
Next, you need to configure the AWS CLI credentials to use the details of the newly created user. Issue the following command for that:
aws configure
Note: You can simply run this command or a new terminal tab or from the root directory of your project. It doesn’t really matter where.
You will be prompted to input the AWS Access Key ID and AWS Secret Access Key. Hit Enter on your keyboard once you are done. You can use these credentials to authenticate awsebcli
and continue with the deployment process.
Initializing the Elastic Beanstalk environment
Initialize your Elastic Beanstalk CLI repository by issuing the following command from the root of your project.
eb init -p corretto-17 exchangeRatesApi
The p
tag specifies the platform you want your Beanstalk to run on. In our case, we will use Amazon Corretto 17, a no-cost, multiplatform, production-ready distribution of the Open Java Development Kit (OpenJDK).
You will get the following output after a successful execution.
Application exchangeRatesApi has been created.
If you are yet to provide an access-id
and secret-key
for awsebcli
, you will see an error similar to the one shown below.
ERROR: The current user does not have the correct permissions. Reason: Operation Denied. The security token included in the request is invalid.
ERROR: The current user does not have the correct permissions. Reason: Operation Denied. The security token included in the request is invalid.
You have not yet set up your credentials or your credentials are incorrect
• You must provide your credentials.
Provide a valid aws-access-id
and aws-secret-key
to complete the setup process. If you don’t have one already, you can follow the steps below.
The next thing to do is create a new environment using the following command.
eb create spring-env
You will see and output similar to this:
Creating application version archive "app-4517-221213_155152698834".
Uploading exchangeRatesApi/app-4517-221213_155152698834.zip to S3. This may take a while.
Upload Complete.
Environment details for: spring-env
Application name: exchangeRatesApi
Region: us-west-2
Deployed Version: app-4517-221213_155152698834
Environment ID: e-jzwrpunr2n
Platform: arn:aws:elasticbeanstalk:us-west-2::platform/Corretto 17 running on 64bit Amazon Linux 2/3.4.1
Tier: WebServer-Standard-1.0
CNAME: UNKNOWN
Updated: 2022-12-13 15:51:58.735000+00:00
This creates an Elastic Beanstalk environment named spring-env
for us — a process which takes about 5 minutes. Once the process is completed, you can find the domain for the new environment by running the following command.
eb status
You will see the following output:
Environment details for: spring-env
Application name: exchangeRatesApi
Region: us-west-2
Deployed Version: app-4517-221213_155152698834
Environment ID: e-jzwrpunr2n
Platform: arn:aws:elasticbeanstalk:us-west-2::platform/Corretto 17 running on 64bit Amazon Linux 2/3.4.1
Tier: WebServer-Standard-1.0
CNAME: spring-env.eba-28m5wkuj.us-west-2.elasticbeanstalk.com
Updated: 2022-12-13 15:55:04.289000+00:00
Status: Ready
Health: Red
At this point, the health status of the spring-env
environment will be RED
.
Deploying the application to Elastic Beanstalk
Next, we need to specify an artifact
in our Beanstalk configuration. This will be the JAR file that is generated when the project is built. To do this, add the following to the automatically created .elasticbeanstalk/config.yml
file.
deploy:
artifact: target/exchangeRates-0.0.1-SNAPSHOT.jar
After you append the previous snippet, your .elasticbeanstalk/config.yml
file should look like this:
branch-defaults:
main:
environment: spring-env
group_suffix: null
global:
application_name: exchangeRatesApi
branch: null
default_ec2_keyname: null
default_platform: Corretto 17
default_region: us-west-2
include_git_submodules: true
instance_profile: null
platform_name: null
platform_version: null
profile: null
repository: null
sc: git
workspace_type: Application
deploy:
artifact: target/exchangeRates-0.0.1-SNAPSHOT.jar
Next, we will need to deploy the changes. Because we are using Git for version control, we will need to commit our changes first before running eb deploy
.
git add .
git commit -m "Add EBS config"
eb deploy
Once this process is completed, run the eb status
command again. This time, the health status should be GREEN. Paste the CNAME
property in your browser to see your API.
Although the health status turns GREEN, if you run the eb status
command after a minute, you will notice the status has turned YELLOW. Also, if you visit the CNAME
on your browser, you will get a 502 error. This does not mean that there is any problem with the deployment or the application. Rather, the port configured in our application is not the default port that is assigned by Elastic Beanstalk. Therefore, you will need to configure the port manually, as shown in the next section.
Setting the port configuration
By default, Spring Boot applications run on port 8080. However, Elastic Beanstalk applications listen on port 5000. As a result, opening the application in your browser will display a 502
error. To fix this, you can add a SERVER_PORT
environment variable to your beanstalk. To do this, go to the Configuration section of your environment and edit the Software options.
Next, under the Environment properties, add a new one named SERVER_PORT
and set the value to 5000 as shown below.
Click Apply to persist the changes. This will trigger an update process for your environment after which you will then be able to see the rates for your application as expected by visiting the CNAME/rates
Set up a CI/CD pipeline on CircleCI
With CircleCI, you can automate all the processes required to build and deploy your Spring Boot application to Elastic Beanstalk. The pipeline would initially build the Maven application and then deploy it on Elastic Beanstalk, whenever a new commit is made to the repository.
At the root of the project, locate the folder named .circleci
. In this folder, modify the content of the config.yml
file as shown here:
version: 2.1
orbs:
eb: circleci/aws-elastic-beanstalk@2.0.1
jobs:
build-and-test:
description: "Setup Spring boot application and run tests"
docker:
- image: cimg/openjdk:19.0.1
steps:
- checkout
- run:
name: Build
command: mvn -B -DskipTests clean package
- persist_to_workspace:
root: .
paths:
- .
- run:
name: Test
command: mvn test
deploy:
docker:
- image: "cimg/base:stable"
description: "Deploying updates to Elastic Beanstalk"
steps:
- attach_workspace:
at: .
- eb/setup
- run:
command: |
eb init exchangeRatesApi -r $AWS_DEFAULT_REGION -p corretto-17
echo "deploy:
artifact: target/exchangeRates-0.0.1-SNAPSHOT.jar" >> .elasticbeanstalk/config.yml
eb deploy spring-env
workflows:
build-and-deploy:
jobs:
- build-and-test
- deploy:
requires:
- build-and-test
context: aws-credentials
This configuration makes use of the eb
orb to set up the application environment during the build and deploy the changes to the environment you created earlier.
In addition to the orbs
declaration, two jobs are declared.
The build-and-test
job checks out the latest code from the repository, builds the project, and runs the tests. Because the package and JAR file generated during the build process is required in the deployment phase, the files are persisted to the workspace, making them available for the subsequent jobs.
The deploy
job attaches the persisted workspace to the build before setting up the Elastic Beanstalk CLI. Next, we add a set of commands. The first instantiates our environment in the CLI. The second updates the Beanstalk config to match our use case - one which requires a deploy
key to be present and pointing to the JAR file generated during the build process. Finally, the changes are deployed to the spring-env
environment.
In the workflow, after running the build-and-test
job, the deploy
job is used to deploy the changes. In addition to the requires
key, which ensures that the build-and-test
job runs first, the application name, environment name, and platform version are specified for the job. A context named aws-credentials
is passed to the job. We will populate this context with the necessary credentials in a moment.
To test our changes, let’s add a new rate to the application. Update the expectedCurrencies
array in src/test/java/com/example/exchangeRates/ExchangeRatesApplicationTests.java
to match the following:
final String[] expectedCurrencies = {"EUR", "GBP", "NGN", "USD", "YEN", "CFA"};
In the same vein, update the supportedCurrencies
array in src/main/java/com/example/exchangeRates/service/ExchangeRatesService.java
.
final String[] supportedCurrencies = {"EUR", "GBP", "NGN", "USD", "YEN", "CFA"};
Next, commit and push the changes to your GitHub repository. Review Pushing a project to GitHubfor instructions.
Add AWS credentials to your pipeline
In your CircleCI dashboard, navigate to the Organization Settings page by clicking on the link in the sidebar. Next, select Contexts and click on the Create Context button and add a unique name for your Context. After you click the Create Context button in the dialog box, the Context appears in a list with Security set to All members
to indicate that anyone in your organization can access this Context at runtime. As specified in the .circleci/config.yml
configuration for this tutorial, the Context name should be aws-credentials
Next, select the aws-credentials
context and you will see the page below:
Click the Add Environment Variable button and enter the variable name and value you wish to associate with this context. Click the Add Variable button to save. The aws-credentials
context requires 3 environment variables namely:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
- The
AWS_DEFAULT_REGION
variable. The value of this is specified in the.elasticbeanstalk/config.yml
file in the project, under theglobal
section.
Deploy your Spring Boot app to AWS with CircleCI
In this section, you will link the project to CircleCI and trigger your first automated deployment. Log in to your CircleCI account. If you signed up with your GitHub account, all your repositories will be available on your project’s dashboard.
Click Set Up Project next to your spring-exchange-api-eb
project.
You will be prompted to either write a new configuration file or use the existing one in your project. Select the existing one and enter the name of the branch where your code is housed on GitHub. Click Set Up Project.
Your first workflow will start running and complete successfully.
To confirm that your workflow was successful, you can open your newly deployed app in your browser using the CNAME
property with a /rates
URL suffix.
Now, on every change to your project repository, CircleCI will automatically run your workflow and deploy a new version of your application to Elastic Beanstalk. For a more robust CI/CD pipeline, consider adding tests to your Spring Boot app to validate your changes before deploying.
Conclusion
In this tutorial, you learned how to set up a CI/CD pipeline for a Spring Boot API using GitHub, CircleCI, and AWS Elastic Beanstalk. You have also seen that it is possible to implement best practices for automated deployments of software updates for Spring Boot projects. Additionally, you can add custom commands in your pipeline configuration to cater to peculiarities in your deployment process while taking advantage of the preset builds made available by your CI/CD provider.
With this knowledge, you can confidently automate the deployment of your Spring Boot applications, ensuring a streamlined and efficient software development and release process. If you haven’t already, sign up for your free CircleCI account and get 6,000 monthly build minutes to try it yourself.
Happy coding!