loading...

Set up CI/CD for containerized React App using Docker, AWS CodeBuild, AWS ECS, AWS CodePipeline & Github

mubbashir10 profile image Mubbashir Mustafa ・6 min read

This is the last part of the series "Dev-ops for Front-End developers". I assume you already have:

-Containerized your React Application using Docker
-Deployed on AWS ECS using Fargate
-Attached ELB and domain with the Container
-Attached SSL to ELB & Enabled HTTPS
-Setup Github repo for your project and pushed your code to it

1. Setting up CodeBuild Project

From the AWS console, navigate to CodeBuild. From the CodeBuild's homepage, select "Create project".
Alt Text

A CodeBuild project has 6-7 parts (at the time of writing):

Project Configuration

Enter in the name (required), description (optional) and tags (optional). Click on "Enable build badge" if you want to show build pass/fail badge on your Github repo page.
Alt Text

Source

Select Github, select "Repository in my Github Account", click on "Connect using OAuth (you can also use access token method if you prefer)", then click on "Connect to GitHub". It will ask you to sign in and authorize, if you intend to authorize repositories from your organization then you will also have to grant access to the organization. Afterward, it will ask you to enter your Github password.
Alt Text

After entering the Github password, it will take you to the CodeBuild page and from there select "Confirm".
Alt Text

Once authorized, you will be taken back to the CodeBuild. Search and select your repo ("my-app" in my case), then enter the branch name in the Source version field (the branch from which you would like to build e.g. master in my case).
Alt Text

Primary source webhook events

Leave it unchecked as we will be triggering build using code pipeline.
Alt Text

Environment

Select:
-"Managed Image" as an Environment image
-"Ubuntu" as an operating system
-"Standard" as a Runtime
-The latest version in Image dropdown ("aws/codebuild/standard:4.0" is the latest at the time of writing)
-"Always use the latest image for this runtime version" as Image version
-"Linux" as Environment type
-Enable the "Privileged" flag
-"New Service Role" as Service role (it will fill in the next field automatically, you can edit if you prefer some custom name)
-Leave Additional configuration as it is (unless you need to increase compute capacity etc.)
Alt Text

Buildspec

Enter "Buildspec.prod.yml" in the Buildspec name field (we will create this file later on).
Alt Text

Artifacts & Logs

Leave these sections and click on "Create build project"
Alt Text

Create and push Buildspec file

Create a new file in your project (react's app) root dir and name it "Buildspec.prod.yml" and paste the following snippet into it.

version: 0.2
phases:
  install:
    runtime-versions:
      docker: 19
  pre_build:
    commands:
      - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
      - REPOSITORY_URI=681373743177.dkr.ecr.us-east-2.amazonaws.com/my-app
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - docker build -t $REPOSITORY_URI:latest -f Dockerfile.prod .
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - printf '[{"name":"my-app-default-container","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
  files: imagedefinitions.json


Replace the container name ("my-app-default-container") with the one that you used while creating Task Definition in earlier articles. Replace YOUR_ECR_IMAGE_URI_HERE with URI of your image, which you can get from AWS ECR.
Alt Text
Save the file, commit, and push to your Github repo.

Note*: Make sure you are providing your Dockerfile name at "-f Dockerfile.prod" in the snippet above.

Give Access to CodeBuild
ECR Permissions

Now you need to give AWS CodeBuild access to your AWS ECR repo. To do that, go back to ECR and click on your repo. Inside your repo, click on "Permissions" from the left sidebar.
Alt Text

Click "Edit Policy JSON" and add the following JSON to the popup and click Save.

{
  "Version": "2008-10-17",
  "Statement": [
    {
      "Sid": "new statement",
      "Effect": "Allow",
      "Principal": {
        "Service": "codebuild.amazonaws.com"
      },
      "Action": [
        "ecr:BatchCheckLayerAvailability",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ]
    }
  ]
}

Alt Text

CodeBuild Role Policies

From AWS console go to IAM and select "Policies" from the left sidebar. Inside the Policies' page click on "Create policy".
Alt Text

Select JSON, enter the following snippet and click "Review Policy".

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "ecr:CompleteLayerUpload",
                "ecr:GetAuthorizationToken",
                "ecr:UploadLayerPart",
                "ecr:InitiateLayerUpload",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage"
            ],
            "Resource": "*"
        }
    ]
}

Alt Text

Name your policy "CodebuildToECR", give a description if you want, and click "Create policy".
Alt Text

Once the policy has been created, it's time to add the policy to the CodeBuild's service role (created earlier). For that select "Roles" from the left sidebar.
Alt Text

Search and select the CodeBuild role that was created earlier.
Alt Text

Click "Attach Policy".
Alt Text

Search for the policy we created earlier (i.e CodebuildToECR), select it and click "Attach Policy".
Alt Text

Now we are ready to build our project using CodeBuild. But we still need to automate the CodeBuild and Deploy to ECS steps, so follow along.

2. Setting up CodePipeline

From the AWS console home, go to CodePipeline. Click "Create pipeline".
Alt Text

Enter the pipeline name and click "Next".
Alt Text

Just like before select "Github" as the source provider, use OAuth to grant access, select and search the repo (my-repo in my case) and enter the branch name (master in my case). Click "Next".
Alt Text

Select "AWS CodeBuild" as the Build provider. Search and select the CodeBuild project we created earlier and click "Next".
Alt Text

Select "Amazon ECS" as the Deploy provider. Select cluster and service we created earlier (in previous articles) and click "Next". Review the configuration and click "Create pipeline".
Alt Text

That's it. After creating the pipeline it will start to build & deploy automatically (the first time). Now, whenever you push to the master branch (or branch you provided earlier) pipeline will be triggered automatically.
Alt Text

You can set up notification rules using AWS Chatbot with Slack (that's what we use) or use SNS with any other service you prefer. That I will cover in some other series.


Technically the part we have done is CD only. CI comes into play when we want to merge branches/PRs etc, and that requires you to write test cases that are executed before merging.

To implement CI (Continous Integration), we will use Github Workflows. Create a folder in your app's root dir. and name it ".github". Inside this folder create a sub-folder and name it "workflows". Inside that folder create a new file called "react.yml". You can also use the following commands to achieve that.

mkdir .github
cd .github
mkdir workflows
touch react.yml

Open up "react.yml" with a text editor and paste the following snippet:

name: React CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [12.x]

    steps:
    - uses: actions/checkout@v2
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - run: yarn
    - run: yarn test

Save the file. Commit the changes and push to your Github repo. That's it. Now, whenever you make changes to your code and create new PRs it will run test cases automatically. You can check your workflow by going to the "Actions" tab on Github within your repo.
Alt Text

Further reading: https://www.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment

Posted on by:

mubbashir10 profile

Mubbashir Mustafa

@mubbashir10

Hi, I am Mubbashir. I specialize in developing highly scalable & distributed web apps. I help startups in developing their apps & ideas. Here I usually write about React, Javascript and DevOps.

Discussion

pic
Editor guide