In this article, I am going to build a simple React Project and deploy it to an AWS S3 bucket using CircleCI. After finish this tutorial, the code will be tested, built and deployed to AWS 3 automatically on every commit.

Create a Simple React App

npx create-react-app my-app

You can run npm start to run it on the local browser. Then, push it to the Git repository.

AWS Setup

Create a S3 bucket and enable website hosting

  • Sign in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3/
  • Click Create bucket and give it a name, I recommend to use yourdomain.com as your bucket name
  • Click the Permissions tab and then the Bucket Policy button, this will bring up an editor. Add below JSON to the editor
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::yourdomain.com/*"
        }
    ]
}
  • Click the Properties tab.
  • Choose Static website hosting, and then choose Use this bucket to host a website.
  • You are prompted to provide the index document and any optional error documents and redirection rules that are needed.

Create an new IAM user for CircleCi

Go to AWS IAM Console

  • Click Users -> Add user
  • Enter a name. For example, circleci_service. And select Programmatic access option.
  • Click Next Permissions
  • In the Set permissions page, choose Attach existing policies directly and click Create policy
  • In the next page, click JSON and paste the following JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation"
            ],
            "Resource": "arn:aws:s3:::yourdomain.com"
        },
        {
            "Effect": "Allow",
            "Action": "*",
            "Resource": "arn:aws:s3:::yourdomain.com/builds/*"
        }
    ]
}
  • Click Revice Policy and give this policy a name
  • Return to the Set Permissions page, and search the policy you just created, and select it
  • Then, click Next: Tags -> Next: Review -> Create user
  • Copy the Access key ID and Secret access key of this user, this information will only be shown one time and we will be using it later

CircleCI Setup

First, add your project to CircleCi by clicking Setup Project on the CircleCi dashboard.

You need to create a file called config.yml inside .circleci folder under the project root.

The yml file should be like this:

defaults: &defaults
  working_directory: ~/repo
  docker:
    - image: circleci/node:8.11
version: 2
jobs:
  checkout_code:
    <<: *defaults
    steps:
      - restore_cache:
          keys:
            - source-{{ .Branch }}-{{ .Revision }}
            - source-{{ .Branch }}-
            - source-

      - checkout

      - save_cache:
          key: source-{{ .Branch }}-{{ .Revision }}
          paths:
            - "~/repo"
  install:
    <<: *defaults
    steps:
      - restore_cache:
          key: source-{{ .Branch }}-{{ .Revision }}
      - restore_cache:
          key: dependency-cache-{{ checksum "package.json" }}
      - run:
          name: "Yarn install"
          command: yarn install
      - save_cache:
          key: dependency-cache-{{ checksum "package.json" }}
          paths:
            - node_modules
  test:
    <<: *defaults
    steps:
      - restore_cache:
          key: source-{{ .Branch }}-{{ .Revision }}
      - restore_cache:
          key: dependency-cache-{{ checksum "package.json" }}
      - run:
          name: "Test"
          command: npm run test
  build:
    <<: *defaults
    steps:
      - restore_cache:
          key: source-{{ .Branch }}-{{ .Revision }}
      - restore_cache:
          key: dependency-cache-{{ checksum "package.json" }}
      - run:
          name: "Build app"
          command: npm run build
      - persist_to_workspace:
          root: ~/repo
          paths:
            - dist
            - package.json
  deploy:
    docker:
      - image: circleci/node:8.11
    working_directory: ~/repo
    steps:
      - run: sudo apt-get update && sudo apt-get install -y python-dev
      - run: sudo curl -O https://bootstrap.pypa.io/get-pip.py
      - run: sudo python get-pip.py
      - run:
          name: Install awscli
          command: sudo pip install awscli
      - restore_cache:
          key: source-{{ .Branch }}-{{ .Revision }}
      - restore_cache:
          key: dependency-cache-{{ checksum "package.json" }}
      - run:
          name: "Build app"
          command: npm run build
      - run:
          name: Deploy to S3
          command: aws s3 sync build/ s3://yourdomain.com/ --delete
workflows:
  version: 2
  build_and_test:
    jobs:
      - checkout_code
      - install:
          requires:
            - checkout_code
      - test:
          requires:
            - install
      - build:
          requires:
            - install
      - deploy:
          requires:
            - test
            - build

Now, CircleCi does not know how to access to your AWS S3. Let’s go to the Setting of your project in CircleCi dashboard.

  • Click Environment Variables -> Add Variable
  • Paste AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in the Name field, and Paste the secret key you copied before from the IAM

Once this is done, the pipeline will be triggered when it detects a git push. The website will be deployed on the S3 Endpoint.

If you would like to use your own domain to access the website, just simply add the endpoint as a CNAME record in the DNS setting of your domain provider.

Categories: Development