• Home
  • Dockerize React App – Continuous Integration and Deployment with TravisCI and AWS

Dockerize React App – Continuous Integration and Deployment with TravisCI and AWS

In today’s article I will try to setup and explain complete workflow of creating some simple project from start, then how to create docker container for it and commit everything to your Github branch. In next step I will explain how to setup TravisCI for continuous deployment of your project to your hosting. (AWS ElasticBeanstalk in my case). For a basic project we will create simple React App. This article is not intended to explain in detail React, Docker, Github, TravisCI or AWS but only workflow of complete process of building some project.

So for start you need to have Github account, TravisCI account, AWS account and Docker installed and configured on your local machine. Complete code of this project is available on my Github.

First we need to create some workdir on our machine. For example:

mkdir dockerreact

then we go inside that directory and create simple basic react app with:

cd dockerreact
create-react-app dockerizereact

After creating of react app is finished we can test installation. Go inside dockerizereact and run:

cd dockerizereact
npm run start

So if everything is ok and your React App can run we can create Dockerfile.dev inside root of your app. We will use this Dockerfile only for our development purposes. For production we will use another Dockerfile.

Dockerfile.dev

FROM node:alpine

WORKDIR '/app'

COPY package.json .
RUN npm install

COPY . .

CMD ["npm", "run", "start"]

As you see we will pull basic node:alpine image from docker hub, workdir inside our container is /app, then we copy our package.json from our root folder and then npm install is runing inside container. Next step is copy everything that we have in our root to container root ( COPY . . )

And here is Dockerfile for production. In this file we also pull nginx image from docker hub.

FROM node:alpine as builder
WORKDIR '/app'
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx
EXPOSE 80
COPY --from=builder /app/build /usr/share/nginx/html

After that we need to setup docker-compose.yml also in root folder of our app.

version: '3'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile.dev
    ports: 
      - "3000:3000"
    volumes:
      - /app/node_modules
      - .:/app
  tests:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - /app/node_modules
      - .:/app
    command: ["npm", "run", "test"]

As you see we have two services here web & tests. Tests is only for testing our app ( command: [“npm”, “run”, “test”] ). In volumes we have reference inside container to everything in our root of project. On the other hand we see that /app/node_modules lies inside container so that means we can easily delete node_modules folder from our root after we create container with docker-compose up.

cd dockerizereact
docker-compose up

After few minutes if everything is ok you can test your app. Go to localhost:3000 and you will see simple React App which is running from docker container.

Now we are ready to push everything to our Github. Create new repository on your Github. I will name my dockerizereact.

cd dockerizereact
git init
git add .
git commit -m "first commit of dockerizereact"
git remote add origin https://github.com/kristijanklepac/dockerizereact.git
git push -u origin master

Our app is pushed to our Github repository (dockerizereact) in master branch. Now it’s time to setup everything in TravisCI. TravisCI will be synchronized with our Github master branch and every time we push something to master branch TravisCI will pull that change and automatically deploy new version of our app to our hosting ( in my case AWS, but you can set up TravisCI to deploy to Microsoft Azure or Digitalocean or many others).

First go to your TravisCI find your dockerizereact repository (TravisCI is synced with Github) and enable checkbox beside settings of your dockerizereact repo. See image bellow.

Now we need to create .travis.yml file inside our root. This file will tell TravisCI what to do with our app. Steps are:

  1. Tell Travis that we need a copy of docker running
  2. Build our image using Dockerfile.dev
  3. Tell Travis how to run our test suite
  4. Tell Travis how to deploy our code to AWS

.travis.yml

sudo: required
services:
  - docker

before_install:
  - docker build -t kristijanklepac/dockerizereact -f Dockerfile.dev .

scripts:
  - docker run kristijanklepac/dockerizereact npm run test -- --coverage

Please be sure to correctly tag your docker build. In my example kristijanklepac is my DockerID you must use yours ( <DockerID>/<Name of Github repo>). Also when you run npm run test add — –coverage. This will ensure that tests are runned once and then exit to console.

Now add everything to Github repo.

git add .
git commit -m "added Travis YML file"
git push origin master

When you push files to master TravisCi will synchronize files and try to build everything according to .travis.yml file. If build is successful you will see that your repo is green inside Travis.

Next you need to create instance of ElasticBeanstalk service on your AWS. ( configured as single Docker container ). For deployment we need to update our .travis.yml

...

deploy:
  provider: elasticbeanstalk
  region: "<YOUR_CREATED_REGION_FROM_AWS_ELASTICBEANSTALK>"
  app: "<YOUR_CREATED_APP_NAME_FROM_AWS_ELASTICBEANSTALK>"
  env: "<YOUR_CREATED_ENV_NAME_FROM_AWS_ELASTICBEANSTALK>"
  bucket_name: "<YOUR_CREATED_BUCKET_NAME_FROM_AWS_ELASTICBEANSTALK>"
  bucket_path: "<YOUR_CREATED_BUCKET_PATH_FROM_AWS_ELASTICBEANSTALK>"
  on:
    branch: master

Please update above code with your own values from AWS. After that you need to create IAM user inside AWS and give user programmatic access and AWS Elasticbeanstalk Full policy access. Copy your access key and access secret somewhere because you will need those keys in TravisCI. Click More Options->Settings within yor repo inside TravisCI. Find area like on image bellow:

You need to create two key/value pairs for AWS_SECRET_KEY and AWS_ACCESS_KEY ( values are your copied values from IAM user). We use environment variables to protect it from expose to outside world. In .travis.yml we will use environment keys to set vars.

 

Next add this to your .travis.yml

...

deploy:
  provider: elasticbeanstalk
  region: "<YOUR_CREATED_REGION_FROM_AWS_ELASTICBEANSTALK>"
  app: "<YOUR_CREATED_APP_NAME_FROM_AWS_ELASTICBEANSTALK>"
  env: "<YOUR_CREATED_ENV_NAME_FROM_AWS_ELASTICBEANSTALK>"
  bucket_name: "<YOUR_CREATED_BUCKET_NAME_FROM_AWS_ELASTICBEANSTALK>"
  bucket_path: "<YOUR_CREATED_BUCKET_PATH_FROM_AWS_ELASTICBEANSTALK>"
  on:
    branch: master
  access_key_id: $AWS_ACCESS_KEY
  secret_access_key:
    secure: "$AWS_SECRET_KEY"

As you see here we will pull environment vars from Travis and they are not exposed to public. After we commit this to Github master Travis will try to build this and deploy to AWS. When app is deployed (check in AWS Elasticbeanstalk) you can visit Elasticbeanstalk url and see your React App. In our example whenever you push something to master branch after few minutes you will see changes in your production ( check your app url )

When you work in teams you will probably have multiple branches inside your Github repo. For example let’s say you have feature branch and every time you push something you will push it into feature branch and then you will merge master and feature branch if everything is as expected in your app. After merge Travis CI will do the rest.

Example:

git checkout -b feature
git add .
git commit -m "added something to app"
git push origin feature

Go to your Github, you will se your feature branch and then try to pull and merge branch. If all goes well you will see that Travis build everything and deploy to AWS…

Thanks for reading…

Tags: , , , , , ,

Copyright by Kristijan Klepač 2018