Automate your deployment flow using AWS Services

Swapnil Sharma

Swapnil Sharma / April 03, 2022

9 min read

https://images.unsplash.com/photo-1555099962-4199c345e5dd?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb

To implement the CICD Pipeline we’ll be using CodePipeline, CodeBuild and Elastic Beanstalk.

We’re going to deploy a simple node API(Source code) for this example.

Our Application

https://cdn-images-1.medium.com/max/1000/1*WAsgQ04w4JM-NBXC_zcV1Q.png

Node.js

Alright, now it’s time to step into the code zone 💻. We won’t be developing anything fancy seeing as that’s not the main objective of this post.

Project Structure and Dependencies

In the directory of our simple-node-app, let’s create a basic Express API application with a single route that we’ll write tests for. Kick-off the process with the following initialization command:

$ npm init -y

Once our package.json file has been created, we shall install a couple of dependencies.

$ npm i --save express cors body-parser
$ npm i -D chai mocha supertest

You will also need to install mocha globally on your local machine

$ npm i -g mocha

In the application folder/directory, you can go ahead and create a src directory using the mkdir command or your IDE. The folder structure for the application (inside src) is as follows (feel free to put a spin on it):

├── test/index.js
├── app.js
└── index.js

Test Script

Let’s turn our attention to the package.json file generated by the initialization command. We’re going to add a script that when run, will check for files inside the src/test directory and run any tests. As you may have guessed from the installations above, we’ll be making use of Mocha as our test framework, Chai as our assertion library, and SuperTest for HTTP assertions. Add the following script:

"test": "mocha 'src/test/**/*.js'"

Test

Inside the index.js file of the src/test folder, we can add the following content to test the response, status code, response format, and message of the route we’ll create.

const { expect } = require('chai');
const { agent } = require('supertest');
const app = require('../app');
const request = agent;
describe('Some controller', () => {
  it('Get request to /test returns some text', async () => {
    const res = await request(app).get('/test');
    const textResponse = res.body;
    expect(res.status).to.equal(200);
    expect(textResponse.text).to.be.a('string');
    expect(textResponse.text).to.equal('Simple Node App Working!');
  });
});

Express API

Next up, let’s initialize and configure our Express API server and add a /test route to it.

app.js

// Express App Setup
const express = require('express');
const http = require('http');
const bodyParser = require('body-parser');
const cors = require('cors');
// Initialization
const app = express();
app.use(cors());
app.use(bodyParser.json());
// Express route handlers
app.get('/test', (req, res) => {
  res.status(200).send({ text: 'Simple Node App Working!' });
});
module.exports = app;

index.js

const http = require('http');
const app = require('./app');
// Server
const port = process.env.PORT || 3001;
const server = http.createServer(app);
server.listen(port, () => console.log(`Server running on port ${port}`));

That’s about it for our application code 😃, now let’s go ahead and run our test and make sure it passes as expected.

$ npm run test

https://cdn-images-1.medium.com/max/1000/1*RAEe6RgwdY7vNj-ykiO5Kw.png

Looks like we’re in business 👍. Let’s create an application environment and setup our pipeline before committing and pushing these local changes.

Our Application Environment

AWS Elastic Beanstalk is a great tool for deploying applications with ease. There’s no cost for using Beanstalk, however, you are charged for the underlying resources that get provisioned.

Switch back to the AWS Console and head over to Elastic Beanstalk. In this section, we’re going to follow these simple steps:

Step 1: Create a New Application

Step 2: Create & Select Environment Tier

Step 3: Configure Environment

Step 1

In the top right corner, you should see a blue label that reads ‘Create New Application’, go ahead and click on it.

https://cdn-images-1.medium.com/max/1000/1*u3qP-lE9rZ-dBZOOX9Slbg.png

The above form should pop up. You can then name the application whatever you want and don’t have to fill in the description field unless you want to. We won’t be including any tags so don’t worry about that either.

Step 2

Next up, we’ll have to create and select the type of environment that we want Beanstalk to setup for us. Go ahead and create a new environment for your application. Since we’re setting up a standard web API, you can go ahead with the default selection of the Web server environment.

https://cdn-images-1.medium.com/max/1000/1*yjS0Z1dPvo2M2pBukDD4uQ.png

Step 3

In this last step, we don’t really need to change much. You can update the environment name of the application if you wish, but I’ll leave mine as is. An important step here is to select a pre-configured platform under the Base configuration section. You can select the Node.js option because our application is a Node.js based web API.

https://cdn-images-1.medium.com/max/1000/1*cTOXFbn5Rq6KIDcLvn9FXA.png

That’s it for Elastic Beanstalk 😃 , go and ahead and save the environment and Beanstalk will provision and configure the underlying resources based on our selections. Once Beanstalk is done, the environment should be healthy and all setup with a link to a sample application (see image below). In your case, the Running Version should have ‘Sample Application’ as opposed to an application version ID like below.

https://cdn-images-1.medium.com/max/1000/1*giC5AyckjH4ae_vtQx88ww.png

Our Build Pipeline

Let’s turn our attention to AWS CodePipeline which is a fully managed CD (Continuous Delivery) service that helps automate release pipelines. We’re now going to create a new pipeline. Here are the steps we’re going to follow:

Step 1: Choose Pipeline settings

Step 2: Add source

Step 3: Add build stage

Step 4: Add deploy stage

Step 5: Review and create a pipeline

Step 1

Start by giving your pipeline a name and a new service role before proceeding to the next step.

https://cdn-images-1.medium.com/max/1000/0*UQwyxnjxDBBi2EkJ.png

Step 2

Next, let’s choose the source for our application which is Github(Version 2). Be sure to select the relevant repository and branch.

https://cdn-images-1.medium.com/max/1000/1*ph5HxAndU4-tiRlso1oCwA.png

Step 3

Now we come to the build stage. We are going to be using AWS CodeBuild as our build provider. CodeBuild is a fully managed CI (Continuous Integration) service that will compile our source code, runs the tests in our Node.js app, and produce a software package that is ready to be deployed. We have not created any projects in AWS CodeBuild yet, so we’ll have to create one on the fly by clicking on the Create project button.

https://cdn-images-1.medium.com/max/1000/0*VexPdR653AWwCKA3.png

By clicking on this button, a new pop-up window will appear for you to create a Build project in CodeBuild. Go ahead and enter a project name and description (optional entry). For the environment settings, we will maintain the default Managed Image and the selection of a new Service Role.

For the Buildspec section, we’ll be using a builspec.yml file so this can remain unchanged. A build spec is a collection of build commands and related settings, in YAML format, that CodeBuild uses to run a build.

The option for logs to be output to CloudWatch can also remain unchanged.

Step 4

Finally, we come to the last main step — our deploy stage. Just in case you were wondering what the point of the Elastic Beanstalk application was, now is where it will be needed. We’re going to be using Elastic Beanstalk as our deploy provider. Remember to select the relevant application and environment.

https://cdn-images-1.medium.com/max/1000/0*qZHmCyEIYEyIEN2p.png

Step 5

Once we’re done with that, all that’s left is to review the pipeline and go ahead and create it.

Add Buildspec To Application

At this point, our pipeline should be ready to go. Before we test it, let’s add the buildspec file at the root of our project. I mentioned in Step 3 of the previous section what the importance of this file is. Now let’s go ahead and implement it in our project because AWS CodeBuild will be looking for this file on the build step of our pipeline.

This file will specify the phases which represent the commands CodeBuild runs during each phase of the build. You can read more details on the buildspec file here.

install: install dependencies you may need for your buildpre_build: final commands to execute before buildbuild: actual build commandspost_build: finishing touches

buildspec.yml

# Do not change version. This is the version of aws buildspec, not the version of your buldspec file.
version: 0.2phases:
  install:
    runtime-versions:
      nodejs: 10
    commands:
      - echo Installing Mocha...
      - npm install -g mocha
  pre_build:
    commands:
      - echo Installing source NPM dependencies...
      - npm install
  build:
    commands:
      - echo Build started on `date`
      - echo Compiling the Node.js code
      - npm run test
  post_build:
    commands:
      - echo Build completed on `date`
# Include only the files required for your application to run.
artifacts:
  files:
    - src/index.js
    - src/app.js
    - package.json
    - node_modules/**/*

Trigger New Build

After adding the build specification to the root of your code, you can go ahead and commit all your changes and push them to the master branch. This will trigger a new build and deployment in the pipeline we just created.

Our pipeline will pull from the source (CodeCommit) in this case, and then build our application and run the tests we created (which can be viewed from the build logs). If these passes, Elastic Beanstalk will then proceed to deploy our application.

https://cdn-images-1.medium.com/max/1000/0*3op3CxnfDBW7wP1m.png

Successful build and test

https://cdn-images-1.medium.com/max/1000/0*sraSRVISVTRSmVH8.png

Testing Our Deployed Web API

Now, the moment you’ve been waiting for. Provided that the deployment was successful, we can take the displayed URL from the Overview page of our application environment in Elastic Beanstalk (ends with [region].elasticbeanstalk.com). You can then run a GET request to this URL with the /test route that we added and you should get the following response:

https://cdn-images-1.medium.com/max/1000/0*f_JT6xr1k0eFIg-l.png

You can find the source code for this basic project here 😃, happy coding!

Subscribe to my newsletter to get early access to all my content.

Subscribe to the newsletter

Get emails from me about web development, tech, and early access to new articles.