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:

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.

2022-12-03-running-app-locally

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.

2022-12-03-add-user

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.

2022-12-03-aws-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.

2022-12-03-setting-aws-configuration-on-aws

Next, under the Environment properties, add a new one named SERVER_PORT and set the value to 5000 as shown below.

2022-12-03-adding-environment-properties

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

2022-12-03-application-updates

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

2022-12-03-adding-aws-context

Next, select the aws-credentials context and you will see the page below:

2022-12-03-adding-aws-credentials

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 the global 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.

2022-12-03-connecting-application-to-circleci

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.

2022-12-03-project-setup-to-circleci

Your first workflow will start running and complete successfully.

2022-12-03-pipeline-ran-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.

2022-12-03-project-deployed-successfully

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!


Oluyemi is a tech enthusiast with a background in Telecommunication Engineering. With a keen interest in solving day-to-day problems encountered by users, he ventured into programming and has since directed his problem solving skills at building software for both web and mobile. A full stack software engineer with a passion for sharing knowledge, Oluyemi has published a good number of technical articles and blog posts on several blogs around the world. Being tech savvy, his hobbies include trying out new programming languages and frameworks.

Read more posts by Olususi Oluyemi